Need count in the query - sql

In sp here I am trying to get a count of how many records meet the criteria so that I can display as a total in the tile of the app. But am not having success with this, can you tell me how to make a count and where to put that.
(
#P_FACILITY_KEY_CSV VARCHAR(MAX)
, #DATEFROM DATETIME
, #DATETHRU DATETIME
, #P_TOTALS NUMERIC(1, 0)
)
AS
BEGIN
DECLARE #DFACKEY CHAR(4)
DECLARE #IRENEWALLCYCLEPERIOD NUMERIC
SET #IRENEWALLCYCLEPERIOD = OGEN.READ_PARAM(349, #P_FACILITY_KEY_CSV, '')
EXEC OGEN.GET_CODE_FACILITY #P_FACILITY_KEY_CSV, 'OGEN.GEN_M_DOCTOR_MAST', 'BASE', #DFACKEY OUTPUT;
IF #P_TOTALS = 1 BEGIN
SELECT P.NURSING_UNIT,
ISNULL( SR.USER_DEFINED_DUE_DATE, ISNULL(SR.RECERT_DATE, P.ADMIT_DATE) + #IRENEWALLCYCLEPERIOD) DUE_DATE,
CONVERT(NUMERIC, ISNULL( SR.USER_DEFINED_DUE_DATE, ISNULL(SR.RECERT_DATE, P.ADMIT_DATE) + #IRENEWALLCYCLEPERIOD) - GETDATE()) REMAINING
FROM OGEN.GEN_M_PATIENT_MAST P
LEFT OUTER JOIN OGEN.GEN_M_DOCTOR_MAST D ON P.PRIMARY_DOCTOR_KEY = D.DOCTOR_KEY AND D.FACILITY_KEY = #DFACKEY
LEFT OUTER JOIN OPTC.ORD_D_SCHEDULED_RECERTS SR ON P.PAT_NUMBER = - SR.PAT_NUMBER
LEFT OUTER JOIN OGEN.GEN_M_USER U ON U.USER_ID = SR.RECERT_BY
WHERE P.FACILITY_KEY IN(SELECT VALUE FROM OGEN.COMMA_TO_TABLE(#P_FACILITY_KEY_CSV))
AND DISCHARGE_DATE IS NULL
AND ( ( (#DATEFROM > 0) AND (OGEN.DATEONLY(ISNULL( SR.USER_DEFINED_DUE_DATE, ISNULL(SR.RECERT_DATE, P.ADMIT_DATE) + #IRENEWALLCYCLEPERIOD)) >= #DATEFROM) )
OR
(#DATEFROM = 0) )
AND ( ( (#DATETHRU > 0) AND (OGEN.DATEONLY(ISNULL( SR.USER_DEFINED_DUE_DATE, ISNULL(SR.RECERT_DATE, P.ADMIT_DATE) + #IRENEWALLCYCLEPERIOD)) <= #DATETHRU) )
OR
( #DATETHRU = 0) )
ORDER BY REMAINING;
END ELSE BEGIN
SELECT P.*, D.DR_FULL_NAME PRIMARY_DOCTOR_NAME,
SR.RECERT_DATE, SR.RECERT_BY, U.USER_NAME,
ISNULL( SR.USER_DEFINED_DUE_DATE, ISNULL(SR.RECERT_DATE, P.ADMIT_DATE) + #IRENEWALLCYCLEPERIOD) DUE_DATE,
CONVERT(NUMERIC, ISNULL( SR.USER_DEFINED_DUE_DATE, ISNULL(SR.RECERT_DATE, P.ADMIT_DATE) + #IRENEWALLCYCLEPERIOD) - GETDATE()) REMAINING
FROM OGEN.GEN_M_PATIENT_MAST P
LEFT OUTER JOIN OGEN.GEN_M_DOCTOR_MAST D ON P.PRIMARY_DOCTOR_KEY = D.DOCTOR_KEY AND D.FACILITY_KEY = #DFACKEY
LEFT OUTER JOIN OPTC.ORD_D_SCHEDULED_RECERTS SR ON P.PAT_NUMBER = - SR.PAT_NUMBER
LEFT OUTER JOIN OGEN.GEN_M_USER U ON U.USER_ID = SR.RECERT_BY
WHERE P.FACILITY_KEY IN(SELECT VALUE FROM OGEN.COMMA_TO_TABLE(#P_FACILITY_KEY_CSV))
AND DISCHARGE_DATE IS NULL
AND ( ( (#DATEFROM > 0) AND (OGEN.DATEONLY(ISNULL( SR.USER_DEFINED_DUE_DATE, ISNULL(SR.RECERT_DATE, P.ADMIT_DATE) + #IRENEWALLCYCLEPERIOD)) >= #DATEFROM) )
OR
(#DATEFROM = 0) )
AND ( ( (#DATETHRU > 0) AND (OGEN.DATEONLY(ISNULL( SR.USER_DEFINED_DUE_DATE, ISNULL(SR.RECERT_DATE, P.ADMIT_DATE) + #IRENEWALLCYCLEPERIOD)) <= #DATETHRU) )
OR
( #DATETHRU = 0) )
ORDER BY DUE_DATE
END
END

Do you just want an additional column in the query that is the COUNT of all records returned?
SELECT COUNT(1) OVER () Total,
.. <all your other columns> ..
Or if you can return it as the SP return value, then
RETURN ##ROWCOUNT
at the end, assuming what you have shown (the IF/SELECTs) is the end of your SP.

Related

How to make a CASE in the where clause

I have this stored procedure
ALTER PROC rpt_ItemsSales_DayMonthYear_Week --'2022-01-01','2022-02-1',0
#from datetime,
#to datetime,
#ByOpenShift bit
AS
SET DATEFIRST 7
;WITH Weeks (WeeksNumber) AS
(SELECT 1
UNION ALL
SELECT WeeksNumber + 1
FROM Weeks
WHERE WeeksNumber < 4)
SELECT SalesPos_Dtls.ItemName,
SUM(SalesPos_Dtls.Qty) AS SumQty,
SUM(SalesPos_Dtls.TotalPrice) AS SumTotal,
CAST(SalesPos.StartDate AS date) AS StartDate,
N'الاسبوع ' + CAST(FLOOR((DATEPART(DAY, SalesPos.StartDate) - 2) / 7) + 1 AS varchar(10)) AS Week,
[dbo].[StartOfWeek](SalesPos.StartDate) AS FirstDay,
SalesPos_Dtls.ItemId
FROM Weeks
LEFT JOIN SalesPos ON CAST(FLOOR((DATEPART(DAY, SalesPos.StartDate) - 2) / 7) + 2 AS varchar(10)) = Weeks.WeeksNumber
AND (status = 'IsPosted')
LEFT JOIN SalesPos_Dtls ON SalesPos.ID = SalesPos_Dtls.OrderId
LEFT JOIN Shift_Open ON Shift_Open.Shift_Id = SalesPos.Shift_Id
WHERE (#from <= SalesPos.StartDate
OR #from IS NULL)
AND (#to >= SalesPos.StartDate
OR #to IS NULL)
GROUP BY SalesPos_Dtls.ItemName,
SalesPos_Dtls.ItemCode,
Weeks.WeeksNumber,
CAST(SalesPos.StartDate AS date),
SalesPos.StartDate,
SalesPos_Dtls.ItemId;
That I want it to if the #ByOpenShift is 0 then the #from and #to will be selected from SalesPos.StartDate else it wil be selected from Shift_Open.OpenDate
edit:
after using ADN/OR logic it worked fine.
((((CAST(SalesPos.StartDate AS date)>= CAST(#from AS date)and CAST(SalesPos.StartDate AS date) <=CAST(#to AS date)) or(#from is null) and (#to is null) )
and (#ByOpenShift = 0 or #ByOpenShift is null))
or ((CAST(Shift_Open.OpenDate AS date)>= CAST(#from AS date)and CAST(SalesPos.StartDate AS date) <=CAST(#to AS date))
or(#from is null) and (#to is null)))

SQL Server 2014 Select total for each day

Hello I am working on a dataset for a report in SSRS
and I have a query which gives the total requests in the backlog :
SELECT
COUNT(*) as NB
FROM p_rqt WITH (NOLOCK)
INNER JOIN p_cpy WITH (NOLOCK) ON p_cpy.CpyInCde = p_rqt.OrigCpyInCde
WHERE
CpyTypInCde IN (27, 31)
AND p_rqt.RqtNatInCde IN (74, 75, 76)
AND HeadRqtInCde = 0
AND p_rqt.OrigCpyInCde LIKE CASE WHEN #Client = 0 THEN '%' ELSE #Client END
AND ((RcvDte < DATEADD(day, 1, #DateDeb) AND RqtEndDte IS NULL) OR
(RcvDte < DATEADD(day, 1, #DateDeb) AND RqtEndDte > DATEADD(day, 1, #DateDeb)))
and I want to retrieve the total amount left per day.
I tried lot of things like this :
SELECT CONVERT(date,rcvdte,103), count(*) as nb
FROM p_rqt p WITH (NOLOCK)
INNER JOIN p_cpy WITH (NOLOCK) ON p_cpy.CpyInCde = p.OrigCpyInCde
WHERE
CpyTypInCde IN (27, 31)
AND p.RqtNatInCde IN (74, 75, 76)
AND HeadRqtInCde = 0
AND ((RcvDte < DATEADD(day, 1, '20170901') AND RqtEndDte IS NULL) OR (RcvDte < DATEADD(day, 1, '20170901') AND RqtEndDte > DATEADD(day, 1, '20170901')))
group by CONVERT(date,rcvdte,103)
order by CONVERT(date,rcvdte,103)
I tried inner join subqueries, Sum and other stuff
but all I can manage to do is to have the number of records added per day
and I want something like this :
date: NB:
01/01/2017 1950
02/01/2017 1954 (+4 items)
03/01/2017 1945 (-9 items)
Thank you
Use LAG:
WITH cte AS (
SELECT
CONVERT(date, rcvdte, 103) AS date,
COUNT(*) AS nb
FROM p_rqt p WITH (NOLOCK)
INNER JOIN p_cpy WITH (NOLOCK)
ON p_cpy.CpyInCde = p.OrigCpyInCde
WHERE
CpyTypInCde IN (27, 31) AND
p.RqtNatInCde IN (74, 75, 76) AND
HeadRqtInCde = 0 AND
((RcvDte < DATEADD(day, 1, '20170901') AND RqtEndDte IS NULL) OR (RcvDte < DATEADD(day, 1, '20170901') AND RqtEndDte > DATEADD(day, 1, '20170901')))
GROUP BY CONVERT(date, rcvdte, 103)
ORDER BY CONVERT(date, rcvdte, 103)
)
SELECT
t1.date,
(SELECT SUM(t2.nb) FROM cte t2 WHERE t2.date <= t1.date) AS nb,
CASE WHEN t1.nb - LAG(t1.nb, 1, t1.nb) OVER (ORDER BY t1.date) > 0
THEN '(+' + (t1.nb - LAG(t1.nb, 1, t1.nb) OVER (ORDER BY t1.date)) + ' items)'
ELSE '(' + (t1.nb - LAG(t1.nb, 1, t1.nb) OVER (ORDER BY t1.date)) + ' items)'
END AS difference
FROM cte t1
ORDER BY t1.date;
So i found a solution but it is really slow,
i still post the answer anyway
DECLARE #Tb TABLE ( Colonne1 Datetime, Colonne2 INT )
DECLARE #Debut Datetime = '01/09/2017'
WHILE #Debut < '13/09/2017'
BEGIN
DECLARE #Compteur int = (
SELECT
COUNT(1) NB
FROM p_rqt WITH (NOLOCK)
INNER JOIN p_cpy WITH (NOLOCK) ON p_cpy.CpyInCde = p_rqt.OrigCpyInCde
WHERE
CpyTypInCde IN (27, 31)
AND p_rqt.RqtNatInCde IN (74, 75, 76)
AND HeadRqtInCde = 0
AND p_rqt.OrigCpyInCde LIKE '%'
AND (
(RcvDte < #Debut AND RqtEndDte IS NULL)
OR
(RcvDte < #Debut AND RqtEndDte > #Debut)
)
)
INSERT INTO #Tb (Colonne1, Colonne2) VALUES (#Debut, #Compteur)
SET #Debut = DATEADD(day, 1, #Debut)
IF #Debut > '13/09/2017'
BREAK
ELSE
CONTINUE
END
SELECT * FROM #Tb

Error message running query - Column name or number of supplied values does not match table definition

I am attempting to update a stored procedure and have added u.DIVISION in the code however I am not getting the error message
Column name or number of supplied values does not match table definition.
Any suggestions on what I might be missing?
SET ansi_nulls ON
go
SET quoted_identifier ON
go
ALTER PROCEDURE [dbo].[Slx_activity]
AS
DECLARE #ReportStartDate DATETIME,
#ReportEndDate DATETIME
DECLARE #Today DATETIME
SET #Today = Getdate()
DECLARE #Diff INT
SET #Diff = Datediff(day, Dateadd(day, 5, 0), #Today)
SET #ReportEndDate = Dateadd(day, #Diff - #Diff % 7, Dateadd(day, 5, 0))
SET #ReportStartDate = Datediff(day, 6, #ReportEndDate)
IF Object_id('SLXActivity', 'U') IS NOT NULL
DROP TABLE slxactivity;
SELECT ' Current Activity:' + ' ' + p.[text] AS [TYPE],
h.createdate,
p.[text],
h.[description],
h.startdate,
Cast (NULL AS DATETIME) AS COMPLETEDDATE,
NULL AS BIDNUMBER,
NULL AS BIDSTATUS,
h.userid,
h.accountid,
h.contactid,
h.opportunityid
INTO slxactivity
FROM [SalesLogix_Production].[sysdba].[activity] h
LEFT JOIN [SalesLogix_Production].[sysdba].[picklist] p
ON h.[type] = p.id
WHERE p.[text] NOT IN ( 'Personal Activity' )
AND Cast(h.startdate AS DATE) BETWEEN
#ReportStartDate AND #ReportEndDate
INSERT INTO slxactivity
SELECT ' Completed Activity:' + ' ' + p.[text] AS [TYPE],
h.createdate,
p.[text],
h.[description],
h.startdate,
h.completeddate,
NULL AS BIDNUMBER,
NULL AS BIDSTATUS,
h.userid,
h.accountid,
h.contactid,
h.opportunityid
FROM (SELECT accountid,
[description],
Min(historyid) AS HISTORYID,
completeddate
FROM [SalesLogix_Production].[sysdba].[history]
GROUP BY accountid,
[description],
completeddate) a1
LEFT JOIN [SalesLogix_Production].[sysdba].[history] h
ON a1.accountid = h.accountid
AND a1.historyid = h.historyid
LEFT JOIN [SalesLogix_Production].[sysdba].[picklist] p
ON h.[type] = p.id
WHERE p.[text] NOT IN ( 'Personal Activity' )
AND Cast(h.completeddate AS DATE) BETWEEN
#ReportStartDate AND #ReportEndDate
INSERT INTO slxactivity
SELECT 'Opportunity Added' AS [TYPE],
o.createdate,
o.status AS [TEXT],
NULL AS [DESCRIPTION],
o.estimatedclose AS STARTDATE,
NULL AS COMPLETEDDATE,
NULL AS BIDNUMBER,
NULL AS BIDSTATUS,
o.createuser,
o.accountid,
NULL AS CONTACTID,
o.opportunityid
FROM [SalesLogix_Production].[sysdba].[opportunity] o
WHERE Cast(o.createdate AS DATE) BETWEEN
#ReportStartDate AND #ReportEndDate
INSERT INTO slxactivity
SELECT 'Contact Added' AS [TYPE],
c.createdate,
NULL AS [TEXT],
NULL AS [DESCRIPTION],
NULL AS STARTDATE,
NULL AS COMPLETEDDATE,
NULL AS BIDNUMBER_STATIC,
NULL AS BID_STATUS,
c.createuser,
c.accountid,
c.contactid,
u.division,
NULL AS OPPORTUNITYID
FROM [SalesLogix_Production].[sysdba].[contact] c
LEFT JOIN [SalesLogix_Production].[sysdba].[userinfo] u
ON c.createuser = u.userid
LEFT JOIN [SalesLogix_Production].[sysdba].[usersecurity] us
ON u.userid = us.userid
WHERE Cast(c.createdate AS DATE) BETWEEN
#ReportStartDate AND #ReportEndDate
INSERT INTO slxactivity
SELECT 'Account Created' AS [TYPE],
a.createdate,
a.type AS [TEXT],
a.industry AS [DESCRIPTION],
NULL AS STARTDATE,
NULL AS COMPLETEDDATE,
NULL AS BIDNUMBER_STATIC,
NULL AS BID_STATUS,
a.createuser,
a.accountid,
NULL AS CONTACTID,
NULL AS OPPORTUNITYID
FROM [SalesLogix_Production].[sysdba].[account] a
WHERE Cast(a.createdate AS DATE) BETWEEN
#ReportStartDate AND #ReportEndDate
SELECT t.[type],
t.createdate,
t.[text],
u.username,
a.account,
c.lastname + ', ' + c.firstname AS [CONTACT],
o.[description] AS OPPORTUNITY,
oe.bidnumber_static,
oe.bid_status,
t.[description],
t.startdate,
t.completeddate,
u.division,
#ReportStartDate AS ReportStartDate,
#ReportEndDate AS ReportEndDate
FROM [SalesLogix_Production].[sysdba].[userinfo] u
JOIN [SalesLogix_Production].[sysdba].[usersecurity] us
ON u.userid = us.userid
LEFT JOIN slxactivity t
ON u.userid = t.userid
LEFT JOIN [SalesLogix_Production].[sysdba].[account] a
ON t.accountid = a.accountid
LEFT JOIN [SalesLogix_Production].[sysdba].[contact] c
ON t.contactid = c.contactid
LEFT JOIN [SalesLogix_Production].[sysdba].[opportunity] o
ON t.opportunityid = o.opportunityid
LEFT JOIN [SalesLogix_Production].[sysdba].[c_opportunity_ext] oe
ON t.opportunityid = oe.opportunityid
WHERE us.[type] NOT IN ( 'R', 'W' )
AND u.username <> 'svc_slxadmin'
You need to specify the column in the first statement which creates the table:
SELECT ' Current Activity:' + ' ' + p.[text] AS [TYPE],
h.createdate,
p.[text],
h.[description],
h.startdate,
Cast (NULL AS DATETIME) AS COMPLETEDDATE,
NULL AS BIDNUMBER,
NULL AS BIDSTATUS,
h.userid,
h.accountid,
h.contactid,
CAST(NULL AS VARCHAR(100)) AS division,
/*
you need to specify/select the column here, with the relevant
type, in this context. I assumed it's a string just for the example.
*/
h.opportunityid
INTO slxactivity
FROM [SalesLogix_Production].[sysdba].[activity] h
LEFT JOIN [SalesLogix_Production].[sysdba].[picklist] p
ON h.[type] = p.id
WHERE p.[text] NOT IN ( 'Personal Activity' )
AND Cast(h.startdate AS DATE) BETWEEN
#ReportStartDate AND #ReportEndDate

Conditional Join or ignore results when second value is null

I've tried to focus on just the portion of my main query giving me trouble. This query is being used to populate an SSRS report which has an optional date parameter. This query snippet is used in a LEFT Join. If no date is specified, all matching records should be returned. That seems to work. But if I specify a date and no records are returned in the second column, no results for that row should be displayed. Not sure if I explained that well.
Here is the snippet:
DECLARE #DispoStartDt datetime, #DispoEndDt datetime, #DispoCode varchar(800)
SET #DispoStartDt = '5-1-2050'
--SET #DispoEndDt = '12-31-2014'
SET #DispoCode = '_NULL'
SELECT c1.CaseID,
STUFF((SELECT '; ' + CONVERT(VARCHAR(10), ct.DispoDt, 101)
FROM jw50_CountInvPers ct
WHERE ct.CaseID = '00-100'
AND (ct.DispoDt >= DATEADD(dd, DATEDIFF(dd, 0, ISNULL(#DispoStartDt, ct.DispoDt)), 0) AND ct.DispoDt < DATEADD(dd, DATEDIFF(dd, -1, ISNULL(#DispoEndDt, ct.DispoDt)), 0))
ORDER BY DispoDesc
FOR XML PATH('')), 1, 1, '') [DispoDts]
FROM jw50_Case c1
WHERE c1.CaseID = '00-100'
GROUP BY c1.CaseID
My results are:
CaseID DispoDts
00-100 NULL
I want no records returned if DispoDts is NULL. Since I cannot reference a column alias, is there another way than putting this in a sub select?
EDIT:
Here is the snippet used in my Join. I'm getting rows with NULL DispoDts because of the left join. If I specify a start date, I want the results to be treated like an inner join, only return results where they match a join row. If I don't specify a date, give me everything in the main table if a join exists or not.
DECLARE #DispoStartDt datetime, #DispoEndDt datetime, #DispoCode varchar(800)
SET #DispoStartDt = '5-1-2015'
--SET #DispoEndDt = '12-31-2014'
SET #DispoCode = '_NULL'
SELECT c.CaseID
, c.ProsNum AS FileNum
, c.CaseStatusDesc AS CaseStatus
, disp.DispoDts
FROM jw50_Case c
LEFT JOIN (SELECT CaseID, DispoDts
FROM (
SELECT c1.CaseID,
STUFF((SELECT '; ' + CONVERT(VARCHAR(10), ct.DispoDt, 101)
FROM jw50_CountInvPers ct
WHERE ct.CaseID = c1.CaseId
AND (ct.DispoDt >= DATEADD(dd, DATEDIFF(dd, 0, ISNULL(#DispoStartDt, ct.DispoDt)), 0) AND ct.DispoDt < DATEADD(dd, DATEDIFF(dd, -1, ISNULL(#DispoEndDt, ct.DispoDt)), 0))
ORDER BY DispoDesc
FOR XML PATH('')), 1, 1, '') [DispoDts]
FROM jw50_Case c1
WHERE c1.CaseID = c1.CaseId
GROUP BY c1.CaseID
) a
WHERE DispoDts IS NOT NULL
) disp ON disp.CaseID = c.CaseID
ORDER BY CaseID, DispoDts
EDIT 2:
Ok, feels dirty, but it works.
WHERE (#DispoStartDt IS NULL AND #DispoEndDt IS NULL)
OR (#DispoStartDt IS NOT NULL AND #DispoEndDt IS NOT NULL AND disp.DispoDts IS NOT NULL)
OR (#DispoStartDt IS NOT NULL AND #DispoEndDt IS NULL AND disp.DispoDts IS NOT NULL)
OR (#DispoStartDt IS NULL AND #DispoEndDt IS NOT NULL AND disp.DispoDts IS NOT NULL)
You can try:
DECLARE #DispoStartDt datetime, #DispoEndDt datetime, #DispoCode varchar(800)
SET #DispoStartDt = '5-1-2050'
--SET #DispoEndDt = '12-31-2014'
SET #DispoCode = '_NULL'
SELECT CaseID,
[DispoDts]
FROM (
SELECT c1.CaseID,
STUFF((SELECT '; ' + CONVERT(VARCHAR(10), ct.DispoDt, 101)
FROM jw50_CountInvPers ct
WHERE ct.CaseID = '00-100'
AND (ct.DispoDt >= DATEADD(dd, DATEDIFF(dd, 0, ISNULL(#DispoStartDt, ct.DispoDt)), 0) AND ct.DispoDt < DATEADD(dd, DATEDIFF(dd, -1, ISNULL(#DispoEndDt, ct.DispoDt)), 0))
ORDER BY DispoDesc
FOR XML PATH('')), 1, 1, '') [DispoDts]
FROM jw50_Case c1
WHERE c1.CaseID = '00-100'
GROUP BY c1.CaseID
) as tbaux
WHERE [DispoDts] IS NOT NULL
This way you get the same values ​​as before, but the result is passed to a query above which validates the DispoDts
And this way ?
DECLARE #DispoStartDt datetime, #DispoEndDt datetime, #DispoCode varchar(800)
SET #DispoStartDt = '5-1-2015'
--SET #DispoEndDt = '12-31-2014'
SET #DispoCode = '_NULL'
SELECT c.CaseID
, c.ProsNum AS FileNum
, c.CaseStatusDesc AS CaseStatus
, disp.DispoDts
FROM jw50_Case c
LEFT JOIN (SELECT c1.CaseID,
STUFF((SELECT '; ' + CONVERT(VARCHAR(10), ct.DispoDt, 101)
FROM jw50_CountInvPers ct
WHERE ct.CaseID = c1.CaseId
AND (ct.DispoDt >= DATEADD(dd, DATEDIFF(dd, 0, ISNULL(#DispoStartDt, ct.DispoDt)), 0) AND ct.DispoDt < DATEADD(dd, DATEDIFF(dd, -1, ISNULL(#DispoEndDt, ct.DispoDt)), 0))
ORDER BY DispoDesc
FOR XML PATH('')), 1, 1, '') [DispoDts]
FROM jw50_Case c1
WHERE c1.CaseID = c1.CaseId
GROUP BY c1.CaseID
) disp ON disp.CaseID = c.CaseID
WHERE #DispoEndDt IS NULL OR disp.DispoDts IS NOT NULL
ORDER BY CaseID, DispoDts

Return All Months & Years Between Date Range - SQL

I'm a bit stumped how I might go about this.
I have a very basic query, that currently returns sales for each product, by year and month.
It is grouping by year/month, and summing up the quantity.
This returns one row for each product/year/month combo where there was a sale.
If there was no sale for a month, then there is no data.
I'd like my query to return one row of data for each product for each year/month in my date range, regardless of whether there was actually an order.
If there was no order, then I can return 0 for that product/year/month.
Below is my example query.
Declare #DateFrom datetime, #DateTo Datetime
Set #DateFrom = '2012-01-01'
set #DateTo = '2013-12-31'
select
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) As YearMonth,
variant_detail.vad_variant_code,
sum(order_line_item.oli_qty_required) as 'TotalQty'
From
variant_Detail
join order_line_item on order_line_item.oli_vad_id = variant_detail.vad_id
join order_header on order_header.oh_id = order_line_item.oli_oh_id
Where
(order_header.oh_datetime between #DateFrom and #DateTo)
Group By
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110),
variant_detail.vad_variant_code
You can generate this by using CTE.
You will find information on this article :
http://blog.lysender.com/2010/11/sql-server-generating-date-range-with-cte/
Especially this piece of code :
WITH CTE AS
(
SELECT #start_date AS cte_start_date
UNION ALL
SELECT DATEADD(MONTH, 1, cte_start_date)
FROM CTE
WHERE DATEADD(MONTH, 1, cte_start_date) <= #end_date
)
SELECT *
FROM CTE
Thank your for your suggestions.
I managed to get this working using another method.
Declare #DateFrom datetime, #DateTo Datetime
Set #DateFrom = '2012-01-01'
set #DateTo = '2013-12-31'
select
YearMonthTbl.YearMonth,
orders.vad_variant_code,
orders.qty
From
(SELECT Convert(CHAR(4),DATEADD(MONTH, x.number, #DateFrom),120) + '/' + Convert(CHAR(2),DATEADD(MONTH, x.number, #DateFrom),110) As YearMonth
FROM master.dbo.spt_values x
WHERE x.type = 'P'
AND x.number <= DATEDIFF(MONTH, #DateFrom, #DateTo)) YearMonthTbl
left join
(select variant_Detail.vad_variant_code,
sum(order_line_item.oli_qty_required) as 'Qty',
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110) As 'YearMonth'
FROM order_line_item
join variant_detail on variant_detail.vad_id = order_line_item.oli_vad_id
join order_header on order_header.oh_id = order_line_item.oli_oh_id
Where
(order_header.oh_datetime between #DateFrom and #DateTo)
GROUP BY variant_Detail.vad_variant_code,
Convert(CHAR(4),order_header.oh_datetime,120) + '/' + Convert(CHAR(2),order_header.oh_datetime,110)
) as Orders on Orders.YearMonth = YearMonthTbl.YearMonth
This is what I put together. It will certainly need some debugging, but I think that this will lead you in the right direction. I broke up the queries into different parts in order to attempt to make it easier to read. Hope this helps.
DECLARE #dateFrom DATETIME, #dateTo DATETIME
SELECT #dateFrom = MIN(oh_datetime) FROM order_header
SELECT #dateTo = MAX(oh_datetime) FROM order_header
;WITH
y AS
(
SELECT YEAR(#dateFrom) AS [Year]
UNION ALL
SELECT [Year] + 1
FROM y
WHERE
[Year] < YEAR (GETDATE())
),
m AS
(
SELECT 1 AS [Month]
UNION ALL
SELECT [Month] + 1
FROM m
WHERE
[Month] < 12
),
dates AS
(
SELECT
CAST(y.[Year] AS nvarchar(4)) + N'/' + RIGHT(N'00' + CAST(m.[Month] AS nvarchar(2)), 2) AS YearMonth
FROM
y CROSS JOIN m
),
qty AS
(
SELECT
YEAR(oh.oh_datetime) + N'/' + MONTH(oh.oh_datetime) AS YearMonth,
v.vad_variant_code,
oli.oli_qty_required AS Qty
FROM
variant_Detail AS v
INNER JOIN order_line_item AS oli ON oil.oli_vad_id = v.vad_id
INNER JOIN order_header AS oh ON oh.oh_id = oli.oli_oh_id
)
SELECT
d.YearMonth,
qty.vad_variant_code,
SUM(qty.Qty) AS TotalQty
FROM
dates AS d LEFT OUTER JOIN qty
ON d.YearMonth = qty.YearMonth
GROUP BY
d.YearMonth,
qty.vad_variant_code
Here is another twist, if you find all months of a year
;WITH DateYear AS (
SELECT 0 AS num
UNION ALL
SELECT num + 1 FROM DateYear
WHERE num < 11
)
Select FirstDateOfTheMonth, DATENAME(mm,FirstDateOfTheMonth), num from
(SELECT CONVERT(DATE,DATEADD(MONTH,num,'2017')) AS FirstDateOfTheMonth, num from DateYear)
cte
and the result will be
Another twist:
Declare #dateFrom datetime ='2019-03-21', #dateTo datetime ='2019-12-31'
;WITH CTE AS
(
SELECT #dateFrom AS cte_start_date
UNION ALL
SELECT DATEADD(MONTH, 1, cte_start_date)
FROM CTE
WHERE ( DATEADD(MONTH, 1, cte_start_date) <= EOMONTH( #dateTo) )
--or ( DATENAME(MONTH, cte_start_date) =DATENAME(MONTH, #dateTo) and DATENAME(year, cte_start_date) =DATENAME(year, #dateTo) ) )
)
SELECT *
FROM CTE
This below is work for sqlserver 2012 and above to get the last day of the month :-
Select EOMONTH('2020-02-15')