I need to analyze data from SQL server table. Table contains data connected with qualifications of all employyes in the company and has the following structure (simplified):
| User | Qualification | DateOfQualificationAssignment |
| user000 | Junior | 2014-01-15 |
| user000 | Middle | 2014-02-15 |
| user001 | Middle | 2014-02-02 |
| user001 | Senior | 2014-03-18 |
| user002 | Senior | 2014-02-19 |
| user003 | Junior | 2014-03-04 |
I need the way to determine number of employees having given qualification for the concrete date. It should be some sort of analyze("Qualification", "Date") function returning the folowing for these types of input data:
analyze("Junior", '2014-01-20') - returns 1 (it is user user000)
analyze("Junior", '2014-02-20') - returns 0 (because user000 became Middle on 2014-02-15)
analyze("Middle", '2014-02-25') - returns 2 (because user000 and user001 are having Middle qualification on 2014-02-25)
analyze("Middle", '2014-03-28') - returns 1 (user000 is still Middle, but user001 became Senior on 2014-03-18)
Currently I have no idea how to handle this efficiently. What approach can be used to achieve my goal?
Think this should satisfy your requirements:
create function dbo.analyze(#qualification varchar(50), #date date)
returns int
as
begin
declare #result int;
with cte
as
(
select t.*, rank() over (partition by t.[User] order by t.DateOfQualificationAssignment desc) r
from theTable t -- no clue what the real table is named
where t.DateOfQualificationAssignment < #date
)
select #result = count(*)
from cte
where cte.r = 1 and cte.Qualification = #qualification
return #result;
end
go
Tested with your data:
create table theTable
(
[User] varchar(50) not null,
Qualification varchar(50) not null,
DateOfQualificationAssignment date not null
)
go
insert into theTable([User],Qualification,DateOfQualificationAssignment)
values
('user000','Junior','20140115'),
('user000','Middle','20140215'),
('user001','Middle','20140202'),
('user001','Senior','20140318'),
('user002','Senior','20140219'),
('user003','Junior','20140304')
go
and the results:
select dbo.analyze('Junior','20140120') --returns 1
go
select dbo.analyze('Junior','20140220') --returns 0
go
select dbo.analyze('Middle','20140225') --returns 2
go
select dbo.analyze('Middle','20140328') --returns 1
go
Use row_number() over() in a derived table to enumerate the rows on DateOfQualificationAssignment descending partitioned by User where DateOfQualificationAssignment is less than the date you want to check on.
In the main query you count the rows with the enumerated value 1 and Qualification.
SQL Fiddle
MS SQL Server 2012 Schema Setup:
create table T
(
[User] char(7),
Qualification char(6),
DateOfQualificationAssignment date
)
insert into T values
('user000', 'Junior', '2014-01-15'),
('user000', 'Middle', '2014-02-15'),
('user001', 'Middle', '2014-02-02'),
('user001', 'Senior', '2014-03-18'),
('user002', 'Senior', '2014-02-19'),
('user003', 'Junior', '2014-03-04')
Query 1:
declare #Qualification char(6) = 'Middle'
declare #Date date = '2014-03-28'
select count(*)
from (
select T.Qualification,
row_number() over(partition by T.[User] order by T.DateOfQualificationAssignment desc) as rn
from T
where T.DateOfQualificationAssignment < #Date
) as T
where T.rn = 1 and
T.Qualification = #Qualification
Results:
| COLUMN_0 |
|----------|
| 1 |
Related
I have the data below in a sql table,
ID | supplier | Supplier_Due | Date |
1 | S-0003 | 14850 |2020-11-09
2 | S-0003 | 850 |2020-11-09
3 | S-0003 | 21750 |2020-11-13
4 | S-0003 | 975 |2020-11-15
5 | S-0003 | 75 |2020-11-17
let assume the user wants to get data of 2020-11-13 which is
3 | S-0003 | 21750 |2020-11-13
but i'd like to get the previous supplier due as well before the date specified which is
850
along with
3 | S-0003 | 21750 |2020-11-13
so the actual query i wanna get is this
ID | supplier | Supplier_Due | Date | Previous Due
3 | S-0003 | 21750 |2020-11-13 | 850
and if there is no previous due i wanna return
ID | supplier | Supplier_Due | Date | Previous Due
3 | S-0003 | 21750 |2020-11-13 | 0.00
i couldn't even figure out how to write the query because i dont understand how to go about it
You can use window functions. Assuming that date can be used to consistently order the records of each supplier:
select *
from (
select t.*,
lag(supplier_due, 1, 0) over(partition by supplier order by date) as previous_due
from mytable t
) t
where date = '2020-11-13' and supplier = 'S-0003'
A typical alternative is a subquery, or a lateral join:
select t.*, coalesce(t1.supplier_due, 0) as previous_due
from mytable t
outer apply (
select top (1) supplier_due
from mytable t1
where t1.supplier = t.supplier and t1.date < t.date
order by t1.date desc
) t1
where date = '2020-11-13' and supplier = 'S-0003'
DECLARE #Suppliers table
(
ID integer PRIMARY KEY CLUSTERED,
Supplier char(6) NOT NULL,
Supplier_Due smallmoney NOT NULL,
[Date] date NOT NULL
);
INSERT #Suppliers
(ID, Supplier, Supplier_Due, [Date])
VALUES
(1, 'S-0003', 14850, '2020-11-09'),
(2, 'S-0003', 850, '2020-11-09'),
(3, 'S-0003', 21750, '2020-11-13'),
(4, 'S-0003', 975, '2020-11-15'),
(5, 'S-0003', 75, '2020-11-17');
SELECT
S.ID,
S.Supplier,
S.Supplier_Due,
S.[Date],
[Previous Due] =
LAG(S.Supplier_Due, 1, 0) OVER (
PARTITION BY S.Supplier
ORDER BY S.[Date] ASC)
FROM #Suppliers AS S
WHERE
S.[Date] = CONVERT(date, '2020-11-13', 121);
db<>fiddle demo
Documentation: LAG (Transact-SQL)
So I have a DataSet file with some TableAdapters where main query is just a select from all main columns
problem is that I want to make a join so i can get the string value from the parent table but i get incorrect input string format exception when i do this....
this is the adapters
| Inventory | | Employee |
| ID int | | ID int |
| employee int | ----- | Name nvarchar |
| warehouse int |
I tried to do this in a stored procedure and make the join clause
GO
IF OBJECT_ID('dbo.spx_SELECT_InventariosByCustomPaging') IS NOT NULL
DROP PROCEDURE spx_SELECT_InventariosByCustomPaging
GO
CREATE PROCEDURE spx_SELECT_InventariosByCustomPaging
#startIndex int,
#pageSize int
AS
BEGIN
SET NOCOUNT ON
SELECT ID, Name, Warehouse, DataCriacao
FROM (
SELECT InventarioID, xc.Name, xa.Warehouse, DataCriacao, ROW_NUMBER()
OVER(ORDER BY Colaborador DESC) AS rowNumber
FROM Inventory xi
LEFT JOIN Employee xc
ON xc.ID= xi.ID
LEFT JOIN xArmazem xa
ON xa.ArmazemID = xi.Armazem
) AS Inventario
WHERE rowNumber > #startIndex AND
rowNumber <= (#startIndex + #pageSize )
END
How can I get the Name column on Inventory DataTable?
Additional information: Input string was not in a correct format.Couldn't store in Inventory Column. Expected type is Int.
I made this question a while back.
SQL Server making rows into columns
Basically, the person that answered explained very well what I needed to do. However, I encountered a problem
aID| status | group |
-----------------------
1 | acti | group1 |
2 | inac | group2 |
A3 | acti | group1 |
Second Table: This table is fixed. It has around 20 values and the IDs are all numbers
atID| traitname |
------------------
1 | trait1 |
2 | trait2 |
3 | trait3 |
Third Table: This table is used to identify the traits the assets in the first table have. The fields that have the same name as fields in the above tables are obviously linked.
tID| aID | atID | trait |
----------------------------------
1 | 1 | 1 | NAME |
2 | 1 | 2 | INFO |
3 | 2 | 3 | GOES |
4 | 2 | 1 | HERE |
Now, the user wants the program to output the data in the following format:
aID| status | group | trait1 | trait2 | trait 3
-------------------------------------------------
1 | acti | group1 | NAME | INFO | NULL
2 | inac | group2 | HERE | NULL | GOES
A3 | acti | group1 | NULL | NULL | NULL
Now, the problem here is that, as you can see, A3 has no trait. In the final view, I would want A3 to appear completely null in the traits. But it doesn't appear at all, even though it's there. Does anyone know how can I fix this?
Here is the query I am using:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(traitname)
from Table2
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT aid, status, [group],' + #cols + '
from
(
select t1.aid,
t1.status,
t1.[group],
t2.traitname,
t3.trait
from table1 t1
inner join table3 t3
on t1.aid = t3.aid
inner join table2 t2
on t3.atid = t2.atid
) x
pivot
(
max(trait)
for traitname in (' + #cols + ')
) p '
execute sp_executesql #query;
The problem is you are using an INNER JOIN on your tables. An INNER JOIN returns all rows that have matching data in both tables.
Since you want to return everything from Table1, you will alter your query to use a LEFT JOIN instead of the INNER JOIN:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(traitname)
from Table2
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT aid, status, [group],' + #cols + '
from
(
select t1.aid,
t1.status,
t1.[group],
t2.traitname,
t3.trait
from table1 t1
left join table3 t3
on t1.aid = t3.aid
left join table2 t2
on t3.atid = t2.atid
) x
pivot
(
max(trait)
for traitname in (' + #cols + ')
) p '
execute sp_executesql #query;
As a side note, it is difficult to tell what the data types on your join columns are. Your Table1.aid column appears to be a varchar because of the A3 value but your Table3.aid column looks to be an int. If your data types are not the same, then you will need to cast the data on the join similar to -- on t1.aid = cast(t3.aid as varchar(10))
I want to show data like pivot grid. I am right now showing data like following. Please see following image or click on link.
http://screencast.com/t/CWeGy0vi
But I want above data like following:
http://screencast.com/t/ZTb2wk4cdmB
Any suggestion how to achieve this. Starting point. Should I use repeater?
Without seeing your table structure, etc. it is hard to give an exact answer. But I can suggest how you could perform this in SQL. You have some previous questions tagged with sql server so I am guessing that.
You can do this using both an UNPIVOT and a PIVOT:
;with unpiv as
(
select activity,
work,
Location+'_'+col as col,
value
from
(
select activity,
work,
cast(AssignedTasks as varchar(50)) AssignedTasks,
cast(CompletedTasks as varchar(50)) AchievedTasks,
Location
from yourtable
) src
unpivot
(
value
for col in (AssignedTasks, AchievedTasks)
) unpiv
),
piv as
(
select Activity,
work,
London_AssignedTasks,
London_AchievedTasks,
Geneva_AssignedTasks,
Geneva_AchievedTasks,
row_number() over(partition by activity order by activity, work) rn
from unpiv
pivot
(
max(value)
for col in (London_AssignedTasks, London_AchievedTasks,
Geneva_AssignedTasks, Geneva_AchievedTasks)
) piv
)
select case when rn = 1 then activity else '' end activity,
work,
London_AssignedTasks,
London_AchievedTasks,
Geneva_AssignedTasks,
Geneva_AchievedTasks
from piv
See SQL Fiddle with Demo.
The result is:
| ACTIVITY | WORK | LONDON_ASSIGNEDTASKS | LONDON_ACHIEVEDTASKS | GENEVA_ASSIGNEDTASKS | GENEVA_ACHIEVEDTASKS |
-------------------------------------------------------------------------------------------------------------------
| Activity 1 | Task 1 | 10 | 8 | 1 | 1 |
| | Task 2 | 15 | 15 | 100 | 25 |
| Activity 2 | Task 1 | 5 | 5 | 0 | 0 |
| | Task 2 | 0 | 0 | 2 | 2 |
| Activity 3 | Task 1 | 10 | 10 | 50 | 40 |
Edit #1, If you have an unknown or dynamic number of Locations then you can use dynamic SQL to return the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(Location+'_'+t.tasks)
from yourtable
cross apply
(
select 'AssignedTasks' tasks
union all
select 'AchievedTasks'
) t
group by location, tasks
order by location
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = ';with unpiv as
(
select activity,
work,
Location+''_''+col as col,
value
from
(
select activity,
work,
cast(AssignedTasks as varchar(50)) AssignedTasks,
cast(CompletedTasks as varchar(50)) AchievedTasks,
Location
from yourtable
) src
unpivot
(
value
for col in (AssignedTasks, AchievedTasks)
) unpiv
),
piv as
(
select Activity,
work,
row_number() over(partition by activity order by activity, work) rn,
'+#cols+'
from unpiv
pivot
(
max(value)
for col in ('+#cols+')
) piv
)
select case when rn = 1 then activity else '''' end activity,
work,
'+#cols+'
from piv'
execute(#query)
See SQL Fiddle with Demo
I'm not an expert at SQL and i'm not even sure if this type of query is doable.
I want to return a count(*) for each "MediaTypeID" for each Month based off of "MediaDate".
Any help would be greatly appreciated!
Thanks.
My Table looks like:
The Table Data looks like:
1 | 1 | Funny Cat Video | 2006-01-25 00:00:00.000
2 | 1 | Funny Dog Video | 2006-01-20 00:00:00.000
3 | 2 | Angry Birds Game | 2006-03-13 00:00:00.000
4 | 4 | Blonde Joke | 2006-03-16 00:00:00.000
5 | 3 | Goofy Clown Picture | 2006-02-27 00:00:00.000
6 | 2 | Racing Game | 2006-02-10 00:00:00.000
7 | 1 | Star Wars Video | 2006-07-15 00:00:00.000
The query would return 12 rows of results for Jan-Dec looking like:
Month | MediaTypeID1Count | MediaTypeID2Count | MediaTypeID3Count | MediaTypeID4Count
Jan | 400 | 255 | 15 | 65
Feb | 100 | 25 | 75 | 35
Mar | 320 | 155 | 50 | 99
Apr | 56 | 0 | 98 | 313
This type of data transformation is known as a PIVOT. SQL Server 2005+ has a pivot function that can be implemented:
select month,
[1] MediaType1_count,
[2] MediaType2_count,
[3] MediaType3_count,
[4] MediaType4_count
from
(
select
mediatypeid,
datename(m, mediadate) Month,
datepart(m, mediadate) monnum
from yourtable
) src
pivot
(
count(mediatypeid)
for mediatypeid in ([1], [2], [3], [4])
) piv
order by monnum
See SQL Fiddle with Demo
If you have an unknown number of values that you want to transpose into columns, then you can use dynamic sql:
DECLARE #cols AS NVARCHAR(MAX),
#colNames AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(mediatypeid)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #colNames = STUFF((SELECT distinct ', ' + QUOTENAME(mediatypeid) +' as MediaType' + cast(mediatypeid as varchar(50))+'_Count'
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT month,' + #colNames + ' from
(
select mediatypeid,
datename(m, mediadate) Month,
datepart(m, mediadate) monnum
from yourtable
) x
pivot
(
count(mediatypeid)
for mediatypeid in (' + #cols + ')
) p
order by monnum'
execute(#query)
See SQL Fiddle with Demo
The result will look like:
| MONTH | MEDIATYPE1_COUNT | MEDIATYPE2_COUNT | MEDIATYPE3_COUNT | MEDIATYPE4_COUNT |
----------------------------------------------------------------------------------------
| January | 2 | 0 | 0 | 0 |
| February | 0 | 1 | 1 | 0 |
| March | 0 | 1 | 0 | 1 |
| July | 1 | 0 | 0 | 0 |
I think this may be what you are looking for. The following will simply return the count based off the media type id, then group by year and then its month
Select MediaTypeID, datepart(year, MediaDate), datepart(month, MediaDate), count(*)
From Media
Group by MediaTypeID, datepart(year, MediaDate), datepart(month, MediaDate)
In my opinion, this could be a good challenge for you to start with this code:
Declare #T Table (
MediaID BigInt Primary Key Identity(1, 1)
, MediaTypeID BigInt
, MediaTitle Nvarchar(50)
, MediaDate DateTime
);
Insert #T (
MediaTypeID
, MediaTitle
, MediaDate
) Select 1
, 'Funny Cat Video'
, '2006-01-25 00:00:00.000'
Union
Select 1
, 'Funny Dog Video'
, '2006-01-20 00:00:00.000'
Union
Select 2
, 'Angry Birds Game'
, '2006-03-13 00:00:00.000'
Union
Select 4
, 'Blonde Joke'
, '2006-03-16 00:00:00.000'
Union
Select 3
, 'Goofy Clown Picture'
, '2006-02-27 00:00:00.000'
Union
Select 2
, 'Racing Game'
, '2006-02-10 00:00:00.000'
Union
Select 1
, 'Star Wars Video'
, '2006-07-15 00:00:00.000'
;
Select Month.Title
, Count(Type01_Result.MediaID) As MediaTypeID_1
, Count(Type02_Result.MediaID) As MediaTypeID_2
, Count(Type03_Result.MediaID) As MediaTypeID_3
, Count(Type04_Result.MediaID) As MediaTypeID_4
From (
Select 1 As Id
, 'Jan' As Title
Union
Select 2
, 'Feb'
Union
Select 3
, 'March'
Union
Select 4
, 'April'
Union
Select 5
, 'May'
Union
Select 6
, 'June'
Union
Select 7
, 'July'
Union
Select 8
, 'Aug'
Union
Select 9
, 'Sept'
Union
Select 10
, 'Nov'
Union
Select 11
, 'Oct'
Union
Select 12
, 'Dec'
) As Month
Left Outer Join
#T As Type01_Result
On Type01_Result.MediaTypeID = 1
And DatePart(Month, Type01_Result.MediaDate) = Month.Id
Left Outer Join
#T As Type02_Result
On Type02_Result.MediaTypeID = 2
And DatePart(Month, Type02_Result.MediaDate) = Month.Id
Left Outer Join
#T As Type03_Result
On Type03_Result.MediaTypeID = 3
And DatePart(Month, Type03_Result.MediaDate) = Month.Id
Left Outer Join
#T As Type04_Result
On Type04_Result.MediaTypeID = 4
And DatePart(Month, Type04_Result.MediaDate) = Month.Id
Group By Month.Title
;
The only thing is that you should be carefull about the year value and how many years you wanna include in the output, because this result will give you the summation of all records in each month no matter which year the date of the record is. It may cause some confusion in the result.
(Remember that I always set the tab size to 8 characters in the Options of Management Studio, so I suggest you do that to see the correct style of writing T-SQL)
Hope it helps you.
Cheers