Iscala Sales Statistics/Month - sql

I am trying to get statistics on monthly sales in iScala ERP. iScala reporting system reports this values.
My Sql query returns
3 058 023 2017-01-01
2 237 651 2017-02-01
4 700 720 2017-03-01
2 268 501 2017-04-01
3 183 576 2017-05-01
3 238 173 2017-06-01
1 949 041 2017-07-01
3 077 111 2017-08-01
My Query, Selecting from invoices SL03 applying Order OR20 to subtract Freight Amount. After that i Union in SL29 Invoice Consolidation History using cross apply to subtract Freight and SaleTax.
BEGIN
SELECT
SUM(cast(replace(isnull(b,0),',','.') as decimal(10,0))) Total,
cast(cast(DATEADD(MONTH, DATEDIFF(MONTH, 0, d), 0) as date) as varchar(50)) date
FROM (
SELECT
SUM(SL03100-aa.f) b ,
cast(cast(DATEADD(MONTH, DATEDIFF(MONTH, 0, SL03004), 0) as date) as varchar(50)) d
FROM SL030100
CROSS apply (
SELECT top 1 OR20044 f
FROM OR200100
WHERE SL030100.SL03036 = OR200100.OR20001
) aa
WHERE SL03004 BETWEEN '2017-01-01' AND DATEADD(d, 1,getdate())
group by cast(cast(DATEADD(MONTH, DATEDIFF(MONTH, 0, SL03004), 0) as date) as varchar(50))
UNION
SELECT
SUM((SL29007-SL29009-ba.f)) b,
cast(cast(DATEADD(MONTH, DATEDIFF(MONTH, 0, SL29006), 0) as date) as varchar(50)) d
FROM SL290100
CROSS apply (
SELECT top 1 OR20044 f
FROM OR200100
WHERE SL290100.SL29028 = OR200100.OR20001
) ba
WHERE SL29006 BETWEEN '2017-01-01' AND DATEADD(d, 1,getdate())
group by cast(cast(DATEADD(MONTH, DATEDIFF(MONTH, 0, SL29006), 0) as date) as varchar(50))
) AS tbl
group by cast(cast(DATEADD(MONTH, DATEDIFF(MONTH, 0, d), 0) as date) as varchar(50))
order by cast(cast(DATEADD(MONTH, DATEDIFF(MONTH, 0, d), 0) as date) as varchar(50))
END
I don't know if this is the best way to do it or what fields are missing. I feel that the difference between the internal report and my SQL result is small but noticeable for the customer.
I hope you can point me in right direction or to some resources that can help.
Best regards
MK

Related

SQL how to count census points occurring between date records

