How to PIVOT with 2 grouping columns in the result set? - sql

I have a query that outputs the following:
ApptDate Truck_ID Item Qty
'8-19-20' TruckA ItemA 100
'8-19-20' TruckB ItemA 200
'8-20-20' TruckC ItemB 300
'8-20-20' TruckD ItemB 400
...
I need to PIVOT so that it returns this:
Item Truck_ID Day1 Day2 ... Day14
ItemA TruckA 100 0 0
ItemA TruckB 200 0 0
ItemB TruckC 0 300 0
ItemB TruckD 0 400 0
I tried this, but it gave an error:
Msg 8114, Level 16, State 1, Line 413
Error converting data type nvarchar to datetime.
Msg 473, Level 16, State 1, Line 413
The incorrect value "Day1" is supplied in the PIVOT operator.
select
item, truck_id, Day1, Day2, Day3, Day4, Day5, Day6, Day7, Day8, Day9, Day10, Day11, Day12, Day13, Day14
from(
select
ds.ApptDate
, c.truck_id
, c.item
, sum(c.qty) qty
from
maintable c with(nolock)
inner join secondtable ds with(nolock) on c.truck_id = ds.truckid and ds.type = 'O'
where
ds.apptdate between cast(getdate() as date) and dateadd(day, 14, cast(getdate() as date))
and coalesce(ds.CancelTruck, 0) <> 1
and ds.Status <> '5'
group by
c.truck_id
, c.item
, ds.ApptDate
) sourcetable
pivot
(
sum(qty)
for apptdate in ([Day1], [Day2], [Day3], [Day4], [Day5], [Day6], [Day7], [Day8], [Day9], [Day10], [Day11], [Day12], [Day13], [Day14])
) as pivottable

Since you expect a fixed number of columns, we don't necessarily need dynamic SQL. One option uses conditional aggregation... and lot of repeated typing:
select
item,
truck_id,
sum(case when appt_date = cast(getdate() as date) then qty else 0 end) day0,
sum(case when appt_date = dateadd(day, -1 , cast(getdate() as date)) then qty else 0 end) day1,
sum(case when appt_date = dateadd(day, -2 , cast(getdate() as date)) then qty else 0 end) day2,
...
sum(case when appt_date = dateadd(day, -14, cast(getdate() as date)) then qty else 0 end) day14
from ( -- your current query here --) t
group by item, truck_id

This approach uses datediff's on the minimum date and the AppDate.
;with
min_dt_cte(min_dt) as (select min(cast(AppDate as date)) from MyTable),
pvt_dt_cte(ApptDate, Truck_ID, Item, Qty, DayNum) as (
select t.*, datediff(d, mdc.min_dt, cast(AppDate as date))
from min_dt_cte mdc
cross join
MyTable t)
select
pdc.Item, pdc.Truck_ID,
iif(pdc.DayNum=1, Qty, 0) Day1,
iif(pdc.DayNum=2, Qty, 0) Day2,
...
iif(pdc.DayNum=14, Qty, 0) Day14
from
pvt_dt_cte pdc;

Related

Select data where sum for last 7 from max-date is greater than x

