Sql query to get unique date based on month - sql

I am working on pulling some data from a table.
declare #SampleData as Table(Id int, ContactId int, Item varchar(25),CreatedOn date)
insert into #SampleData
VALUES(100,2500,'Some item name 1212', '9/5/2020'),
(104,2500,'Some item name 2232', '9/15/2020'),
(109,2500,'Some item name 3434', '9/20/2020'),
(112,3000,'Some item name 5422', '8/1/2020'),
(132,3000,'Some item name 344', '9/5/2020'),
(134,3000,'Some item name 454', '9/15/2020'),
(139,3500,'Some item name 6455', '7/5/2020'),
(146,3500,'Some item name 546', '8/5/2020'),
(142,3500,'Some item name 867', '9/5/2020'),
(149,3500,'Some item name 677', '9/15/2020'),
(150,3500,'Some item name 888', '9/19/2020')
The logic here is so that you can find new contact id each month (so logic is if same contact dont have any record in last 28 days from 1st of that month, it consider as new contact)
When you have two date periods, this is easy to do so you can exclude the records you want as below
SELECT *
FROM #SampleData
WHERE CreatedOn> = #FromDate
and CreatedOn <=#Date
and ContactId not in (SELECT ContactId
FROM #SampleData
WHERE CreatedOn >= DateAdd(Day, -28,#FromDate)
AND CreatedOn < #FromDate)
What I want is to pre-populate this data without having parameters to a some table so that user can use.
In this example data, I am expecting contact 3500 for July, 3000 for August and 2500&3000 for September.
Also it need to display only record per contact and not duplicate.
DECLARE #From date,
#To date
DECLARE date_cursor CURSOR FOR
select distinct DATEADD(month, DATEDIFF(month, 0, CreatedOn), 0) FromDate,EOMONTH(CreatedOn) ToDate
from #SampleData
OPEN date_cursor
FETCH NEXT FROM date_cursor INTO #From,#To
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT *
FROM (
SELECT DISTINCT ContactId,#From 'From Date', #To 'To Date'
FROM #SampleData D
WHERE D.CreatedOn>= #From AND D.CreatedOn <= #To
AND ContactId NOT IN (SELECT ContactId
FROM #SampleData
WHERE CreatedOn >= DateAdd(Day, -28,#From)
AND CreatedOn < #From)) ContactData
OUTER APPLY (
--pick first row for the contact as per the period
SELECT TOP 1 *
FROM #SampleData D
WHERE D.ContactId = ContactData.ContactId
AND D.CreatedOn >= ContactData.[From Date]
AND D.CreatedOn < ContactData.[To Date]
ORDER BY CreatedOn
) Records
FETCH NEXT FROM date_cursor INTO #From,#To
END
CLOSE date_cursor
DEALLOCATE date_cursor
Result
ContactId From Date To Date Id Item CreatedOn
3500 01/07/2020 31/07/2020 139 Some item name 6455 05/07/2020
3000 01/08/2020 31/08/2020 112 Some item name 5422 01/08/2020
2500 01/09/2020 30/09/2020 100 Some item name 1212 05/09/2020
3000 01/09/2020 30/09/2020 132 Some item name 344 05/09/2020
I would like to get rid of cursor, is there any possibility

You can assign a grouping to the contacts by using lag() and comparing the rows:
select sd.*,
sum(case when prev_createdon > dateadd(day, -28, createdon) then 0 else 1 end) over
(partition by contactid order by createdon) as grouping
from (select sd.*,
lag(createdon) over (partition by contactid order by createdon) as prev_createdon
from SampleData sd
) sd;
If you just want the first row in a series of adjacent records, then:
select sd.*
from (select sd.*,
lag(createdon) over (partition by contactid order by createdon) as prev_createdon
from SampleData sd
) sd
where prev_createdon < dateadd(day, -28, createdon) or prev_createdon is null;
Here is a db<>fiddle.
EDIT:
Based on the revised question, you want to summarize by group. You an do this using:
select contactid, min(createdon), max(createdon), min(id),
max(case when seqnum = 1 then item end) as item
from (select sd.*,
row_number() over (partition by contactid, grouping order by createdon) as seqnum
from (select sd.*,
sum(case when prev_createdon > dateadd(day, -28, createdon) then 0 else 1 end) over
(partition by contactid order by createdon) as grouping
from (select sd.*,
lag(createdon) over (partition by contactid order by createdon) as prev_createdon
from SampleData sd
) sd
) sd
) sd
group by contactid, grouping;
I updated the DB fiddle to have this as well.

Related

Need to calc start and end date from single effective date

I am trying to write SQL to calculate the start and end date from a single date called effective date for each item. Below is a idea of how my data looks. There are times when the last effective date for an item will be in the past so I want the end date for that to be a year from today. The other two items in the table example have effective dates in the future so no need to create and end date of a year from today.
I have tried a few ways but always run into bad data. Below is an example of my query and the bad results
select distinct tb1.itemid,tb1.EffectiveDate as startdate
, case
when dateadd(d,-1,tb2.EffectiveDate) < getdate()
or tb2.EffectiveDate is null
then getdate() +365
else dateadd(d,-1,tb2.EffectiveDate)
end as enddate
from #test tb1
left join #test as tb2 on (tb2.EffectiveDate > tb1.EffectiveDate
or tb2.effectivedate is null) and tb2.itemid = tb1.itemid
left join #test tb3 on (tb1.EffectiveDate < tb3.EffectiveDate
andtb3.EffectiveDate <tb2.EffectiveDate or tb2.effectivedate is null)
and tb1.itemid = tb3.itemid
left join #test tb4 on tb1.effectivedate = tb4.effectivedate \
and tb1.itemid = tb4.itemid
where tb1.itemID in (62741,62740, 65350)
Results - there is an extra line for 62740
Bad Results
I expect to see below since the first two items have a future end date no need to create an end date of today + 365 but the last one only has one effective date so we have to calculate the end date.
I think I've read your question correctly. If you could provide your expected output it would help a lot.
Test Data
CREATE TABLE #TestData (itemID int, EffectiveDate date)
INSERT INTO #TestData (itemID, EffectiveDate)
VALUES
(62741,'2016-06-25')
,(62741,'2016-06-04')
,(62740,'2016-07-09')
,(62740,'2016-06-25')
,(62740,'2016-06-04')
,(65350,'2016-05-28')
Query
SELECT
a.itemID
,MIN(a.EffectiveDate) StartDate
,MAX(CASE WHEN b.MaxDate > GETDATE() THEN b.MaxDate ELSE CONVERT(date,DATEADD(yy,1,GETDATE())) END) EndDate
FROM #TestData a
JOIN (SELECT itemID, MAX(EffectiveDate) MaxDate FROM #TestData GROUP BY itemID) b
ON a.itemID = b.itemID
GROUP BY a.itemID
Result
itemID StartDate EndDate
62740 2016-06-04 2016-07-09
62741 2016-06-04 2016-06-25
65350 2016-05-28 2017-06-24
This should do it:
SELECT itemid
,effective_date AS "Start"
,(SELECT MIN(effective_date)
FROM effective_date_tbl
WHERE effective_date > edt.effective_date
AND itemid = edt.itemid) AS "End"
FROM effective_date_tbl edt
WHERE effective_date <
(SELECT MAX(effective_date) FROM effective_date_tbl WHERE itemid = edt.itemid)
UNION ALL
SELECT itemid
,effective_date AS "Start"
,(SYSDATE + 365) AS "End"
FROM effective_date_tbl edt
WHERE 1 = ( SELECT COUNT(*) FROM effective_date_table WHERE itemid = edt.itemid )
ORDER BY 1, 2, 3;
I did this exercise for Items that have multiple EffectiveDate in the table
you can create this view
CREATE view [VW_TESTDATA]
AS ( SELECT * FROM
(SELECT ROW_NUMBER() OVER (ORDER BY Item,CONVERT(datetime,EffectiveDate,110)) AS ID, Item, DATA
FROM MyTable ) AS Q
)
so use a select to compare the same Item
select * from [VW_TESTDATA] as A inner join [VW_TESTDATA] as B on A.Item = B.Item and A.id = B.id-1
in this way you always minor and major Date
I did not understand how to handle dates with only one Item , but it seems the simplest thing and can be added to this query with a UNION ALL, because the view not cover individual Item
You also need to figure out how to deal with Item with two equal EffectiveDate
you should use the case when statement..
[wrong query because a misunderstand of the requirements]
SELECT
ItemID AS Item,
StartDate,
CASE WHEN EndDate < Sysdate THEN Sysdate + 365 ELSE EndDate END AS EndDate
FROM
(
SELECT tabStartDate.ItemID, tabStartDate.EffectiveDate AS StartDate, tabEndDate.EffectiveDate AS EndDate
FROM TableItems tabStartDate
JOIN TableItems tabEndDate on tabStartDate.ItemID = tabEndDate.ItemID
) TableDatesPerItem
WHERE StartDate < EndDate
update after clarifications in the OP and some comments
I found a solution quite portable, because it doesn't make use of partioning but endorses on a sort of indexing rule that make to correspond the dates of each item with others with the same id, in order of time's succession.
The portability is obviously related to the "difficult" part of query, while row numbering mechanism and conversion go adapted, but I think that it isn't a problem.
I sended a version for MySql that it can try on SQL Fiddle..
Table
CREATE TABLE ITEMS
(`ItemID` int, `EffectiveDate` Date);
INSERT INTO ITEMS
(`ItemID`, `EffectiveDate`)
VALUES
(62741, DATE(20160625)),
(62741, DATE(20160604)),
(62740, DATE(20160709)),
(62740, DATE(20160625)),
(62740, DATE(20160604)),
(62750, DATE(20160528))
;
Query
SELECT
RESULT.ItemID AS ItemID,
DATE_FORMAT(RESULT.StartDate,'%m/%d/%Y') AS StartDate,
CASE WHEN RESULT.EndDate < CURRENT_DATE
THEN DATE_FORMAT((CURRENT_DATE + INTERVAL 365 DAY),'%m/%d/%Y')
ELSE DATE_FORMAT(RESULT.EndDate,'%m/%d/%Y')
END AS EndDate
FROM
(
SELECT
tabStartDate.ItemID AS ItemID,
tabStartDate.StartDate AS StartDate,
tabEndDate.EndDate
,tabStartDate.IDX,
tabEndDate.IDX AS IDX2
FROM
(
SELECT
tabStartDateIDX.ItemID AS ItemID,
tabStartDateIDX.EffectiveDate AS StartDate,
#rownum:=#rownum+1 AS IDX
FROM ITEMS AS tabStartDateIDX
ORDER BY tabStartDateIDX.ItemID, tabStartDateIDX.EffectiveDate
)AS tabStartDate
JOIN
(
SELECT
tabEndDateIDX.ItemID AS ItemID,
tabEndDateIDX.EffectiveDate AS EndDate,
#rownum:=#rownum+1 AS IDX
FROM ITEMS AS tabEndDateIDX
ORDER BY tabEndDateIDX.ItemID, tabEndDateIDX.EffectiveDate
)AS tabEndDate
ON tabStartDate.ItemID = tabEndDate.ItemID AND (tabEndDate.IDX - tabStartDate.IDX = ((select count(*) from ITEMS)+1) )
,(SELECT #rownum:=0) r
UNION
(
SELECT
tabStartDateSingleItem.ItemID AS ItemID,
tabStartDateSingleItem.EffectiveDate AS StartDate,
tabStartDateSingleItem.EffectiveDate AS EndDate
,0 AS IDX,0 AS IDX2
FROM ITEMS AS tabStartDateSingleItem
Group By tabStartDateSingleItem.ItemID
HAVING Count(tabStartDateSingleItem.ItemID) = 1
)
) AS RESULT
;

Joining sub-queries to get data for start and end provided dates optimization

I'm using SQL-Server 2008.
I have to select stock of items at provided start date and stock of items at provided end date from 2 warehouses.
This is how I'm selecting QuantityStock for #startDate:
DECLARE #startDate DATE = '20160111'
SELECT *
FROM (
SELECT SUM(QuantityStock) AS QuantityStockStart, Vendor, ItemNo, Company, [Date]
FROM WarehouseA wha
WHERE [Date] = (SELECT MAX([Date])
FROM WarehouseA wha2
WHERE wha.Vendor = wha2.Vendor
AND wha.ItemNo = wha2.ItemNo
AND wha.Company= wha2.Company
AND [Date] <= #startDate)
GROUP BY Vendor, ItemNo, Company, [Date]
UNION ALL
SELECT SUM(QuantityStock) AS QuantityStockStart, Vendor, ItemNo, Company, [Date]
FROM WarehouseB whb
WHERE [Date] = (SELECT MAX([Date])
FROM WarehouseB whb2
WHERE whb.Vendor = whb2.Vendor
AND whb.ItemNo = whb2.ItemNo
AND whb.Company= whb2.Company
AND [Date] <= #startDate)
GROUP BY Vendor, ItemNo, Company, [Date]
) stock_start
LEFT JOIN some_table st ON.....
As you see there are 2 similar queries, just selecting from different tables, for that I'm using UNION ALL
Also I'm using [DATE] <= #startDate that because not every day remaining stock is inserting, so for provided date '20160111' there can be no data, so need to select max date where remaining stock is inserted.
With query above a bit slowly, but working fine.
Problem is that I need to do the same with #endDate to get remaining stock for end date. Query is similar as above just instead of #startDate I need to use #endDate.
I've tried to use query above and LEFT JOIN similar query, just with #endDate instead of #startDate in following:
DECLARE #startDate DATE = '20160111',
#endDate DATE = '20165112'
SELECT stock_start.*, stock_end.QuantityStockEnd
FROM (
SELECT SUM(QuantityStock) AS QuantityStockStart, Vendor, ItemNo, Company, [Date]
FROM WarehouseA wha
WHERE [Date] = (SELECT MAX([Date])
FROM WarehouseA wha2
WHERE wha.Vendor = wha2.Vendor
AND wha.ItemNo = wha2.ItemNo
AND wha.Company= wha2.Company
AND [Date] <= #startDate)
GROUP BY Vendor, ItemNo, Company, [Date]
UNION ALL
SELECT SUM(QuantityStock) AS QuantityStock, Vendor, ItemNo, Company, [Date]
FROM WarehouseB whb
WHERE [Date] = (SELECT MAX([Date])
FROM WarehouseB whb2
WHERE whb.Vendor = whb2.Vendor
AND whb.ItemNo = whb2.ItemNo
AND whb.Company= whb2.Company
AND [Date] <= #startDate)
GROUP BY Vendor, ItemNo, Company, [Date]
) stock_start
LEFT JOIN (
SELECT SUM(QuantityStock) AS QuantityStockEnd, Vendor, ItemNo, Company, [Date]
FROM WarehouseA wha
WHERE [Date] = (SELECT MAX([Date])
FROM WarehouseA wha2
WHERE wha.Vendor = wha2.Vendor
AND wha.ItemNo = wha2.ItemNo
AND wha.Company= wha2.Company
AND [Date] <= #endDate)
GROUP BY Vendor, ItemNo, Company, [Date]
UNION ALL
SELECT SUM(QuantityStock) AS QuantityStockEnd, Vendor, ItemNo, Company, [Date]
FROM WarehouseB whb
WHERE [Date] = (SELECT MAX([Date])
FROM WarehouseB whb2
WHERE whb.Vendor = whb2.Vendor
AND whb.ItemNo = whb2.ItemNo
AND whb.Company= whb2.Company
AND [Date] <= #endDate)
GROUP BY Vendor, ItemNo, Company, [Date]
) stock_end ON stock_start.Vendor = stock_end.Vendor AND stock_start.ItemNo = stock_end.ItemNo AND stock_start.Company = stock_end.Company
LEFT JOIN some_table st ON.....
In this way I got desired results, but Its execution time so high (about 10x longer than first query only with #startDate). Have you ideas how could I optimize It? It looks like there should be any other, simpler way, without repeating code...
So final results should be:
QuantityStockStart | Vendor | ItemNo | Company | [Date] | QuantityStockEnd
I suggest use of the analytic function ROW_NUMBER() to locate the wanted source table rows. While there is no sample data to test against it is something of a guess but I think you may be able to do this:
SELECT
whab.Vendor
, whab.ItemNo
, whab.Company
, MIN(CASE WHEN whab.start_rn = 1 THEN whab.[Date] END) start_dt
, SUM(CASE WHEN whab.start_rn = 1 THEN whab.QuantityStock END) qty_at_start
, MAX(CASE WHEN whab.end_rn = 1 THEN whab.[Date] END) end_dt
, SUM(CASE WHEN whab.end_rn = 1 THEN whab.QuantityStock END) qty_at_end
FROM (
SELECT
Vendor
, ItemNo
, Company
, [Date]
, QuantityStock
, ROW_NUMBER() OVER (PARTITION BY Vendor, ItemNo, Company
ORDER BY CASE WHEN [Date] <= #startDate THEN 1 ELSE 2 END, [Date] DESC) AS start_rn
, ROW_NUMBER() OVER (PARTITION BY Vendor, ItemNo, Company
ORDER BY CASE WHEN [Date] <= #endDate THEN 1 ELSE 2 END, [Date] DESC) AS end_rn
FROM WarehouseA
UNION ALL
SELECT
Vendor
, ItemNo
, Company
, [Date]
, QuantityStock
, ROW_NUMBER() OVER (PARTITION BY Vendor, ItemNo, Company
ORDER BY CASE WHEN [Date] <= #startDate THEN 1 ELSE 2 END, [Date] DESC) AS start_rn
, ROW_NUMBER() OVER (PARTITION BY Vendor, ItemNo, Company
ORDER BY CASE WHEN [Date] <= #endDate THEN 1 ELSE 2 END, [Date] DESC) AS end_rn
FROM WarehouseB
) whab
WHERE whab.start_rn = 1
OR whab.end_rn = 1
GROUP BY
whab.Vendor
, whab.ItemNo
, whab.Company
Try removing the subquery that follows WHERE [Date]= but keeping the where conditions from that subquery. Change [Date] to MAX([Date]) and remove [Date] from the GROUP BY in the query that used to use the removed subquery.

Group continuous date ranges from same table SQL Server

I have following data:
CREATE TABLE #Rate
(
RateId Bigint
,PropertyId Bigint
,StartDate DATETIME
,EndDate DATETIME
)
INSERT INTO #Rate VALUES (100,1000,'2015-01-01','2010-01-11')
INSERT INTO #Rate VALUES (100,1000,'2015-01-12','2015-02-02')
INSERT INTO #Rate VALUES (100,1000,'2015-02-11','2015-02-25')
INSERT INTO #Rate VALUES (100,1002,'2015-01-01','2010-01-11')
INSERT INTO #Rate VALUES (100,1002,'2015-01-12','2015-02-02')
INSERT INTO #Rate VALUES (101,1000,'2015-02-11','2015-02-25')
INSERT INTO #Rate VALUES (101,1000,'2015-01-01','2010-01-11')
INSERT INTO #Rate VALUES (101,1000,'2015-01-12','2015-02-02')
And I need this result set
100 1000 '2015-01-01' '2015-02-02'
100 1000 '2015-02-11' '2015-02-25'
100 1002 '2015-01-01' '2015-02-02'
101 1002 '2015-01-01' '2015-02-02'
I need to group by RateId and propertyId and continuous date range for this. I have done this using cursor but I don't want cursor because we have lots of records.
If we can create view out of it that will be great :)
Thanks.
Changing all the 2010 with 2015 in your data the actual resultset you can expect is
RateId PropertyId StartDate EndDate
-------------------- -------------------- ---------- ----------
100 1000 2015-01-01 2015-02-02
100 1000 2015-02-11 2015-02-25
100 1002 2015-01-01 2015-02-02
101 1000 2015-01-01 2015-02-02
101 1000 2015-02-11 2015-02-25
this question is quite similar to find start and stop date for contiguous dates in multiple rows so I'll use my answer to that one as a template
WITH D AS (
SELECT RateId, PropertyId, StartDate, EndDate
, _Id = ROW_NUMBER() OVER (PARTITION BY RateId, PropertyId
ORDER BY StartDate, EndDate)
FROM #Rate
), N AS (
SELECT m.RateId, m.PropertyId, m.StartDate, m.EndDate
, LastStop = p.EndDate
FROM D m
LEFT JOIN D p ON m.RateID = p.RateId
AND m.PropertyId = p.PropertyId
AND m._Id = p._Id + 1
), B AS (
SELECT RateId, PropertyId, StartDate, EndDate, LastStop
, Block = SUM(CASE WHEN LastStop Is Null Then 1
WHEN LastStop + 1 < StartDate Then 1
ELSE 0
END)
OVER (PARTITION BY RateId, PropertyId ORDER BY StartDate, EndDate)
FROM N
)
SELECT RateId, PropertyId
, MIN(StartDate) StartDate
, MAX(EndDate) EndDate
FROM B
GROUP BY RateId, PropertyId, Block
ORDER BY RateId, PropertyId, Block;
D generates a row counter to avoid to use triangular join.
N get the previous EndDate in the same RateID, PropertyID group for every row.
B generate a sequence number for every block
The main query aggregates the data in B to get the wanted resultset.
Assuming you are using SQL Server 2012+, you can take the following approach:
Find all the records that do not overlap with the prev record. These begin a range.
Count the number of such records before any given record. These assign a constant value to the range.
Use this as a grouping factor.
The query looks like:
select rateid, propertyid, min(startdate) as startdate, max(enddate) as enddate
from (select r.*,
sum(case when preved < startdate then 1 else 0 end) over (partition by rateid, propertyid order by startdate) as grp
from (select r.*,
lag(enddate) over (partition by rateid, propertyid order by enddate) as preved
from #Rate r
) r
) r
group by rateid, propertyid, grp;
EDIT:
In SQL Server 2008, you can do something similar:
with r as (
select r.*,
(case when exists (select 1
from #rate r2
where r2.rateid = r.rateid and r2.propertyid = r.propertyid and
(r2.startdate <= dateadd(1 day, r.enddate) and
r2.enddate >= r.startdate)
) then 0 else 1 end) as isstart
from #Rate r join
#Rate r2
)
select rateid, propertyid, min(startdate) as startdate, max(enddate) as enddate
from (select r.*,
(select sum(isstart)
from r r2
where r2.rateid = r.rateid and r2.propertyid = r.propertyid
r2.startdate <= r.startdate) as grp
from r
) r
group by rateid, propertyid, grp;

SQL query to return data corresponding to all values of a column except for the min value of that column

I have a table with the following columns:
userid, datetime, type
Sample data:
userid datetime type
1 2013-08-01 08:10:00 I
1 2013-08-01 08:12:00 I
1 2013-08-01 08:12:56 I
I need to fetch data for only two rows other than the row with min(datetime)
my query to fetch data for min(datetime) is :
SELECT
USERID, MIN(CHECKTIME) as ChkTime, CHECKTYPE, COUNT(*) AS CountRows
FROM
T1
WHERE
MONTH(CONVERT(DATETIME, CHECKTIME)) = MONTH(DATEADD(MONTH, -1,
CONVERT(DATE, GETDATE())))
AND YEAR(CONVERT(DATETIME, CHECKTIME)) = YEAR(GETDATE()) AND USERID=35
AND CHECKTYPE='I'
GROUP BY
CONVERT(DATE, CHECKTIME), USERID, CHECKTYPE
HAVING
COUNT(*) > 1
a lil help'll be much appreciated..thnx
Maybe something like this will help you:
WITH CTE AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY userid ORDER BY checktime) RN
FROM dbo.T1
WHERE CHECKTYPE = 'I'
--add your conditions here
)
SELECT * FROM CTE
WHERE RN > 1
Using CTE and ROW_NUMBER() function this will select all rows except min(date) for each user.
SQLFiddle DEMO
SELECT * FROM YOURTABLE A
INNER JOIN
(SELECT USERID,TYPE,MIN(datetime) datetime FROM YOURTABLE GROUP BY USERID,TYPE )B
ON
A.USERID=B.USERID AND
A.TYPE=B.TYPE
WHERE A.DATETIME<>B.DATETIME

Running totals with initial value then adding the totals as stated by the date

Imagine we have a table:
SELECT SUM(A) AS TOTALS,DATE,STUFF FROM TABLE WHERE DATE BETWEEN 'DATESTART' AND 'DATEEND'
GROUP BY DATE,STUFF
Normally this gets the totals as:
totals stuff date
23 x 01.01.1900
3 x 02.01.1900
44 x 06.01.1900
But what if we have the previous the data before the startdate,and i want to add those initial data to my startdate value; for example; from the begining of time i already have a sum value of x lets say 100
so i want my table to start from 123 and add the previous data such as:
123
126
126+44 and so on...
totals stuff date
123 x 01.01.1900
126 x 02.01.1900
170 x 06.01.1900
How can i achieve that?
Source data:
WITH Stocks
AS (
SELECT
Dep.Dept_No ,
SUM(DSL.Metre) AS Metre ,
CONVERT(VARCHAR(10), Date, 112) AS Date
FROM
DS (NOLOCK) DSL
JOIN TBL_Depts (NOLOCK) Dep ON Dep.Dept_No = DSL.Dept
WHERE
1 = 1 AND
DSL.Sil = 0 AND
DSL.Depo IN ( 5000, 5001, 5002, 5003, 5004, 5014, 5018, 5021, 5101, 5109, 5303 ) AND
Dep.Dept_No NOT IN ( 6002 ) AND
Dep.Dept_No IN ( 6000, 6001, 6003, 6004, 6005, 6011, 6024, 6030 ) AND
DSL.Date BETWEEN '2013-06-19' AND '2013-06-20'
GROUP BY
Dep.Dept_No ,
CONVERT(VARCHAR(10), Date, 112)
)
SELECT
Stocks.Metre ,
Dep.Dept AS Dept ,
Stocks.Date
FROM
Stocks
LEFT JOIN TBL_Depts (NOLOCK) Dep ON Stocks.Dept = Dep.Dept
ORDER BY
Stocks.Metre DESC
Any RDBMS with window and analytic functions (SQL Server 2012, PostgreSQL but not MySQL)
SELECT
SumA + SUM(SumARange) OVER (ORDER BY aDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS TOTALS,
other, aDate
FROM
(
SELECT
SUM(a) AS SumARange,
other, aDate
FROM
SomeTable
WHERE
aDate BETWEEN '20130101' AND '20130106'
GROUP BY
other, aDate
) X
CROSS JOIN
(
SELECT
SUM(a) AS SumA
FROM
SomeTable
WHERE
aDate < '20130101'
) Y
ORDER BY
aDate;
or
SELECT
SUM(SumA) OVER () + SUM(SumARange) OVER (ORDER BY aDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS TOTALS,
other, aDate
FROM
(
SELECT
SUM(CASE WHEN aDate < '20130101' THEN a ELSE 0 END) AS SumA,
SUM(CASE WHEN aDate BETWEEN '20130101' AND '20130106' THEN a ELSE 0 END) AS SumARange,
other, aDate
FROM
SomeTable
WHERE
aDate <= '20130106'
GROUP BY
other, aDate
) X
ORDER BY
aDate;
SQLFiddle example and another
Use option with APPLY operator to calculate the totals. You need also add additional CASE expression in the GROUP BY clause
;WITH cte AS
(
SELECT SUM(a) AS sumA, [stuff], MAX([Date]) AS [Date]
FROM SomeTable
WHERE [Date] <= '20130106'
GROUP BY [stuff], CASE WHEN [Date] <= '20130101' THEN 1 ELSE [Date] END
)
SELECT o.total, [stuff], [Date]
FROM cte c CROSS APPLY (
SELECT SUM(c2.sumA) AS total
FROM cte c2
WHERE c.[Date] >= c2.[Date]
) o
See example on SQLFiddle