resulting multiple columns from single value field - sql-server

I have a table with the below columns (Table1).
[Date], [Status], [Time], [Category], [Count]
And I've written a SQL Query using, below is the query.
SELECT [Date]
,[Status]
,[Time]
,[1 time] as '1 time'
,[2 times] as '2 times'
,[3 times] as '3 times'
,[4 times] as '4 times'
,[5 times] as '5 times'
,[>5 times] as '>5 times'
FROM Table1
PIVOT (
SUM([Count])
FOR [Category] IN
([1 time], [2 times], [3 times], [4 times], [5 times], [>5 times])
) as PVT
ORDER BY 1, 2, 3, 4
And the I did the get the result as required with the below columns.
[Date], [Status], [Time], [1 time], [2 times], [3 times], [4 times], [5 times], [>5 times]
But I need to add one more column names as Overall which will give the sum of all these columns.
[1 time], [2 times], [3 times], [4 times], [5 times], [>5 times]
Can someone help me with it?

Try this:
SELECT [Date]
,[Status]
,[Time]
,[1 time]
,[2 times]
,[3 times]
,[4 times]
,[5 times]
,[>5 times]
,[1 time] + [2 times] + [3 times] + [4 times] + [5 times] + [>5 times] AS Overall
FROM (SELECT [Date]
,[Status]
,[Time]
,[1 time] as '1 time'
,[2 times] as '2 times'
,[3 times] as '3 times'
,[4 times] as '4 times'
,[5 times] as '5 times'
,[>5 times] as '>5 times'
FROM Table1
PIVOT (SUM([Count]) FOR [Category] IN ([1 time], [2 times], [3 times], [4 times], [5 times], [>5 times])) as PVT) AS T
ORDER BY 1, 2, 3, 4

Related

Sorting query output by Month name

I am trying to extract values from Excel using an SQL Query, but what I've been struggling with is sorting the months in their respective order. Right now the table is being sorted A-Z, I tried playing around with DATEPART, but was not very successful as I was getting an Int16 error.
Select F1,
SUM(F2),
ROUND(SUM(REPLACE(F3, ',', '.')), 2),
ROUND(SUM(REPLACE(F4, ',', '.')), 2)
FROM [Sheet1$]
WHERE F1 IN ('January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December')
GROUP BY F1;
This is the query that works, but the result is:
I am also open to any suggestions that could improve my query speed as the document is quite big, about 50k rows, thanks.
For anyone wondering the final query that worked was:
Select F1,
SUM(F2),
ROUND(SUM(REPLACE(F3, ',', '.')), 2),
ROUND(SUM(REPLACE(F4, ',', '.')), 2)
FROM [Sheet1$]
WHERE F1 IN ('January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December')
GROUP BY F1
ORDER BY SWITCH(
F1='January', 1,
F1='February', 2,
F1='March', 3,
F1='April', 4,
F1='May', 5,
F1='June', 6,
F1='July', 7,
F1='August', 8,
F1='September', 9,
F1='October', 10,
F1='November', 11,
F1='December', 12
);
Either use a CASE expression:
Select
f1,
SUM(f2),
ROUND(SUM(REPLACE(f3, ',', '.')), 2),
ROUND(SUM(REPLACE(f4, ',', '.')), 2)
FROM [Sheet1$]
WHERE F1 IN ('January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December')
GROUP BY F1
ORDER BY
CASE F1
WHEN 'January' THEN 1
WHEN 'February' THEN 2
WHEN 'March' THEN 3
WHEN 'April' THEN 4
WHEN 'May' THEN 5
WHEN 'June' THEN 6
WHEN 'July' THEN 7
WHEN 'August' THEN 8
WHEN 'September' THEN 9
WHEN 'October' THEN 10
WHEN 'November' THEN 111
WHEN 'December' THEN 12
END;
Or create a month table on the fly:
Select
s.f1,
SUM(s.f2),
ROUND(SUM(REPLACE(s.f3, ',', '.')), 2),
ROUND(SUM(REPLACE(s.f4, ',', '.')), 2)
FROM [Sheet1$] s
JOIN VALUES
(
('January', 1),
('February', 2),
('March', 3),
('April', 4),
('May', 5),
('June', 6),
('July', 7),
('August', 8),
('September', 9),
('October', 10),
('November', 11),
('December', 12)
) months(month_name, month_number) ON s.f1 = months.month_name
GROUP BY s.f1
ORDER BY months.month_number;
Or create a real month table.
You could do:
order by datepart(mm, f1 + ' 1 2000')