I have a data set as such:
Date Value Type
2020-06-01 103 B
2020-06-01 100 A
2020-06-01 133 A
2020-06-11 150 A
2020-07-01 1000 A
2020-07-21 104 A
2020-07-25 140 A
2020-07-28 1600 A
2020-08-01 100 A
Like this:
Type ISHIGH
A 1
B 0
Here's the query i tried,
select type, case when sum(value) > 10 then 1 else 0 end as total_usage
from table_a
where (select sum(value) as usage from tableA where date = max(date)-7)
group by type, date
This is clearly not right. What is a simple way to do this?
It is a simply group by except that you need to be able to access max date before grouping:
select type
, max(date) as last_usage_date
, sum(value) as total_usage
, case when sum(case when date >= cutoff_date then value end) >= 1000 then 'y' end as [is high!]
from t
cross apply (
select dateadd(day, -6, max(date))
from t as x
where x.type = t.type
) as ca(cutoff_date)
group by type, cutoff_date
If you want just those two columns then a simpler approach is:
select t.type, case when sum(value) >= 1000 then 'y' end as [is high!]
from t
left join (
select type, dateadd(day, -6, max(date)) as cutoff_date
from t
group by type
) as a on t.type = a.type and t.date >= a.cutoff_date
group by t.type
Find the max date by type. Then used it to find last 7 days and sum() the value.
with
cte as
(
select [type], max([Date]) as MaxDate
from tableA
group by [type]
)
select c.[type], sum(a.Value),
case when SUM(a.Value) > 1000 then 1 else 0 end as ISHIGH
from cte c
inner join tableA a on a.[type] = c.[type]
and a.[Date] >= DATEADD(DAY, -7, c.MaxDate)
group by c.[type]
This can be done through a cumulative total as follows:
;With CTE As (
Select [type], [date],
SUM([value]) Over (Partition by [type] Order by [date] Desc) As Total,
Row_Number() Over (Partition by [type] Order by [date] Desc) As Row_Num
From Tbl)
Select Distinct CTE.[type], Case When C.[type] Is Not Null Then 1 Else 0 End As ISHIGH
From CTE Left Join CTE As C On (CTE.[type]=C.[type]
And DateDiff(dd,CTE.[date],C.[date])<=7
And C.Total>1000)
Where CTE.Row_Num=1
I think you are quite close with you initial attempt to solve this. Just a tiny edit:
select type, case when sum(value) > 1000 then 1 else 0 end as total_usage
from tableA
where date > (select max(date)-7 from tableA)
group by type

My count CTE returning blanks, how can I get it return as 0?

CTE created to count the number of days left from today's date to end of current month. So my report for today (30 March 2021) did not count tomorrow's date 31 March 2021.
declare #DespatchTo Date = '03-30-2021'
WITH mycte AS
(
SELECT CAST(Convert(date,getdate()) AS DATETIME) DateValue
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue < DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, #DespatchTo) + 1, 0)) --03-31-2021
)
SELECT SUN.Count as SunCount, SAT.Count as SatCount, WK.Count as WeekCount
FROM
(SELECT count(*) as Count
FROM mycte
WHERE DatePart("w",DateValue) = 1
group by DatePart("w",DateValue))
As SUN,
(SELECT count(*) as Count
FROM mycte
WHERE DatePart("w",DateValue) = 7
group by DatePart("w",DateValue))
As SAT,
(SELECT distinct SUM(COUNT(*)) OVER() AS Count
FROM mycte
WHERE DatePart("w",DateValue) > 1 AND DatePart("w",DateValue) < 7
group by DatePart("w",DateValue))
As WK
Which returns blank/null results. How can I return as 0?
here is what you need to do:
;WITH mycte AS (
SELECT GETDATE() DateValue
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue < EOMONTH(GETDATE())
)
select
count(case when datepart(dw, DateValue) = 1 then 1 end) SUN
, count(case when datepart(dw, DateValue) = 7 then 1 end) SAT
, count(case when datepart(dw, DateValue) between 2 and 6 then 1 end) WK
from mycte
if you want to exclude today, you can adjust cte :
;WITH mycte AS (
SELECT GETDATE() + 1 DateValue
WHERE GETDATE() <> EOMONTH(GETDATE())
UNION ALL
SELECT DateValue + 1
FROM mycte
WHERE DateValue < EOMONTH(GETDATE())
)
select
count(case when datepart(dw, DateValue) = 1 then 1 end) SUN
, count(case when datepart(dw, DateValue) = 7 then 1 end) SAT
, count(case when datepart(dw, DateValue) between 2 and 6 then 1 end) WK
from mycte

How to write SQL for stock quantity that requires calculation from previous orders

