Dynamic Monthly Pivot Table - sql-server

I have an invoice table that I want to create a rolling monthly dynamic pivot table out of. I want the current month to be month "1" and this month last year to be month "13"
Sample data:
INVOICEDATE | ITEMCODE | UNITS
2018-05-07 | 123456 | 20
2018-05-04 | 123456 | 5
2018-04-07 | 123456 | 10
....
2017-05-25 | 123456 | 50
Desired Output:
ITEMCODE | 01 | 02 | .... | 13
123456 | 25 | 10 | .... | 50
I have start with the following but am getting stuck with the month numbering /ordering piece, especially with the month of last year rolling into the same month of this year.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#NulltoZero nvarchar(max)
select #cols = STUFF((SELECT distinct ',' +
quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2)) [Month]
FROM MAS_RDP..AR_InvoiceHistoryHeader
where invoicedate >= DATEADD(MONTH, -12, DATEADD(month, DATEDIFF(month, 0, getdate()), 0))
order by [Month] DESC
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #NulltoZero = STUFF((SELECT distinct ',ISNULL(' +
quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2)) + ',0) AS ' + quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2))
FROM MAS_RDP..AR_InvoiceHistoryHeader
where invoicedate >= DATEADD(MONTH, -12, DATEADD(month, DATEDIFF(month, 0, getdate()), 0))
order by ',ISNULL(' +
quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2)) + ',0) AS ' + quotename(substring(CONVERT(varchar,INVOICEDATE,112),5,2)) DESC
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT itemcode, ' + #NulltoZero + ' from
(
Select ARD.itemcode
,(12 + DATEPART(MONTH, GETDATE()) - DATEPART(MONTH, invoicedate)) % 12 + 1 [MONTH]
,cast(ISNULL(quantityshipped*[UnitOfMeasureConvFactor],0) as int) as units
FROM [MAS_RDP].[dbo].[AR_InvoiceHistoryDetail] ARD
inner join MAS_RDP..AR_InvoiceHistoryHeader ARH on ARD.InvoiceNo = ARH.InvoiceNo and ARD.HeaderSeqNo = ARH.HeaderSeqNo
inner join MAS_RDP..CI_Item CI on ARD.Itemcode = CI.itemcode and CI.Inactiveitem = ''N'' and CI.itemcode not like ''2%'' and len(ci.itemcode) = 6
inner join MAS_RDP..IM_Itemwarehouse IMW on ARD.itemcode = IMW.itemcode and IMW.warehousecode = ''000'' and imw.udf_is_stocked = ''Y''
where invoicedate >= DATEADD(MONTH, -12, DATEADD(month, DATEDIFF(month, 0, getdate()), 0))
) x
pivot (sum( units ) for month in (' + #cols + ') ) p
order by itemcode'
execute(#query)

Try this solution. Correct me if I'm wrong, but you don't need a dynamic pivot if you know that you want months 1 to 13.
In the first CTE we group data by month, then calculate each month's difference against current month with DATEDIFF MONTH and finally pivot the values just for the month differences 1 to 13.
IF OBJECT_ID('tempdb..#Data') IS NOT NULL
DROP TABLE #Data
CREATE TABLE #Data (
InvoiceDate DATE,
ItemCode INT,
Units INT)
INSERT INTO #Data (
InvoiceDate,
ItemCode,
Units)
VALUES
('2018-05-07', 123456, 20),
('2018-05-04', 123456, 5),
('2018-04-07', 123456, 10),
('2017-05-25', 123456, 50),
('2017-09-07', 123456, 40),
('2018-01-07', 123456, 35)
;WITH GroupedMonths AS
(
SELECT
ItemCode = D.ItemCode,
Year = DATEPART(YEAR, D.InvoiceDate),
Month = DATEPART(MONTH, D.InvoiceDate),
Units = SUM(D.Units),
InitialDate = DATEFROMPARTS(
DATEPART(YEAR, D.InvoiceDate),
DATEPART(MONTH, D.InvoiceDate),
1),
CurrentInitialDate = DATEFROMPARTS(
DATEPART(YEAR, GETDATE()),
DATEPART(MONTH, GETDATE()),
1)
FROM
#Data AS D
GROUP BY
D.ItemCode,
DATEPART(YEAR, D.InvoiceDate),
DATEPART(MONTH, D.InvoiceDate)
),
MonthRankings AS
(
SELECT
G.ItemCode,
G.Units,
MonthRanking = DATEDIFF(MONTH, G.InitialDate, G.CurrentInitialDate) + 1
FROM
GroupedMonths AS G
)
SELECT
T.ItemCode,
'01' = ISNULL(T.[1], 0),
'02' = ISNULL(T.[2], 0),
'03' = ISNULL(T.[3], 0),
'04' = ISNULL(T.[4], 0),
'05' = ISNULL(T.[5], 0),
'06' = ISNULL(T.[6], 0),
'07' = ISNULL(T.[7], 0),
'08' = ISNULL(T.[8], 0),
'09' = ISNULL(T.[9], 0),
'10' = ISNULL(T.[10], 0),
'11' = ISNULL(T.[11], 0),
'12' = ISNULL(T.[12], 0),
'13' = ISNULL(T.[13], 0)
FROM
MonthRankings AS R
PIVOT (
MAX(R.Units) FOR R.MonthRanking IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13])
) AS T