convert rows to columns using date column

I have a table containing four rows: id(primary key, auto increment), value, type and time.
id value type time
1 1.2 1 2017-10-26 16:16:49.350
2 12.4 2 2017-10-26 16:16:49.350
3 0.6 3 2017-10-26 16:16:49.350
4 1.1 4 2017-10-26 16:16:49.350
5 1.8 1 2017-10-25 14:12:24.650
6 3.2 2 2017-10-25 14:12:24.650
7 0.2 3 2017-10-25 14:12:24.650
8 1.2 4 2017-10-25 14:12:24.650
Is it possible to convert these rows to columns based on type and time(either by query or stored procedure)? something like this:
(type)1 2 3 4 time
1.2 12.4 0.6 1.1 2017-10-26 16:16:49.350
1.8 3.2 0.2 1.2 2017-10-25 14:12:24.650
PS: Each four types share the same time.
Try this:
DECLARE #DataSource TABLE
(
[id] SMALLINT
,[value] DECIMAL(9,1)
,[type] TINYINT
,[time] DATETIME2
);
INSERT INTO #DataSource ([id], [value], [type], [time])
VALUES (1, 1.2, 1, '2017-10-26 16:16:49.350')
,(2, 12.4, 2, '2017-10-26 16:16:49.350')
,(3, 0.6, 3, '2017-10-26 16:16:49.350')
,(4, 1.1, 4, '2017-10-26 16:16:49.350')
,(5, 1.8, 1, '2017-10-25 14:12:24.650')
,(6, 3.2, 2, '2017-10-25 14:12:24.650')
,(7, 0.2, 3, '2017-10-25 14:12:24.650')
,(8, 1.2, 4, '2017-10-25 14:12:24.650');
SELECT [1], [2], [3], [4], [time]
FROM
(
SELECT [value], [type], [time]
FROM #DataSource
) DS
PIVOT
(
MAX([value]) FOR [type] IN ([1], [2], [3], [4])
) PVT
ORDER BY [time] DESC;
Here is another option using conditional aggregation or cross tab.
select Type1 = max(case when type = 1 then value)
Type2 = max(case when type = 2 then value)
Type3 = max(case when type = 3 then value)
Type4 = max(case when type = 4 then value)
, time
from YourTable
group by time
You can use PIVOT:
SELECT
[1] type1
, [2] type2
, [3] type3
, [4] type4
, time
FROM
(
SELECT
value
, type
, time
FROM table
) T
PIVOT
(
SUM (value)
FOR type IN
(
[1], [2], [3], [4]
)
) P

Second condition inside SELECT query