I have two tables, one for current total stock of products and one for the product orders.
STOCK_TB
PRODUCT_ID STOCK_QTY
A 20
B 15
C 10
ORDER_TB
ORDER_DATE PRODUCT_ID ORDER QTY
2015-03-01 A 5
2015-03-02 A 3
2015-03-02 B 4
2015-03-03 C 1
2015-03-04 C 3
I'd like to select data for a monthly-stock quantity report that looks like this. Assume the report was built on March 5th
Stock Quantity of March:
Daily Stock Qty
Product ID 1 2 3 4 5 6 7 ... 28 29 30 31
A 23 20 20 20 20 0 0 0 0 0 0
B 19 15 15 15 15 0 0 0 0 0 0
C 14 14 13 10 10 0 0 0 0 0 0
The stock quantity for previous dates is based on the closing day (I.E: March 2nd above refers to March 2nd 23:59:99.999)
Any dates that goes beyond the current date will have a quantity of 0
We don't have a table for keeping daily-stocks, just the current stock. So this means for getting stocks of previous dates, I'd have to add the amount of product orders backwards.
How do you write this type of query? For the date columns, I can have them fixed from 1 to 31, since I can just hide the unused dates based on the month in my application. But I'm not really sure how I can write logic in SQL for adding order quantity to the current stock on previous dates.
Query example for 6 days (the other 25 days are the same :-)
DECLARE #FirstOfMonth AS DATETIME = DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
SELECT
CASE WHEN DAY(GETDATE()) < 1 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 0, #FirstOfMonth)), 0) END _1,
CASE WHEN DAY(GETDATE()) < 2 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 1, #FirstOfMonth)), 0) END _2,
CASE WHEN DAY(GETDATE()) < 3 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 2, #FirstOfMonth)), 0) END _3,
CASE WHEN DAY(GETDATE()) < 4 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 3, #FirstOfMonth)), 0) END _4,
CASE WHEN DAY(GETDATE()) < 5 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 4, #FirstOfMonth)), 0) END _5,
CASE WHEN DAY(GETDATE()) < 6 THEN 0 ELSE S.STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > DATEADD(day, 5, #FirstOfMonth)), 0) END _6
FROM STOCK_TB S
Note that I've used > DATEADD instead of >= DATEADD but I'm not so sure... The order you put the first of the month when are counted?
Second solution, but I don't think the complexity will change very much:
DECLARE #FirstOfMonth AS DATETIME = DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
DECLARE #Today AS DATETIME = DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0)
;WITH Days(d, dat) AS
(
SELECT 1, #FirstOfMonth
UNION ALL
SELECT d+1, DATEADD(day, 1, dat) FROM Days WHERE d < DATEPART(day, #today)
)
, Work1 AS (
SELECT PRODUCT_ID, STOCK_QTY + ISNULL((SELECT SUM(O.ORDER_QTY) FROM ORDER_TB O WHERE O.PRODUCT_ID = S.PRODUCT_ID AND O.ORDER_DATE > dat), 0) STOCK_TB, d FROM STOCK_TB S, Days
)
SELECT PRODUCT_ID,
ISNULL(MAX(CASE WHEN d = 1 THEN STOCK_TB END), 0) _1,
ISNULL(MAX(CASE WHEN d = 2 THEN STOCK_TB END), 0) _2,
ISNULL(MAX(CASE WHEN d = 3 THEN STOCK_TB END), 0) _3,
ISNULL(MAX(CASE WHEN d = 4 THEN STOCK_TB END), 0) _4,
ISNULL(MAX(CASE WHEN d = 5 THEN STOCK_TB END), 0) _5,
ISNULL(MAX(CASE WHEN d = 6 THEN STOCK_TB END), 0) _6,
ISNULL(MAX(CASE WHEN d = 7 THEN STOCK_TB END), 0) _7,
ISNULL(MAX(CASE WHEN d = 8 THEN STOCK_TB END), 0) _8
FROM Work1 GROUP BY PRODUCT_ID
Here I use a fancy recursive query to build a table of days 1...(today), then I build a Work1 intermediate that has all the stock quantities day by day (so x products * y days rows), and then I group them
Third possibility: double recursive query (one to calculate the numbers 1...31 and one to do a running total), plus the final GROUP BY nearly identical to the previous example.
DECLARE #FirstOfMonth AS DATETIME = DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
DECLARE #Today AS DATETIME = DATEADD(dd, DATEDIFF(dd, 0, GETDATE()), 0)
;WITH Days(d, dat) AS
(
SELECT DATEPART(day, #Today), #Today dat
UNION ALL
SELECT d-1, DATEADD(day, -1, dat) dat
FROM Days
WHERE d > 1
)
# Product Days x STOCK_TB with a LEFT JOIN on ORDER_TB.
, Work1 AS (
SELECT S.PRODUCT_ID, d, dat, S.STOCK_QTY, ISNULL(O.ORDER_QTY, 0) ORDER_QTY
FROM Days
CROSS JOIN STOCK_TB S # Full cartesian product, JOIN without conditions
LEFT JOIN ORDER_TB O ON dat = O.ORDER_DATE AND S.PRODUCT_ID = O.PRODUCT_ID
)
# Second recursive query to do the running total
, Days2(PRODUCT_ID, d, dat, STOCK_QTY) AS
(
SELECT PRODUCT_ID, d, dat, STOCK_QTY
FROM Work1
WHERE d = DATEPART(day, #Today)
UNION ALL
SELECT d.PRODUCT_ID, d.d - 1, w.dat, d.STOCK_QTY + w.ORDER_QTY
FROM Days2 d
INNER JOIN Work1 w ON d.PRODUCT_ID = w.PRODUCT_ID AND d.d /* - 1 */ = w.d
WHERE d.d > 1
)
SELECT PRODUCT_ID,
ISNULL(MAX(CASE WHEN d = 1 THEN STOCK_QTY END), 0) _1,
ISNULL(MAX(CASE WHEN d = 2 THEN STOCK_QTY END), 0) _2,
ISNULL(MAX(CASE WHEN d = 3 THEN STOCK_QTY END), 0) _3,
ISNULL(MAX(CASE WHEN d = 4 THEN STOCK_QTY END), 0) _4,
ISNULL(MAX(CASE WHEN d = 5 THEN STOCK_QTY END), 0) _5,
ISNULL(MAX(CASE WHEN d = 6 THEN STOCK_QTY END), 0) _6,
ISNULL(MAX(CASE WHEN d = 7 THEN STOCK_QTY END), 0) _7,
ISNULL(MAX(CASE WHEN d = 8 THEN STOCK_QTY END), 0) _8
FROM Days2 GROUP BY PRODUCT_ID
Note the /* - 1 */ commented part. Uncommenting it you control how the value of the first of the month is used.

T-SQL NULL-Friendly Query

I have a table "tblSalesOrder" in Microsoft T-SQL with some sample records:
SalesOrderID OrderDate ItemID Quantity PromotionCode
====================================================================
1 2014-09-01 100 5 NULL
2 2014-09-01 120 10 ABC
3 2014-09-05 150 7 NULL
4 2014-09-08 200 15 NULL
I need to return NULL-friendly resultset for records which do not exist.
As an example, I want a monthly query for September 2014:
SELECT SalesOrderID, OrderDate, ItemID, Quantity, PromotionCode
FROM tblSalesOrder
WHERE OrderDate = BETWEEN '2014-09-01' AND '2014-09-30'
I need it to return at least 1 row for each day (i.e. 0 valued row, if the entry for that day is not available)
SalesOrderID OrderDate ItemID Quantity PromotionCode
====================================================================
1 2014-09-01 100 5 NULL
2 2014-09-01 120 10 ABC
0 2014-09-02 0 0 0
0 2014-09-03 0 0 0
0 2014-09-04 0 0 0
3 2014-09-05 150 7 NULL
0 2014-09-06 0 0 0
0 2014-09-07 0 0 0
4 2014-09-08 200 15 NULL
0 2014-09-09 0 0 0
...
...
...
0 2014-09-30 0 0 0
master..spt_values is a table in all microsoft sql databases containing 2506 rows, by cross joining, it will have 2506*2506 rows to calculate dates between from and to. Other tables can be used as well, this is just a table used to create the dates. A calendar table would be even easier to use.
The EXCEPT will remove all dates already in use. Then by combining the rows from tblSalesOrder and CTE with union all, empty days will be filled with the required hardcoded values:
DECLARE #from date = '2014-09-01'
DECLARE #to date = '2014-09-30'
;WITH CTE as
(
SELECT top (case when #to < #from then 0 else datediff(day, #from, #to) + 1 end)
dateadd(day, row_number() over (order by (select 1)) - 1, #from) OrderDate
FROM
master..spt_values t1
CROSS JOIN
master..spt_values t2
EXCEPT
SELECT
OrderDate
FROM
tblSalesOrder
)
SELECT
0 SalesOrderID, OrderDate, 0 ItemID, 0 Quantity, '0' PromotionCode
FROM
CTE
UNION ALL
SELECT
SalesOrderID, OrderDate, ItemID, Quantity, PromotionCode
FROM
tblSalesOrder
ORDER BY
OrderDate, SalesOrderId
You can join the a date parameter in an empty select and coalesce the values:
select coalesce(t.SalesOrderID, 0) SalesOrderID
, coalesce(t.OrderDate, d.OrderDate) OrderDate
, coalesce(t.ItemID, 0) ItemID
, coalesce(t.Quantity, 0) Quantity
, coalesce(t.PromotionCode, 0) PromotionCode
from (select #dateParameter OrderDate) d
left
outer
join ( SELECT SalesOrderID, OrderDate, ItemID, Quantity, PromotionCode
FROM tblSalesOrder
) t
on t.OrderDate = d.OrderDate
DECLARE #startDate date= '20140901'
,#endDate date = '20140930';
WITH Calendar as (
SELECT #startDate as OrderDate
UNION ALL
SELECT DATEADD(DAY, 1, OrderDate) as OrderDate
FROM Calendar
WHERE OrderDate < #endDate
)
SELECT coalesce(t.SalesOrderID, 0) SalesOrderID
, coalesce(t.OrderDate, Calendar.OrderDate) OrderDate
, coalesce(t.ItemID, 0) ItemID
, coalesce(t.Quantity, 0) Quantity
, CASE WHEN t.OrderDate IS NULL THEN '0' ELSE t.PromotionCode END as PromotionCode FROM Calendar
LEFT JOIN tblSalesOrder t ON Calendar.OrderDate = t.OrderDate
ORDER BY Calendar.OrderDate, t.SalesOrderID
OPTION (MAXRECURSION 0);

sql timesheet count by day for the week

my table looks like this:
select clocktime, for_UID, in1_out0 from timeclockentries
clocktime for_UID in1_out0
2011-08-07 15:13:58.390 user193 1
2011-08-07 21:09:45.093 user193 0
2011-08-09 14:10:00.000 user193 1
2011-08-09 20:10:00.000 user193 0
I want the results to look like (assuming start of week is Saturday), separated by COLUMNS named 'day1', 'day2', etc.... (but for readability, i've typed them out with linefeeds) :
day1 day2 day3
1900-01-01 00:00:00.000 1900-01-01 05:55:46.700 1900-01-01 00:00:00.000
day4 day5 day6
1900-01-01 06:00:00.000 1900-01-01 00:00:00.000 1900-01-01 00:00:00.000
day7
1900-01-01 00:00:00.000
(i'm using sql2005)
below is what i'm using for a single day:
CREATE PROCEDURE [dbo].[sp_gethoursbyday]
#whichforUID varchar(20),
#whichdate datetime
AS
BEGIN
;WITH CTE as(
SELECT
DENSE_RANK() over (Partition by for_UID , in1_out0 Order by clocktime) id,
clocktime,
for_UID,
in1_out0
FROM
kdhcastle.dbo.timeclockentries tc
WHERE
tc.for_UID = #whichforUID
and month(tc.[clocktime]) = month(#whichdate)
and day(tc.[clocktime]) = day(#whichdate)
and year(tc.[clocktime]) = year(#whichdate)
)
SELECT
Cast(cast(sum(
cast(outTime.clocktime as float) - cast(inTime.clocktime as float)
)as datetime) as datetime) as 'hoursbydy'
FROM
CTE inTime
INNER JOIN CTE outTime
ON inTime.for_UID = outTime.for_UID
AND inTime.id = outTime.id
AND inTime.in1_out0 = 1
and outTime.in1_out0 = 0
END
SELECT
SUM(CASE WHEN DayOfWeek = 1 THEN Duration ELSE 0 END) AS Day1,
SUM(CASE WHEN DayOfWeek = 2 THEN Duration ELSE 0 END) AS Day2,
SUM(CASE WHEN DayOfWeek = 3 THEN Duration ELSE 0 END) AS Day3,
SUM(CASE WHEN DayOfWeek = 4 THEN Duration ELSE 0 END) AS Day4,
SUM(CASE WHEN DayOfWeek = 5 THEN Duration ELSE 0 END) AS Day5,
SUM(CASE WHEN DayOfWeek = 6 THEN Duration ELSE 0 END) AS Day6,
SUM(CASE WHEN DayOfWeek = 7 THEN Duration ELSE 0 END) AS Day7
FROM
(
SELECT
DATEDIFF(DAY, '2011 Jan 01', clocktime) % 7 + 1 AS DayOfWeek,
CAST(MAX(clocktime) - MIN(clocktime) AS FLOAT) AS Duration
FROM
yourTable
GROUP BY
for_UID,
DATEDIFF(DAY, '2011 Jan 01', clocktime)
)
AS [data]
This is more verbose but my focus was (a) to avoid repeating expressions and (b) to simulate all of the input parameters intended to be fed to the stored procedure so that the results are filtered on the desired user / date. Note that the #whichdate parameter is reeled back to the preceding Saturday at midnight, regardless of which day of the week it is or what time is associated with it.
Input parameters:
DECLARE #whichdate DATETIME;
SET #whichdate = '2011-08-08T12:34:00';
DECLARE #whichforUID VARCHAR(32);
SET #whichforUID = 'user193';
Body (just comment out the DECLARE #t / INSERT #t lines, and change #t in the first CTE to the real table name:
SET #whichdate = DATEADD(DAY, -DATEPART(WEEKDAY, #whichdate), #whichdate);
SET #whichdate = DATEADD(DAY, 0, DATEDIFF(DAY, 0, #whichdate));
DECLARE #t TABLE(clocktime DATETIME, for_UID VARCHAR(32), in1_out0 BIT);
INSERT #t SELECT '2011-08-07 15:13:58.390','user193',1
UNION ALL SELECT '2011-08-07 21:09:45.093','user193',0
UNION ALL SELECT '2011-08-09 14:10:00.000','user193',1
UNION ALL SELECT '2011-08-09 20:10:00.000','user193',0;
WITH s(dw, ct, in1_out0) AS
(
SELECT 1 + (DATEDIFF(DAY, '2011-01-01', clocktime) % 7),
clocktime, in1_out0 FROM #t
where for_UID = #whichforUID
AND clocktime >= #whichdate
AND clocktime < DATEADD(DAY, 7, #whichdate)
),
d(dw, min_ct, max_ct) AS
(
SELECT dw,
MIN(CASE WHEN in1_out0 = 1 THEN ct ELSE NULL END),
MAX(CASE WHEN in1_out0 = 0 THEN ct ELSE NULL END)
FROM s GROUP BY dw
),
x AS
(
SELECT d = DATEADD(MILLISECOND, DATEDIFF(MILLISECOND, min_ct, max_ct), 0),
dw FROM d
),
pvt AS (
SELECT * FROM x PIVOT
(MAX(d) FOR dw IN ([1],[2],[3],[4],[5],[6],[7])) AS p
)
SELECT
day1 = COALESCE([1], '19000101'),
day2 = COALESCE([2], '19000101'),
day3 = COALESCE([3], '19000101'),
day4 = COALESCE([4], '19000101'),
day5 = COALESCE([5], '19000101'),
day6 = COALESCE([6], '19000101'),
day7 = COALESCE([7], '19000101')
FROM pvt;