I’m using MS-SQL-2008 R2 trying to write a script that calculates the Number of Hospital Beds occupied on any given day, at 2 census points: midnight, and 09:00.
I’m working from a data set of patient Ward Stays. Basically, each row in the table is a record of an individual patient's stay on a single ward, and records the date/time the patient is admitted onto the ward, and the date/time the patient leaves the ward.
A sample of this table is below:
Ward_Stay_Primary_Key | Ward_Start_Date_Time | Ward_End_Date_Time
1 | 2017-09-03 15:04:00.000 | 2017-09-27 16:55:00.000
2 | 2017-09-04 18:08:00.000 | 2017-09-06 18:00:00.000
3 | 2017-09-04 13:00:00.000 | 2017-09-04 22:00:00.000
4 | 2017-09-04 20:54:00.000 | 2017-09-08 14:30:00.000
5 | 2017-09-04 20:52:00.000 | 2017-09-13 11:50:00.000
6 | 2017-09-05 13:32:00.000 | 2017-09-11 14:49:00.000
7 | 2017-09-05 13:17:00.000 | 2017-09-12 21:00:00.000
8 | 2017-09-05 23:11:00.000 | 2017-09-06 17:38:00.000
9 | 2017-09-05 11:35:00.000 | 2017-09-14 16:12:00.000
10 | 2017-09-05 14:05:00.000 | 2017-09-11 16:30:00.000
The key thing to note here is that a patient’s Ward Stay can span any length of time, from a few hours to many days.
The following code enables me to calculate the number of beds at both census points for any given day, by specifying the date in the case statement:
SELECT
'05/09/2017' [Date]
,SUM(case when Ward_Start_Date_Time <= '05/09/2017 00:00:00.000' AND (Ward_End_Date_Time >= '05/09/2017 00:00:00.000' OR Ward_End_Date_Time IS NULL)then 1 else 0 end)[No. Beds Occupied at 00:00]
,SUM(case when Ward_Start_Date_Time <= '05/09/2017 09:00:00.000' AND (Ward_End_Date_Time >= '05/09/2017 09:00:00.000' OR Ward_End_Date_Time IS NULL)then 1 else 0 end)[No. Beds Occupied at 09:00]
FROM
WardStaysTable
And, based on the sample 10 records above, generates this output:
Date | No. Beds Occupied at 00:00 | No. Beds Occupied at 09:00
05/09/2017 | 4 | 4
To perform this for any number of days is obviously onerous, so what I’m looking to create is a query where I can specify a start/end date parameter (e.g. 1st-5th Sept), and for the query to then evaluate the Ward_Start_Date_Time and Ward_End_Date_Time variables for each record, and – grouping by the dates defined in the date parameter – count each time the 00:00:00.000 and 09:00:00.000 census points fall between these 2 variables, to give an output something along these lines (based on the above 10 records):
Date | No. Beds Occupied at 00:00 | No. Beds Occupied at 09:00
01/09/2017 | 0 | 0
02/09/2017 | 0 | 0
03/09/2017 | 0 | 0
04/09/2017 | 1 | 1
05/09/2017 | 4 | 4
I’ve approached this (perhaps naively) thinking that if I use a cte to create a table of dates (defined by the input parameters), along with associated midnight and 9am census date/time points, then I could use these variables to group and evaluate the dataset.
So, this code generates the grouping dates and census date/time points:
DECLARE
#StartDate DATE = '01/09/2017'
,#EndDate DATE = '05/09/2017'
,#0900 INT = 540
SELECT
DATEADD(DAY, nbr - 1, #StartDate) [Date]
,CONVERT(DATETIME,(DATEADD(DAY, nbr - 1, #StartDate))) [MidnightDate]
,DATEADD(mi, #0900,(CONVERT(DATETIME,(DATEADD(DAY, nbr - 1, #StartDate))))) [0900Date]
FROM
(
SELECT
ROW_NUMBER() OVER ( ORDER BY c.object_id ) AS nbr
FROM sys.columns c
) nbrs
WHERE nbr - 1 <= DATEDIFF(DAY, #StartDate, #EndDate)
The stumbling block I’ve hit is how to join the cte to the WardStays dataset, because there’s no appropriate key… I’ve tried a few iterations of using a subquery to make this work, but either I’m taking the wrong approach or I’m getting my syntax in a mess.
In simple terms, the logic I’m trying to create to get the output is something like:
SELECT
[Date]
,SUM (case when WST.Ward_Start_Date_Time <= [MidnightDate] AND (WST.Ward_End_Date_Time >= [MidnightDate] OR WST.Ward_End_Date_Time IS NULL then 1 else 0 end) [No. Beds Occupied at 00:00]
,SUM (case when WST.Ward_Start_Date_Time <= [0900Date] AND (WST.Ward_End_Date_Time >= [0900Date] OR WST.Ward_End_Date_Time IS NULL then 1 else 0 end) [No. Beds Occupied at 09:00]
FROM WardStaysTable WST
GROUP BY [Date]
Is the above somehow possible, or am I barking up the wrong tree and need to take a different approach altogether? Appreciate any advice.
I would expect something like this:
WITH dates as (
SELECT CAST(#StartDate as DATETIME) as dte
UNION ALL
SELECT DATEADD(DAY, 1, dte)
FROM dates
WHERE dte < #EndDate
)
SELECT dates.dte [Date],
SUM(CASE WHEN Ward_Start_Date_Time <= dte AND
Ward_END_Date_Time >= dte
THEN 1 ELSE 0
END) as num_beds_0000,
SUM(CASE WHEN Ward_Start_Date_Time <= dte + CAST('09:00' as DATETIME) AND
Ward_END_Date_Time >= dte + CAST('09:00' as DATETIME)
THEN 1 ELSE 0
END) as num_beds_0900
FROM dates LEFT JOIN
WardStaysTable wt
ON wt.Ward_Start_Date_Time <= DATEADD(day, 1, dates.dte) AND
wt.Ward_END_Date_Time >= dates.dte
GROUP BY dates.dte
ORDER BY dates.dte;
The cte is just creating the list of dates.
What a cool exercise. Here is what I came up with:
CREATE TABLE #tmp (ID int, StartDte datetime, EndDte datetime)
INSERT INTO #tmp values(1,'2017-09-03 15:04:00.000','2017-09-27 06:55:00.000')
INSERT INTO #tmp values(2,'2017-09-04 08:08:00.000','2017-09-06 18:00:00.000')
INSERT INTO #tmp values(3,'2017-09-04 13:00:00.000','2017-09-04 22:00:00.000')
INSERT INTO #tmp values(4,'2017-09-04 20:54:00.000','2017-09-08 14:30:00.000')
INSERT INTO #tmp values(5,'2017-09-04 20:52:00.000','2017-09-13 11:50:00.000')
INSERT INTO #tmp values(6,'2017-09-05 13:32:00.000','2017-09-11 14:49:00.000')
INSERT INTO #tmp values(7,'2017-09-05 13:17:00.000','2017-09-12 21:00:00.000')
INSERT INTO #tmp values(8,'2017-09-05 23:11:00.000','2017-09-06 07:38:00.000')
INSERT INTO #tmp values(9,'2017-09-05 11:35:00.000','2017-09-14 16:12:00.000')
INSERT INTO #tmp values(10,'2017-09-05 14:05:00.000','2017-09-11 16:30:00.000')
DECLARE
#StartDate DATE = '09/01/2017'
,#EndDate DATE = '10/01/2017'
, #nHours INT = 9
;WITH d(OrderDate) AS
(
SELECT DATEADD(DAY, n-1, #StartDate)
FROM (SELECT TOP (DATEDIFF(DAY, #StartDate, #EndDate) + 1)
ROW_NUMBER() OVER (ORDER BY [object_id]) FROM sys.all_objects) AS x(n)
)
, CTE AS(
select OrderDate, t2.*
from #tmp t2
cross apply(select orderdate from d ) d
where StartDte >= #StartDate and EndDte <= #EndDate)
select OrderDate,
SUM(CASE WHEN OrderDate >= StartDte and OrderDate <= EndDte THEN 1 ELSE 0 END) [No. Beds Occupied at 00:00],
SUM(CASE WHEN StartDTE <= DateAdd(hour,#nHours,CAST(OrderDate as datetime)) and DateAdd(hour,#nHours,CAST(OrderDate as datetime)) <= EndDte THEN 1 ELSE 0 END) [No. Beds Occupied at 09:00]
from CTE
GROUP BY OrderDate
This should allow you to check for any hour of the day using the #nHours parameter if you so choose. If you only want to see records that actually fall within your date range then you can filter the cross apply on start and end dates.

Function to count if X amount amount of days as a full month

We offer services for clients and each client has an Authorization for 90 days
I want to create a function which counts 15 days as full months.
For example, let’s say a client get Authorization on 10/17/2017. It’s means it’s less than 15 days for October so that Authorization will not count for October, but it has to count for November, December and January 2018.
;WITH CTE AS (
select
d.ClientId,
LOC
datediff(day, l.DecisionOn, d.duedate) 'Days',
l.DecisionOn,
d.duedate
from code d
join codeloc l on d.curdocversionid = l.docversionid
join codeaccess a on a.docversionid = d.curdocversionid
where codeid = 69999
and aoca in ('68','69','70','71','72','74')
),
T AS (
SELECT ClientId, LOC, COUNT(*) CNT FROM CTE
WHERE [Days] > 15
AND AuthorizedDecisionOn > DATEADD(MONTH, (CASE WHEN DAY(GETDATE()) > 15 THEN 1 ELSE 0 END) , CAST( GETDATE() as date))
AND duedate < DATEADD(MONTH,3 + (CASE WHEN DAY(GETDATE()) > 15 THEN 1 ELSE 0 END) , CAST( GETDATE() as date))
GROUP BY ClientId, LOC
)
Here's an inline table valued function (iTvf) that will give you what you need.
(note: I use iTvf's because they outperform scalar udfs)
CREATE FUNCTION dbo.monthsBetweenMinDay
(
#fromDate date,
#toDate date,
#minDays tinyint
)
RETURNS TABLE WITH SCHEMABINDING AS RETURN
SELECT Months = m.mb +
CASE WHEN DATEDIFF(day,d.fd,dateadd(month, -m.mb, d.td)) >= #minDays THEN 1 ELSE 0 END
FROM (VALUES (#fromDate, #toDate)) d(fd,td) -- from date and todate
CROSS APPLY (VALUES(
CASE WHEN d.fd > d.td THEN NULL
WHEN DATEPART(day, d.fd) > DATEPART(day, d.td) THEN DATEDIFF(month, d.fd, d.td)-1
ELSE DATEDIFF(month, d.fd, d.td) END)) m(mb);
Here's an example of the function in action:
-- sample data
CREATE TABLE #dates (date1 date, date2 date);
INSERT #dates
SELECT dt.dt, CAST(DATEADD(day, [days].d, DATEADD(month, months.m, dt.dt)) as date)
FROM (VALUES ('20170101')) dt(dt), (VALUES (4),(15),(25)) [days](d), (VALUES(0),(1),(4)) months(m);
-- solution
SELECT *
FROM #dates d
CROSS APPLY dbo.monthsBetweenMinDay(d.date1, d.date2, 15);
Results
date1 date2 Months
---------- ---------- -----------
2017-01-01 2017-01-05 0
2017-01-01 2017-01-16 1
2017-01-01 2017-01-26 1
2017-01-01 2017-02-05 1
2017-01-01 2017-02-16 2
2017-01-01 2017-02-26 2
2017-01-01 2017-05-05 4
2017-01-01 2017-05-16 5
2017-01-01 2017-05-26 5

SQL Query to Count number of values in a column Per Month

id date sales
1 01/01/2015 100
2 01/01/2015 100
3 02/01/2015 100
4 03/01/2015 100
What I need is to count the number of sales in a given date range (per month)which is based user input which are StartDate and EndDate. For Example the User inputs StartDate - 01/01/2015 and EndDate - 04/01/2015
the output would be like this
Month StartMonth EndMonth TotalSales
1 01/01/2015 01/31/2015 200
2 02/01/2015 02/28/2015 100
3 03/01/2015 03/31/2015 100
4 04/01/2015 04/30/2015 0
Started to something like this
set #Start_act = cast(DATEADD(month, DATEDIFF(month, 0, #StartDate), 0) as date)
set #End_act = cast(DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, #Enddate)+1, 0)) as date)
set #counter = DATEDIFF(month, #Start_act, #End_act)
if(#counter = 1)
begin
set #counter = #counter
end
else
set #counter = #counter + 1
end
set #count = 0
CREATE TABLE #TempTableID
(
Month int,
StartMonth date,
EndMonth date,
TotalSales
)
while (#count <= #counter)
begin
set #count = #count + 1;
if(#count = 1)
begin
set #Start = #Start_act
set #End = cast(DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, #Start_act)+1, 0)) as date)
set #plannedHorseCapacity = 123
end
else
begin
set #Start = cast(DATEADD(d, 1, #End)as date)
set #End = cast(DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, #Start)+1, 0)) as date)
set #plannedHorseCapacity = 456
end
Insert into #TempTableID
(
Month
StartMonth
EndMonth
TotalSales
)
Values
(
#count,
#Start,
#End,
#TotalSales
)
if(#count > #counter)
begin
break
end
else
begin
continue
end
end
Select * from #TempTableID
You can use below script -
WITH cte
AS
(SELECT
CONVERT(VARCHAR(20), MONTH([date]))
+ '-' + CONVERT(VARCHAR(20), YEAR([date])) monthyear
,([sales])
FROM [sales])
--add where condition for from and to date here
SELECT
monthyear
,SUM(sales) totalsales
FROM cte
GROUP BY monthyear
Output will be
monthyear totalsales
1-2015 400
2-2015 50
3-2015 150
Option 2 With Start and End Date
WITH cte
AS
(SELECT
FORMAT(MONTH([date]), '0#')
+ '-' + CONVERT(VARCHAR(20), YEAR([date])) monthyear
,([sales])
FROM [sales])
--add where condition for from and to date here
SELECT
monthyear
,cast (SUBSTRING(monthyear, 1, 2) as int) [Month]
,SUBSTRING(monthyear, 4, 4) [Year]
,(SELECT
DATEADD(MONTH, SUBSTRING(monthyear, 1, 2) - 1, DATEADD(YEAR, SUBSTRING(monthyear, 4, 4) - 1900, 0)))
StartDate
,(SELECT
DATEADD(DAY, -1, DATEADD(MONTH, CAST(SUBSTRING(monthyear, 1, 2) AS INT), DATEADD(YEAR, SUBSTRING(monthyear, 4, 4) - 1900, 0))))
EndDate
,SUM(sales) totalsales
FROM cte
GROUP BY monthyear
Output will be
monthyear Month Year StartDate EndDate totalsales
01-2015 1 2015 2015-01-01 00:00:00.000 2015-01-31 00:00:00.000 400
02-2015 2 2015 2015-02-01 00:00:00.000 2015-02-28 00:00:00.000 50
03-2015 3 2015 2015-03-01 00:00:00.000 2015-03-31 00:00:00.000 50
11-2015 11 2015 2015-11-01 00:00:00.000 2015-11-30 00:00:00.000 100
EDIT - Sorting
If you have multiple year data, then the dates will not come in sequence to fix that add order by [StartDate] in last.
output will be
monthyear Month Year StartDate EndDate totalsales
01-2015 1 2015 2015-01-01 00:00:00 2015-01-31 00:00:00.000 400
02-2015 2 2015 2015-02-01 00:00:00 2015-02-28 00:00:00.000 50
03-2015 3 2015 2015-03-01 00:00:00 2015-03-31 00:00:00.000 50
11-2015 11 2015 2015-11-01 00:00:00 2015-11-30 00:00:00.000 100
01-2016 1 2016 2016-01-01 00:00:00 2016-01-31 00:00:00.000 125
11-2016 11 2016 2016-11-01 00:00:00 2016-11-30 00:00:00.000 55
You can achieve it like this,
;WITH [CTE_DATE]
AS
(
SELECT MONTH(#fromdt) AS [Month]
,DATEADD(mm, DATEDIFF(mm, 0, #fromdt), 0) AS StartMonth
,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,#fromdt)+1,0)) AS EndMonth
UNION ALL
SELECT [Month] + 1 AS [Month]
,DATEADD(MONTH,1,StartMonth) AS StartMonth
,DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,DATEADD(MONTH,1,StartMonth))+1,0)) AS EndMonth
FROM [CTE_DATE] WHERE [Month] < MONTH(#todt)
)
SELECT *
,(SELECT SUM(sales) FROM yourtable where [date] between StartMonth and EndMonth) as TotalSales
FROM [CTE_DATE]
You can find end of month as below:
select [Month] = Month([date]), [date] as StartMonth,
EndMonth = convert(date, dateadd(month,datediff(month,0,'2017-02-11')+1,0)-1),
TotalSales from (
select [date], sum(sales) as totalSales
from #yoursales
group by [date]
) a
You could use a CTE like this
DECLARE #SampleData AS TABLE
(
id int,
[date] date,
sales int
)
INSERT INTO #SampleData
VALUES
( 1 , '2015-01-01', 100 ),
( 2 , '2015-01-01', 100 ),
( 3 , '2015-02-01', 100 ),
( 4 , '2015-03-01', 100 )
DECLARE #StartDate date = '2015-01-01'
DECLARE #EndDate date = '2015-08-01'
;WITH temp AS -- calendar table
(
SELECT dateadd(month, datediff(month,0,#StartDate),0) AS [StartMonthDate],
dateadd(day, -1 ,dateadd(month, datediff(month,0,#StartDate) + 1,0)) AS [EndMonthDate]
UNION ALL
SELECT dateadd(month, 1, t.[StartMonthDate]),
dateadd(day,-1,dateadd(month, 2, t.[StartMonthDate]))
FROM temp t
WHERE dateadd(month, 1, t.[StartMonthDate]) <= #EndDate
)
SELECT datepart(year,t.StartMonthDate) AS year,
datepart(month,t.StartMonthDate) AS month,
t.StartMonthDate,
t.EndMonthDate,
coalesce(ap.TotalSales,0) AS TotalSales
FROM temp t
CROSS APPLY
(
SELECT SUM(sales) AS TotalSales
FROM #SampleData sd
WHERE sd.[date] BETWEEN t.StartMonthDate AND t.EndMonthDate
) ap
OPTION (MAXRECURSION 0)
Demo link: http://rextester.com/LWUX67185
;With cte(id,date,sales)
AS
(
SELECT 1,'01/01/2015',100 UNION ALL
SELECT 2,'01/01/2015',100 UNION ALL
SELECT 3,'02/01/2015',100 UNION ALL
SELECT 4,'03/01/2015',100 UNION ALL
SELECT 5,'04/01/2015',NULL
)
SELECT [Id],CONVERT(VARCHAR(10),[DATE], 101) AS [DATE],
CONVERT(VARCHAR(10),[EndMonth],101) AS [EndMonth],
[SumOfSale] From
(
SELECT id,[DATE],EndMonth,SUM(sales) OVER(Partition by [DATE],EndMonth order by EndMonth) AS SumOfSale,
Row_NUmber ()OVER(Partition by [DATE],EndMonth order by id)As Seq From
(
SELECT id, CAST([DATE] AS DATE)[DATE], EOMONTH(date)AS EndMonth,ISNULL(sales,0)As Sales from cte
)Dt
)Final
WHERE Final.Seq=1
OutPut
Month StartMonth EndMonth TotalSales
1 01/01/2015 01/31/2015 200
2 02/01/2015 02/28/2015 100
3 03/01/2015 03/31/2015 100
4 04/01/2015 04/30/2015 0

DATEDIFF excluding summer months

We are running reports for a seasonal business, with expected lulls during the summer months. For some metrics, we'd essentially like to pretend that those months don't even exist.
Thus consider the default behavior of:
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-06-01') -- answer = 1
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-07-01') -- 2
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-08-01') -- 3
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-09-01') -- 4
We want to ignore June and July, so we would like those answers to look like this:
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-06-01') -- answer = 1
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-07-01') -- 1
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-08-01') -- 1
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-09-01') -- 2
What is the easiest way to accomplish this? I'd like a pure SQL solution, rather than something using TSQL, but writing a custom function such as NOSUMMER_DATEDIFF could also work.
Also, keep in mind the reports will span multiple years, so the solution should be able to handle that.
If you are only interested month differences, then I would suggest a trick here. Count the number of months since some date 0, but ignore the summer months. For example:
'2015-05-01' --> 2015 * 10 + 5 = 20155
'2015-06-01' --> 2015 * 10 + 6 = 20156
'2015-07-01' --> 2015 * 10 + 6 = 20156
'2015-08-01' --> 2015 * 10 + 6 = 20156
'2015-09-01' --> 2015 * 10 + 7 = 20157
This is a fairly easy calculation:
select (case when month(date2) <= 6 then year(date2) * 10 + month(date2)
when month(date2) in (7, 8) then year(date2) * 10 + 6
else year(date2) * 10 + (month(date2) - 2)
end)
For the difference:
select ((case when month(date2) <= 6 then year(date2) * 10 + month(date2)
when month(date2) in (7, 8) then year(date2) * 10 + 6
else year(date2) * 10 + (month(date2) - 2)
end) -
(case when month(date1) <= 6 then year(date1) * 10 + month(date1)
when month(date1) in (7, 8) then year(date1) * 10 + 6
else year(date1) * 10 + (month(date1) - 2)
end)
)
To able to achieve that, you have to "split" dates ranges to an "array" of dates for every single range of dates. CTE might be helpful in this case.
See:
--your table which holds dates ranges
DECLARE #dates TABLE(id INT IDENTITY(1,1), dFrom DATE, dTo DATE)
INSERT INTO #dates (dFrom, dTo)
VALUES('2015-05-01', '2015-06-01'),
('2015-05-01', '2015-07-01'),
('2015-05-01', '2015-08-01'),
('2015-05-01', '2015-09-01')
--summer month table
DECLARE #summermonths TABLE(summMonth INT)
INSERT INTO #summermonths(summMonth)
VALUES(6), (7)
--here Common Table Expressions is in action to "split" dates ranges to an array of dates for every single date range
;WITH CTE AS
(
SELECT id, DATEADD(MM, 0, dFrom) AS ndFrom, dTo, CASE WHEN MONTH(DATEADD(MM, 0, dFrom)) = 6 OR MONTH(DATEADD(MM, 0, dFrom)) = 7 THEN 0 ELSE 1 END AS COfMonth
FROM #dates
WHERE DATEADD(MM, 1, dFrom)<=dTo
UNION ALL
SELECT id, DATEADD(MM, 1, ndFrom) AS ndFrom, dTo, CASE WHEN MONTH(DATEADD(MM, 1, ndFrom)) = 6 OR MONTH(DATEADD(MM, 1, ndFrom)) = 7 THEN 0 ELSE 1 END AS COfMonth
FROM CTE
WHERE DATEADD(MM, 1, ndFrom)<=dTo
)
SELECT t1.id, t2.dFrom, t2.dTo, SUM(t1.COfMonth) AS MyDateDiff
FROM CTE AS t1 INNER JOIN #dates AS t2 ON t1.id = t2.id
GROUP BY t1.id, t2.dFrom , t2.dTo
Result:
id dFrom dTo MyDateDiff
1 2015-05-01 2015-06-01 1
2 2015-05-01 2015-07-01 1
3 2015-05-01 2015-08-01 2
4 2015-05-01 2015-09-01 3 --not 2, because of 5, 8, 9
Got it?
Note: a solution might be differ in case of dFrom and dTo is not the first date of month.

Draw a dynamic table in SQL

Good morning, I'm trying to draw a dynamic table with some data, this query, draw a table that has a day, his week, and some data that I want to calculate dynamically.
This is my query
use Alfri
;with monthDates
as
(
select DATEADD(month, 0, CONVERT(DATE,'2013-09-09',102)) as d
,DATEPART(week, DATEADD(month, datediff(month, 0, '2013-09-09'),0)) as w,
(
SELECT SUM(
CASE WHEN arrive_yard IS NOT NULL THEN
DATEDIFF(mi, Solicitado, Libre)-DATEDIFF(mi, arrive_yard, leave_yard)
ELSE
DATEDIFF(mi, Solicitado, Libre)
END
) as Tiempo
FROM MovimientoHoras
WHERE CONVERT(DATE, Solicitado, 102) = '2013-10-11'
) as info
union all
select DATEADD(day, 1, d)
,DATEPART(week, DATEADD(day, 1, d))
, info
from monthDates
where d < DATEADD(month, datediff(month, 0, '2013-10-09')+1,-1)
)
SELECT * FROM monthDates
This query draw me a table like this.
d |w |info |
2013-09-09 | 36 | 2780|
2013-09-10 | 37 | 2780|
2013-09-11 | 37 | 2780|
2013-09-12 | 37 | 2780|
2013-09-13 | 37 | 2780|
2013-09-14 | 37 | 2780|
2013-09-15 | 37 | 2780|
2013-09-16 | 37 | 2780|
But the info's column isn't calculling dynamically and this is my dilenma.
The point is that column d is calculated dynamically and that's the value that I want to use in info's column query, something like this WHERE CONVERT(DATE, Solicitado, 102) = d) as info instead of WHERE CONVERT(DATE, Solicitado, 102) = '2013-10-11') as info where D is the date changing in every row, the way that I'm trying it just giving me same data of '2013-10-11'
Something like a While to change a day in that subquery
Thanks
The basic approach is to separate the part that generates dates from the part that calculates the info for that date:
;with monthDates as (
select
cast('20130909' as date) as d,
datepart(week, dateadd(month, datediff(month, 0, '2013-09-09'), 0)) as w
union all
select
dateadd(day, 1, d),
datepart(week, dateadd(day, 1, d))
from
monthDates
where
d < dateadd(month, datediff(month, 0, '2013-10-09') + 1, -1)
)
select
m.d,
m.w,
sum(
datediff(mi, Solicitado, Libre)
- case when arrive_yard is not null then
datediff(mi, arrive_yard, leave_yard)
else 0 end
) info
from
monthDates m
left outer join
MovimientoHoras h
on cast(Solicitado as date) = m.d
group by
m.d,
m.w
Example SQLFiddle