I have this simple query (TSQL) -
SELECT IdTour, Tour, TourOrder, IdContent
FROM View_ToursListContentId
WHERE (IdContent = 3) OR (IdContent = 4)
ORDER BY TourOrder DESC, Tour
Here is the result
58 Air & Style Tour 2015/16 NULL 3
48 FIS Europa Cup 2015/16 NULL 3
46 FIS World Cup Tour 2015/16 NULL 3
131 KDC Grand Slam Regional Qualifiers 2016 NULL 3
59 Swatch Freeride World Tour 2016 NULL 3
77 World Rookie Tour 2015/16 NULL 3
57 World Snowboard Tour 2015/16 NULL 3
45 X Games 2016 NULL 3
45 X Games 2016 NULL 4
What I need to do is. If ther is inside result IdTour with IdContent = 3 don't show the same IdTour with IdContent = 4. (Show IdTour with IdContent = 4 only, if there is not the same IdTour with IdContent = 3 - in my case show only one IdTour 45 with IdContent 3)
What is the easiest and the fastest way, how could I accomplish it?
Thanx a lot
One way involves using NOT EXISTS:
SELECT IdTour, Tour, TourOrder, IdContent
FROM View_ToursListContentId t1
WHERE (IdContent = 3) OR
((IdContent = 4) AND NOT EXISTS (SELECT 1
FROM View_ToursListContentId t2
WHERE t1.IdTour = t2.IdTour AND
t2.IdContent = 3))
ORDER BY TourOrder DESC, Tour
The NOT EXISTS operator filters out records having IdContent = 4 in case a record with the same IdTour and IdContent = 3 exists.
select * from (
select row_number() over (partition by IdTour, Tour, TourOrder order by IdContent) rownum,
IdTour, Tour, TourOrder, IdContent from View_ToursListContentId)src
where rownum=1
You could use a window function to obtain the lowest IdContent available for that IdTour:
SELECT IdTour,
Tour,
TourOrder,
IdContent,
MinIdContent = MIN(IdContent) OVER(PARTITION BY IdTour)
FROM View_ToursListContentId
WHERE IdContent IN (3, 4);
Then if this is 3 then you select only 3, if it is 4 then you select only 4, or more simply, only select IdContent that matches the minimum:
SELECT IdTour, Tour, TourOrder, IdContent
FROM ( SELECT IdTour,
Tour,
TourOrder,
IdContent,
MinIdContent = MIN(IdContent) OVER(PARTITION BY IdTour)
FROM View_ToursListContentId
WHERE IdContent IN (3, 4)
) AS t
WHERE IdContent = MinIdContent;
FULL EXAMPLE
WITH View_ToursListContentId AS
( SELECT IdTour, Tour, TourOrder, IdContent
FROM (VALUES
(58, 'Air & Style Tour 2015/16', NULL, 3),
(48, 'FIS Europa Cup 2015/16', NULL, 3),
(46, 'FIS World Cup Tour 2015/16', NULL, 3),
(131, 'KDC Grand Slam Regional Qualifiers 2016', NULL, 3),
(59, 'Swatch Freeride World Tour 2016', NULL, 3),
(77, 'World Rookie Tour 2015/16', NULL, 3),
(57, 'World Snowboard Tour 2015/16', NULL, 3),
(45, 'X Games 2016', NULL, 3),
(45, 'X Games 2016', NULL, 4)
) t (IdTour, Tour, TourOrder, IdContent)
)
SELECT IdTour, Tour, TourOrder, IdContent
FROM ( SELECT IdTour,
Tour,
TourOrder,
IdContent,
MinIdContent = MIN(IdContent) OVER(PARTITION BY IdTour)
FROM View_ToursListContentId
WHERE IdContent IN (3, 4)
) AS t
WHERE IdContent = MinIdContent;
you should just use group by IdContent in query
like
SELECT IdTour, Tour, TourOrder, IdContent
FROM View_ToursListContentId
WHERE (IdContent = 3) OR (IdContent = 4)
group by IdContent
ORDER BY TourOrder DESC, Tour

Pivoting datetime column and summarizing by the hour of day returns nulls

I am trying to query a table that has a datetime 'myDateTime' column and get the counts of how many times each 'myDateTime' appears and then group it by 'myDateTime' as a date and the hour in the day as column.
with CTE1 as (select DATEADD(dd, DATEDIFF(dd, 0, myDateTime), 0) myDate, count(myDateTime) as Counts,
case when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) in (0,1,2,3,4,5,6,7,21,22,23) then '8 PM to 7 AM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 8 then '8 AM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 9 then '9 AM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 10 then '10 AM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 11 then '11 AM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 12 then '12 PM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 13 then '1 PM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 14 then '2 PM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 15 then '3 PM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 16 then '4 PM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 17 then '5 PM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 18 then '6 PM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 19 then '7 PM'
when DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0))) = 20 then '8 PM'
else 'Error' end as HourOfDay
from [table1] with(nolock)
where myDateTime is not null
and datediff(day, myDateTime, getdate()) <= 10
group by DATEADD(dd, DATEDIFF(dd, 0, myDateTime), 0), DATEPART(hour,(DATEADD(hh, DATEDIFF(hh, 0, myDateTime), 0)))
),
CTE2 as (select myDate, sum(Counts) as Counts, HourOfDay
from CTE1
group by myDate, HourOfDay
--order by HourOfDay desc
)
--CTE3 as (select distinct HourOfDay as hod from cte2)
select myDate, [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14]
from CTE2
PIVOT
(
sum(Counts)
for HourOfDay in ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14])
) as piv
What I get to unfortunately returns nulls all around. Where the 1-14 numbers appear should be my 8 AM to 8 PM and an extra columns for hours outside of that timeframe. What am I doing wrong?
myDate 1 2 3 4 5 6 7 8 9 10 11 12 13 14
2016-04-13 00:00:00.000 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
2016-04-14 00:00:00.000 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
2016-04-15 00:00:00.000 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
Change your PIVOT column name in query as per the values you provided inside the CTE (column [1] is actually [1 PM],[2] is [2 PM] etc)
select *
from CTE2
PIVOT ( sum(Counts) for HourOfDay in ([1 PM], [2 PM], [3 PM], [4 PM], [5 PM], [6 PM]
, [7 PM], [8 PM], [9 PM], [10 PM], [11 PM], [12 PM], [13 PM], [14 PM])
) as piv