Related

Is there a faster way of adding up time ranges, taking overlaps into account?

I have a subquery that is taking multiple minutes to execute. If I pull out just the initial rows that are being added up, it only takes half a second with 2,400ish rows so I don't understand why the main query doing the sum is taking so long.
What I'm trying to do is for all the transactions in a date range, for all the workers assigned to those transactions, add up the scheduled hours for each worker.
The query is returning the correct data, it's just taking FOREVER to do it.
QUERY
SELECT scheduled_hours = COALESCE(sum(hours), 0), worker_sysid
FROM (
SELECT DISTINCT
B.DateR1,
B.DateR2,
hours = ABS((B.DAteR1 - B.DateR2) / 3600),
B.worker_sysid
FROM Trans A
OUTER APPLY (
SELECT
DateR1 = MIN(TRANS_START),
DateR2 = MAX(TRANS_END),
worker_sysid
FROM Trans
JOIN trans_workers ON trans_workers.trans_sysid = Trans.SYSID
LEFT JOIN Service ON Service.SYSID = Trans.SERVICESYSID
WHERE
TRANS_START <= A.TRANS_END AND TRANS_END >= A.TRANS_START
AND TRANS_START IS NOT NULL AND TRANS_END IS NOT NULL
AND TRANS_START != '' AND TRANS_END != ''
AND Trans.CHARGEBY IN ('Hours', 'Hour')
AND (
COALESCE(Service.overnight, 0) != 1
OR
COALESCE(Service.active_overnight, 0) = 1
)
AND TRANSDATE BETWEEN 80387 AND 80400 ### These are Clarion dates
AND trans_workers.deleted_at IS NULL
GROUP BY worker_sysid
) B
) A
WHERE worker_sysid IS NOT NULL
GROUP BY worker_sysid
TABLES
Trans: SYSID (int, pk), TRANSDATE (int, clarion-formatted date), TRANS_START / TRANS_END (UNIX timestamp), SERVICESYSID (int, fk), CHARGEBY (varchar)
trans_workers: trans_sysid, worker_sysid, deleted_at
Service: SYSID (int, pk)
UPDATE
Moving the trans_workers join out of the OUTER APPLY has reduced the execution time from 1 minute down to 16 seconds, so that's an improvement.
SELECT scheduled_hours = COALESCE(sum(hours), 0), worker_sysid
FROM (
SELECT DISTINCT
B.DateR1,
B.DateR2,
hours = ABS((B.DateR1 - B.DateR2) / 3600),
worker_sysid
FROM Trans A
JOIN trans_workers ON A.SYSID = trans_workers.trans_sysid
OUTER APPLY (
SELECT
DateR1 = MIN(TRANS_START),
DateR2 = MAX(TRANS_END),
Trans.SYSID
FROM Trans
LEFT JOIN Service ON Service.SYSID = Trans.SERVICESYSID
WHERE
TRANS_START <= A.TRANS_END AND TRANS_END >= A.TRANS_START
AND TRANS_START IS NOT NULL AND TRANS_END IS NOT NULL
AND TRANS_START != '' AND TRANS_END != ''
AND Trans.CHARGEBY IN ('Hours', 'Hour')
AND COALESCE(Service.overnight, 0) != 1
AND TRANSDATE BETWEEN 80387 AND 80400
GROUP BY Trans.SYSID
) B
) A
WHERE worker_sysid IS NOT NULL
GROUP BY worker_sysid
ORDER BY worker_sysid
Thanks to https://www.sqlservercentral.com/forums/topic/consolidate-overlapping-date-periods I have a query that executes in under a second and returns what appear to be the correct hours. Only problem being I don't understand what's happening.
DECLARE #start INTEGER, #end INTEGER;
SET #start = 80401; --06/02/2021
SET #end = 80414; --19/02/2021
WITH cteTemp
AS (
SELECT
worker_sysid,
BeginDate =
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY worker_sysid ORDER BY theDate) - openCnt = 0 THEN theDate
END,
EndDate =
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY worker_sysid ORDER BY theDate) - closeCnt = 0 THEN theDate
END
FROM (
SELECT
worker_sysid,
theDate = DATEADD(day, 0, DATEDIFF(day, 0, (dateadd(day,[TRANSDATE]-(4),'1801-01-01')))) + DATEADD(day, 0 - DATEDIFF(day, 0, DATEADD(second, TRANS_START - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01')), DATEADD(second, TRANS_START - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01')),
closeCnt = NULL,
openCnt = (ROW_NUMBER() OVER (PARTITION BY worker_sysid ORDER BY DATEADD(day, 0, DATEDIFF(day, 0, (dateadd(day,[TRANSDATE]-(4),'1801-01-01')))) + DATEADD(day, 0 - DATEDIFF(day, 0, DATEADD(second, TRANS_START - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01')), DATEADD(second, TRANS_START - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01'))) * 2) - 1
FROM
Trans
INNER JOIN trans_workers ON trans_workers.trans_sysid = Trans.SYSID
JOIN Service ON Service.SYSID = Trans.SERVICESYSID
WHERE
worker_sysid IS NOT NULL
AND Trans.deleted_at IS NULL
AND trans_workers.deleted_at IS NULL
AND Trans.CHARGEBY IN ('Hour', 'Hours')
AND (transCancelled IS NULL OR transCancelled != 1)
AND (
COALESCE(Service.overnight, 0) = 0
)
AND TRANSDATE BETWEEN #start AND #end
UNION ALL
SELECT
worker_sysid,
theDate = DATEADD(day, 0, DATEDIFF(day, 0, (dateadd(day,[TRANSDATE]-(4),'1801-01-01')))) + DATEADD(day, 0 - DATEDIFF(day, 0, DATEADD(second, TRANS_END - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01')), DATEADD(second, TRANS_END - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01')),
closeCnt = ROW_NUMBER() OVER (PARTITION BY worker_sysid ORDER BY worker_sysid, DATEADD(day, 0, DATEDIFF(day, 0, (dateadd(day,[TRANSDATE]-(4),'1801-01-01')))) + DATEADD(day, 0 - DATEDIFF(day, 0, DATEADD(second, TRANS_END - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01')), DATEADD(second, TRANS_END - DATEDIFF(S, GETDATE(), GETUTCDATE()), '1970-01-01'))) * 2,
openCnt = NULL
FROM
Trans
JOIN trans_workers ON trans_workers.trans_sysid = Trans.SYSID
JOIN Service ON Service.SYSID = Trans.SERVICESYSID
WHERE
worker_sysid IS NOT NULL
AND Trans.deleted_at IS NULL
AND trans_workers.deleted_at IS NULL
AND Trans.CHARGEBY IN ('Hour', 'Hours')
AND (transCancelled IS NULL OR transCancelled != 1)
AND (
COALESCE(Service.overnight, 0) = 0
)
AND TRANSDATE BETWEEN #start AND #end
)
AS baseSelected
)
SELECT scheduled_hours = SUM(hours), worker_sysid
FROM (
SELECT
dt.worker_sysid,
hours = CAST(ABS(DATEDIFF(second, MIN(dt.BeginDate), MAX(dt.EndDate))) / 3600.0 AS DECIMAL(10,2))
FROM (
SELECT
worker_sysid,
BeginDate,
EndDate,
grpID =
IIF(BeginDate IS NOT NULL, ROW_NUMBER() OVER (PARTITION BY worker_sysid ORDER BY worker_sysid, BeginDate), ROW_NUMBER() OVER (PARTITION BY worker_sysid ORDER BY worker_sysid, EndDate))
FROM
cteTemp
WHERE
BeginDate IS NOT NULL OR EndDate IS NOT NULL
)
AS dt
GROUP BY dt.worker_sysid,grpID
) AS final_table
GROUP BY worker_sysid ORDER BY worker_sysid
Bonus points to myself for conversions because the DATE of each transaction is in Clarion and the TIME of each transaction is a Unix timestamp

How do I create a custom Year/Week field in SQL Server?

I'm trying to extend a CalendarDate table in one of our systems because the initial table only had dates up to the end of 2019. (I know...)
The issue is that one of the fields is a week field for our client that is in the format YYYYXX, where XX is a counter of week (ie 01 - 52).
The problem I am encountering is that there is a corresponding DayOfWeek field where Saturday is 1, and the week in the problem column increments on a Saturday, whereas in SQL Server it seems that DATEPART(WEEK, #Date) increments on a Sunday.
Using a temporary table of dates from today until 2030, is there any way I can compute this column?
One caveat is that the column must contain 52 full weeks per year. This means, for example, that the week 202001 in this column actually started on 2019-12-28, so I cannot simply get the year component from DATEPART(YEAR, #date)
Here is what I have so far (#TempDates is just a table with list of dates from today onward):
SELECT
10 AS TrackingGroupID,
CAST([Date] AS DATETIME) AS CalendarDate,
NULL AS RetailerWeek,
CAST(CAST(DATEPART(YEAR, Date) AS VARCHAR(4))
+ RIGHT('000' + CONVERT(VARCHAR(3), DATEPART(DAYOFYEAR, Date)), 3) AS INT) AS DateID,
UPPER(SUBSTRING(DATENAME(WEEKDAY, Date), 1, 3)) AS DayOfWeek,
CASE UPPER(SUBSTRING(DATENAME(WEEKDAY, Date), 1, 3))
WHEN 'SAT' THEN 1
WHEN 'SUN' THEN 2
WHEN 'MON' THEN 3
WHEN 'TUE' THEN 4
WHEN 'WED' THEN 5
WHEN 'THU' THEN 6
WHEN 'FRI' THEN 7
END AS DayOfWeekID,
-- This is the column that needs fixing
CAST(CAST(DATEPART(YEAR, Date) AS VARCHAR(4))
+ RIGHT('00' + CONVERT(VARCHAR(2), DATEPART(WEEK, Date)), 2) AS INT) AS RetailerWeek2
FROM
#TempDates
I use this code to create date dimension.
This contains the week for every day.
You can generate the week as you wish.
/*Creación de la tabla*/
create table Dimensiones.Fecha
(
FechaSK int not null,
Fecha date not null,
Año smallint not null,
Trimestre smallint not null,
Mes smallint not null,
Semana smallint not null,
Dia smallint not null,
DiaSemana smallint not null,
NTrimestre char(12) not null,
NMes char(15) not null,
NMes3L char(3) not null,
NSemana char(10) not null,
NDia char(6) not null,
NDiaSemana char(10) not null
constraint PK_DIM_TIEMPO PRIMARY KEY CLUSTERED
(
Fecha asc
)
)
/*Script de carga*/
DECLARE #FechaDesde as smalldatetime, #FechaHasta as smalldatetime
DECLARE #FechaAAAAMMDD int
DECLARE #Año as smallint, #Trimestre char(2), #Mes smallint
DECLARE #Semana smallint, #Dia smallint, #DiaSemana smallint
DECLARE #NTrimestre char(12), #NMes char(15)
DECLARE #NMes3l char(3)
DECLARE #NSemana char(10), #NDia char(6), #NDiaSemana char(10)
--Set inicial por si no coincide con los del servidor
SET DATEFORMAT dmy
SET DATEFIRST 1
BEGIN TRANSACTION
--Borrar datos actuales, si fuese necesario
TRUNCATE TABLE dimensiones.fecha
--Rango de fechas a generar: del 01/01/1990 al 31/12/Año actual+2
SELECT #FechaDesde = CAST('19900101' AS smalldatetime)
--SELECT #FechaHasta = CAST(CAST(YEAR(GETDATE())+2 AS CHAR(4)) + '1231' AS smalldatetime)
WHILE (#FechaDesde <= #FechaHasta) BEGIN
SELECT #FechaAAAAMMDD = YEAR(#FechaDesde)*10000+
MONTH(#FechaDesde)*100+
DATEPART(dd, #FechaDesde)
SELECT #Año = DATEPART(yy, #FechaDesde)
SELECT #Trimestre = DATEPART(qq, #FechaDesde)
SELECT #Mes = DATEPART(m, #FechaDesde)
SELECT #Semana = DATEPART(wk, #FechaDesde)
SELECT #Dia = RIGHT('0' + DATEPART(dd, #FechaDesde),2)
SELECT #DiaSemana = DATEPART(DW, #FechaDesde)
SELECT #NMes = DATENAME(mm, #FechaDesde)
SELECT #NMes3l = LEFT(#NMes, 3)
SELECT #NTrimestre = 'Trimestre ' + CAST(#Trimestre as CHAR(1))
SELECT #NSemana = 'Sem ' +CAST(#Semana AS CHAR(2)) + '/' + RIGHT(RTRIM(CAST(#Año as CHAR(4))),2)
SELECT #NDia = CAST(#Dia as CHAR(2)) + ' ' + RTRIM(#NMes)
SELECT #NDiaSemana = DATENAME(dw, #FechaDesde)
INSERT INTO Dimensiones.Fecha
(
FechaSK,
Fecha,
Año,
Trimestre,
Mes,
Semana,
Dia,
DiaSemana,
NTrimestre,
NMes,
NMes3L,
NSemana,
NDia,
NDiaSemana
) VALUES
(
#FechaAAAAMMDD,
#FechaDesde,
#Año,
#Trimestre,
#Mes,
#Semana,
#Dia,
#DiaSemana,
#NTrimestre,
#NMes,
#NMes3l,
#NSemana,
#NDia,
#NDiaSemana
)
--Incremento del bucle
SELECT #FechaDesde = DATEADD(DAY, 1, #FechaDesde)
END
COMMIT TRANSACTION
If you set the DATEFIRST to 6 then a week starts on saturday.
Then by using a CASE WHEN the year & week can be adjusted.
...
CAST(
CASE
WHEN DATEPART(week, [Date]) > 52
THEN (100*(YEAR([Date])+1))+1
ELSE (100* YEAR([Date])) + DATEPART(week, [Date])
END AS VARCHAR(6)) as RetailerWeek2
...
Example:
SET DATEFIRST 6; -- 6: Saturday
SELECT ##DATEFIRST AS datefirst;
SELECT [Date]
, DATEPART(week, [Date]) as WeekNr
, DATEPART(dw, [Date]) as WeekdayNr
, CAST(
CASE
WHEN DATEPART(week, [Date]) > 52
THEN (100*(YEAR([Date])+1))+1
ELSE (100* YEAR([Date])) + DATEPART(week, [Date])
END AS VARCHAR(6)) as AdjustedYearWeek
FROM (VALUES
(CAST('2019-12-28' AS DATE)),
(CAST('2020-01-01' AS DATE)),
(CAST('2020-12-31' AS DATE))
) q([Date]);
GO
| datefirst |
| :-------- |
| 6 |
Date | WeekNr | WeekdayNr | AdjustedYearWeek
:------------------ | -----: | --------: | :---------------
28/12/2019 00:00:00 | 53 | 1 | 202001
01/01/2020 00:00:00 | 1 | 5 | 202001
31/12/2020 00:00:00 | 53 | 6 | 202101
db<>fiddle here

SQLSERVER 2008: Breaking a output for the entire day into 2 records for 12 hours

I am looking for the count of records as below.
PLANNED_SHIP_From_Date PLANNED_SHIP_To Date Total_Lines_Count ....
1) 09-04-2016 07:00:01 09-04-2016 18:59:59 165 .....
2) 09-04-2016 19:00:00 10-04-2016 07:00:00 121 .....
3) 10-04-2016 07:00:01 10-04-2016 18:59:59 165 .....
4) 10-04-2016 19:00:00 11-04-2016 07:00:00 123 .....
5) 11-04-2016 07:00:01 11-04-2016 18:59:59 234 .....
.
Currently my query is counting the records as per date.
SELECT
cast(shdr.PLANNED_SHIP_DATE as date),
SUM(sdtl_1_1.TOTAL_LINES_COUNT) AS TOTAL_LINES_COUNT
FROM
dbo.SHIPMENT_HEADER AS shdr WITH (NOLOCK)
INNER JOIN
(
SELECT
SHIPMENT_ID,
COUNT(*) AS TOTAL_LINES_COUNT
FROM
dbo.SHIPMENT_DETAIL AS SHIPMENT_DETAIL_1 WITH (NOLOCK)
WHERE
(
STATUS1 >= 401
)
AND (
DATEDIFF(day, PLANNED_SHIP_DATE, CONVERT(date, SYSDATETIME())) < 4
)
GROUP BY
SHIPMENT_ID
) AS sdtl_1_1
ON sdtl_1_1.SHIPMENT_ID = shdr.SHIPMENT_ID
WHERE
(
shdr.TRAILING_STS >= 401
)
AND (
DATEDIFF(day, shdr.PLANNED_SHIP_DATE, CONVERT(date, SYSDATETIME())) < 4
)
GROUP BY
cast(shdr.PLANNED_SHIP_DATE as date)
Try this -
DECLARE #ReportDays int = 30,
#StartHr int = 7,
#Today DATETIME2 = CAST(SYSDATETIME() AS DATE);
--http://sqlblog.com/blogs/adam_machanic/archive/2006/07/12/you-require-a-numbers-table.aspx
WITH
a AS (SELECT 1 AS i UNION ALL SELECT 1),
b AS (SELECT 1 AS i FROM a AS x, a AS y),
c AS (SELECT 1 AS i FROM b AS x, b AS y),
d AS (SELECT 1 AS i FROM c AS x, c AS y),
e AS (SELECT 1 AS i FROM d AS x, d AS y),
numbers as (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1 AS number FROM e),
StartDates AS (
SELECT
DATEADD(
HH,
#StartHr + (n2.number * 12),
DATEADD(D, 0-n1.number, #Today)
) AS StartDT
FROM
(SELECT * FROM numbers WHERE Number BETWEEN 0 AND #ReportDays) n1
CROSS JOIN (SELECT * FROM numbers WHERE Number IN (0,1)) n2
),
DateRanges AS
(SELECT StartDT, DATEADD(hh, 12, StartDT) AS EndDT FROM StartDates),
Shipments AS
(SELECT
StartDT AS PLANNED_SHIP_From_Date,
EndDT AS PLANNED_SHIP_To_Date,
1 AS Shipment
FROM
DateRanges dr
LEFT JOIN dbo.SHIPMENT_DETAIL sd
ON sd.Status1 >=401
AND sd.PLANNED_SHIP_DATE BETWEEN dr.StartDT AND dr.EndDT)
SELECT
PLANNED_SHIP_From_Date,
PLANNED_SHIP_To_Date,
SUM(Shipment) AS TOTAL_LINES_COUNT
FROM
Shipments
ORDER BY
PLANNED_SHIP_From_Date;
What we're doing is -
Building a numbers table
Using that to pull a list of days, with two records per day
Working out the start & finish times for each time window
Joining the time windows to the records and summing
Hope that helps :-)
Add another column to your select....
CASE
WHENE DATEPART(HOUR, Planned_SHIP_DATE) < 12 THEN 'AM' ELSE 'PM'
END AS ShipPeriod
You could then add that column into a GROUPING to seperate the 'AM's from 'PM's
Of course I have assuumed you wanted AM/PM. But you can modify the CASE statement to break the hours up as you see fit.
Hope this helps
Thank you all for helping me out.
I have created a SQL query which worked for me. This query gives the count of records from morning 7 AM to 7 PM as MORNING_SHIFT count and 7PM to next day 7AM morning as EVENING_SHIFT for dates greater than 14 days in the past.
SELECT
CASE
WHEN convert(VARCHAR(50), sh.PLANNED_SHIP_DATE, 120) BETWEEN
(convert(VARCHAR(10), sh.PLANNED_SHIP_DATE, 120) + ' 07:00:00') AND
(convert(VARCHAR(10), sh.PLANNED_SHIP_DATE, 120) + ' 18:59:59')
THEN (CONCAT(cast(sh.PLANNED_SHIP_DATE as date),' ','morning_shift'))
WHEN convert(VARCHAR(50), sh.PLANNED_SHIP_DATE, 120) BETWEEN
(convert(VARCHAR(10), sh.PLANNED_SHIP_DATE, 120) + ' 00:00:00') AND
(convert(VARCHAR(10), sh.PLANNED_SHIP_DATE, 120) + ' 06:59:59')
then (CONCAT(cast(DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) as date),' ','EVENING_shift'))
when
convert(VARCHAR(50), DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) , 120) BETWEEN (convert(VARCHAR(10), cast(DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) as date), 120) + ' 19:00:00') AND
(convert(VARCHAR(10), cast(DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) as date), 120) + ' 23:59:59')
THEN (CONCAT(cast(DATEADD(DAY, -1, sh.PLANNED_SHIP_DATE) as date),' ','EVENING_shift'))
END AS 'actual_date_time', sh.PLANNED_SHIP_DATE
FROM dbo.SHIPMENT_HEADER AS sh WITH (nolock)
WHERE (shdr.TRAILING_STS >= 401) AND (DATEDIFF(day, shdr.ACTUAL_SHIP_DATE_TIME, CONVERT(date, SYSDATETIME())) < 14)
group by sh.ACTUAL_SHIP_DATE_TIME;

How to display all the days of a month in SQL Server 2008?

I have written a query like
SELECT
Sum(a.in_total) as Totall,
DATEPART(dd, a.in_date_issued) as dateissued
FROM
dbo.IN_Invoices as a
WHERE
DATEPART(mm, a.in_date_issued) = 5
AND DATEPART(yyyy, a.in_date_issued)= 2015
AND a.sy_id='DPI'
AND EXISTS(SELECT DISTINCT cl_id as clid
FROM dbo.cloi_clientorderitems as c
WHERE c.masterorderid=a.masterorderid)
--AND c.cl_id NOT IN ('100001_DPO'))
GROUP BY
DATEPART(dd, a.in_date_issued)
ORDER BY dateissued ASC
This query will written the out put like
Total| day
100 | 1
0 | 3
150 | 10
-
-
200 | 31
Expected output
Total| day
100 | 1
150 | 2
0 | 3
600 | 4
-
-
200 | 31
Please help me in that query.
You can try something like this:
DECLARE #y INT;
DECLARE #m INT;
SET #y = 2015;
SET #m = 5;
WITH
m AS(SELECT 1 AS d UNION ALL SELECT d+1 FROM m WHERE d < datediff(d, DATEADD(mm, #m - 1, CAST(#y AS VARCHAR(8)) + '0101'), dateadd(m, 1, DATEADD(mm, #m - 1, CAST(#y AS VARCHAR(8)) + '0101'))))
SELECT isnull(Totall, 0) AS Totall, m.d AS dateissued
FROM m
LEFT JOIN(
SELECT SUM(a.in_total) AS Totall ,
DATEPART(dd, a.in_date_issued) AS dateissued
FROM dbo.IN_Invoices AS a
WHERE DATEPART(mm, a.in_date_issued) = #m
AND DATEPART(yyyy, a.in_date_issued) = #y
AND a.sy_id = 'DPI'
AND EXISTS ( SELECT DISTINCT
cl_id AS clid
FROM dbo.cloi_clientorderitems AS c
WHERE c.masterorderid = a.masterorderid )
--and c.cl_id not in ('100001_DPO'))
GROUP BY DATEPART(dd, a.in_date_issued)
)t ON m.d = t.dateissued
ORDER BY m.d ASC

display all the date between two date with data

I got the following code from this forum.It retrieve data from staff attendance from the table like:
userid dateandtime checktype
1. 100 01/01/2015 I
2. 100 01/01/2015 O
3. 102 02/02/2015 I
4. 102 02/02/2015 O
Now I want to retrieve all the data between two specific date but all the date should be retrieved even one absent and these days should show blank or zero in the column of hours
SELECT t.UserID ,
[Date] = DATEADD(dd, 0, DATEDIFF(dd, 0, t.CheckIn)) ,
CheckIn = CONVERT(VARCHAR(10), t.CheckIn, 108) ,
CheckOut = CONVERT(VARCHAR(10), t.CheckOut, 108) ,
[Hours] = CAST(DATEDIFF(MINUTE, t.CheckIn, t.CheckOut) / 60. AS DECIMAL(10,
2))
FROM ( SELECT t.UserID ,
CheckIn = t.Checktime ,
CheckOut = r.Checktime ,
RowNum = ROW_NUMBER() OVER ( PARTITION BY t.UserID,
r.Checktime ORDER BY 1 / 0 )
FROM CHECKINOUT t
OUTER APPLY ( SELECT TOP 1
*
FROM CHECKINOUT t2
WHERE t2.UserID = t.UserID
AND t2.Checktime > t.Checktime
AND DATEADD(dd, 0,
DATEDIFF(dd, 0,
t.Checktime)) = DATEADD(dd,
0,
DATEDIFF(dd, 0,
t2.Checktime))
AND t2.Checktype = 'O'
ORDER BY t2.Checktime
) r
WHERE t.Checktype = 'I'
) t
WHERE t.RowNum = 1

Resources