SQL - Group Results on Same Row

So I've got data like so
id type date
1 1 2015-02-04
2 1 2015-02-04
3 2 2015-02-04
4 1 2015-02-05
5 2 2015-02-06
And I want a result like so
countForType1 countForType2 dow
2 1 Wednesday
1 0 Thursday
0 1 Friday
etc...
I'm trying use the OVER(PARTITION but I think I'm using it incorrectly, or possibly, I need to use something else. Here is my current query:
SELECT
COUNT(seatType) OVER(PARTITION BY seatType) AS Counts,
CASE DATEPART(DW,testDate)
WHEN 1 THEN 'Sunday'
WHEN 2 THEN 'Monday'
WHEN 3 THEN 'Tuesday'
WHEN 4 THEN 'Wednesday'
WHEN 5 THEN 'Thursday'
WHEN 6 THEN 'Friday'
WHEN 7 THEN 'Saturday'
END dow
FROM tst_Tests
WHERE roomid = 1
GROUP BY DATEPART(DW,testDate), seatType
I'm not sure how to create a second column counting by an individual seat types.
I'm thinking I could just put two select statements inside the select statement, but that seems inefficient. I feel like there is a function for this I am using incorrectly or not at all.
EDIT: I made the example data match actual dates and numbers of what would be returned.
You should use Conditional Aggergate instead of window function
SELECT Count(CASE WHEN type = 1 THEN 1 END) AS countForType1,
Count(CASE WHEN type = 2 THEN 1 END) AS countForType2,
CASE
WHEN Datepart(DW, date) = 1 THEN 'Sunday'
WHEN Datepart(DW, date) = 2 THEN 'Monday'
WHEN Datepart(DW, date) = 3 THEN 'Tuesday'
WHEN Datepart(DW, date) = 4 THEN 'Wednesday'
WHEN Datepart(DW, date) = 5 THEN 'Thursday'
WHEN Datepart(DW, date) = 6 THEN 'Friday'
WHEN Datepart(DW, date) = 7 THEN 'Saturday'
END dow
FROM Yoursampletable
GROUP BY Datepart(DW, date)
Like this?
DECLARE #Example TABLE ([Id] int, [type] int, [testDate] date)
INSERT INTO #Example ([Id], [type], [testDate])
SELECT 1,1,'2015-02-04' UNION ALL
SELECT 2,1,'2015-02-04' UNION ALL
SELECT 3,2,'2015-02-04' UNION ALL
SELECT 4,1,'2015-02-05' UNION ALL
SELECT 5,2,'2015-02-06'
;with rowsWithDayName as (
select *,
CASE WHEN DATEPART(DW,testDate) = 1 THEN 'Sunday'
WHEN DATEPART(DW,testDate) = 2 THEN 'Monday'
WHEN DATEPART(DW,testDate) = 3 THEN 'Tuesday'
WHEN DATEPART(DW,testDate) = 4 THEN 'Wednesday'
WHEN DATEPART(DW,testDate) = 5 THEN 'Thursday'
WHEN DATEPART(DW,testDate) = 6 THEN 'Friday'
WHEN DATEPART(DW,testDate) = 7 THEN 'Saturday'
END as [DayName]
from #Example
)
select
SUM(CASE WHEN [type]=1 THEN 1 ELSE 0 END) as countForType1
, SUM(CASE WHEN [type]=2 THEN 1 ELSE 0 END) as countForType2
, [DayName]
FROM rowsWithDayName
group by [DayName]

Resources