I have two table like
ItemTable_One
id itemID Date qty
===================================================
1 1 2015-07-1 10
2 1 2015-07-3 20
3 2 2015-07-5 30
4 2 2015-07-7 40
ItemTable_Two
id itemID Date qty
===================================================
1 1 2015-07-2 50
2 1 2015-07-4 60
3 3 2015-07-6 70
4 3 2015-07-8 80
I want to retrieve data where itemID is equal to 1 in a date range.
For example ( date range between 2015-07-1 and 2015-07-30 )
itemID Date ItemTableOne_qty ItemTableTwo_qty
============================================================================
1 2015-07-1 10 0
1 2015-07-3 20 0
1 2015-07-2 0 50
1 2015-07-4 0 60
I've tried union join and subquery to do it, but I'm very weak in sql query.
You can use UNION ALL to get all the data you need:
SELECT ItemTable_One.itemID, ItemTable_One.Date, ItemTable_One.qty as ItemTableOne_qty, 0 as ItemTableTwo_qty
FROM ItemTable_One
WHERE ItemTable_One.itemID = 1 AND
ItemTable_One.Date BETWEEN '2015-07-01' AND '2015-08-01'
UNION ALL
SELECT ItemTable_Two.itemID, ItemTable_Two.Date, 0 as ItemTableOne_qty, ItemTable_Two.qty as ItemTableTwo_qty
FROM ItemTable_One
WHERE ItemTable_Two.itemID = 1 AND
ItemTable_Two.Date BETWEEN '2015-07-01' AND '2015-08-01'
You can use a FULL OUTER JOIN:
SELECT COALESCE(t1.itemID, t2.itemID) AS itemID,
COALESCE(t1.[Date], t2.[Date]) AS [Date],
COALESCE(t1.qty, 0) AS ItemTableOne_qty,
COALESCE(t2.qty, 0) AS ItemTableTwo_qty
FROM ItemTable_One AS t1
FULL OUTER JOIN ItemTable_Two AS t2 ON t1.itemID = t2.itemID AND t1.[Date] = t2.[Date]
WHERE COALESCE(t1.itemID, t2.itemID) = 1 AND
COALESCE(t1.[Date], t2.[Date]) BETWEEN '2015-07-01' AND '2015-07-31'
ORDER BY COALESCE(t1.[Date], t2.[Date])
This will put records having the same [Date] value in the source tables, into the same row of the output table.
If records of ItemTable_One always have separate [Date] values from records of ItemTable_Two, then the UNION solution proposed in other answers is preferable.
Demo here
Try this:
select itemID, Date, qty as ItemTableOne_qty, 0 as ItemTableTwo_qty
from ItemTable_One
where ItemID = 1
and date >= '20150701'
and date < '20150731'
union all
select itemID, Date, 0 as ItemTableOne_qty, qty as ItemTableTwo_qty
from ItemTable_Two
where ItemID = 1
and date >= '20150701'
and date < '20150731'
The upper limit for date is intentionally < than the wanted date +1 so that in case it's a datetime that has the time in it, the last day will be included too.
You do it with a FULL JOIN or a UNION ALL (depending on exact required output)
FULL JOIN
A FULL JOIN will allow you to get results like you show as long as there are no identical dates between the 2 tables. If such dates are present in both tables, you'd get a single row per date with both values filled.
The query to use is:
SELECT COALESCE(t1.itemID, t2.itemID) itemID, COALESCE(t1.Date, t2.Date) Date,
ISNULL(t1.qty, 0) ItemTableOne_qty, ISNULL(t2.qty, 0) ItemTableTwo_qty
FROM ItemTable_One t1 FULL JOIN ItemTable_Two t2
ON t1.itemID = t2.itemID AND t1.Date = t2.Date
WHERE COALESCE(t1.itemID, t2.itemID) = 1 AND
COALESCE(t1.Date, t2.Date) BETWEEN '2015-07-01' AND '2015-08-01'
UNION ALL
A UNION ALL will allow you to get resutls like you show and will create duplicate rows where the same date exists in both tables. There will always be at least 1 '0' value in any row.
The query to use is:
SELECT itemID, Date, qty ItemTableOne_qty, 0 ItemTableTwo_qty
FROM ItemTable_One
WHERE itemID = 1 AND Date BETWEEN '2015-07-01' AND '2015-08-01'
UNION ALL
SELECT itemID, Date, 0 ItemTableOne_qty, qty ItemTableTwo_qty
FROM ItemTable_Two
WHERE itemID = 1 AND Date BETWEEN '2015-07-01' AND '2015-08-01'
this will be the other way we can achieve the same result basing on your sample data
declare #ItemTable_One table (id int, itemID int, Date date, qty int)
insert into #ItemTable_One values
(1, 1, '2015-07-1', 10),
(2, 1, '2015-07-3', 20),
(3, 2, '2015-07-5', 30),
(4, 2, '2015-07-7', 40)
declare #ItemTable_Two table (id int, itemID int, Date date, qty int)
insert into #ItemTable_Two values
(1, 1, '2015-07-2', 50),
(2, 1, '2015-07-4', 60) ,
(3, 3, '2015-07-6', 70) ,
(4, 3, '2015-07-8', 80)
;with CTE AS (
select i.itemID As ItemID1,ii.itemID As ItemID2,i.Date As Dated1,ii.Date As Dated2,i.qty as qty,ii.qty As qty1 from #ItemTable_One i
CROSS APPLY (select * from #ItemTable_Two )ii
where i.id = ii.id AND i.itemID = ii.itemID
)
select * from (
Select ItemID1 As item,Dated1 AS Date, qty,'' as qty1 from CTE
UNION
Select ItemID2 As item,Dated2 AS Date,'' as qty,qty1 from CTE)T
--ORDER BY t.qty desc ,t.qty1
Use inline view to simplify horrid sql used in prior answers:
SELECT *
FROM (
SELECT COALESCE(t1.itemID, t2.itemID) AS itemID,
COALESCE(t1.[Date], t2.[Date]) AS [Date],
COALESCE(t1.qty, 0) AS ItemTableOne_qty,
COALESCE(t2.qty, 0) AS ItemTableTwo_qty
FROM ItemTable_One AS t1 FULL OUTER JOIN ItemTable_Two AS t2
ON t1.itemID = t2.itemID AND t1.[Date] = t2.[Date]
) AS v
WHERE v.itemID = 1 AND
v.[Date] BETWEEN '2015-07-01' AND '2015-07-31'
ORDER BY v.[Date]
Related
I have two tables, each of which holds the period of dates (from date1 to date2)
i will Find overlapping days between two periods of Date in table1 and table2
Example
table1
-------------------------
id | FromDate | ToDate
1 |2000-01-01 | 2000-02-04
2 |2000-03-01 | 2000-03-29
table2
-------------------------
id | FromDate | ToDate
1 |2000-02-01 | 2000-02-07
2 |2000-03-27 | 2000-03-29
The result I want to have:
2000-02-01
2000-02-02
2000-02-03
2000-02-04
2000-03-27
2000-03-28
2000-03-29
This should work:
CREATE TABLE #t1
(
id int,
FromDate date,
ToDate date
)
CREATE TABLE #t2
(
id int,
FromDate date,
ToDate date
)
INSERT #t1 VALUES
(1, '2000-01-01', '2000-02-04'),
(2, '2000-03-01', '2000-03-29')
INSERT #t2 VALUES
(1, '2000-02-01', '2000-02-07'),
(2, '2000-03-27', '2000-03-29')
WITH DateRange AS --select range where intersection is possible
(
SELECT MAX(MinDate) MinDate,MIN(MaxDate) MaxDate,DATEDIFF(DAY,MAX(MinDate),MIN(MaxDate)) Diff
FROM (VALUES ((SELECT MIN(FromDate) FROM #t1)),((SELECT MIN(FromDate) FROM #t2))) MinDate(MinDate)
CROSS APPLY (VALUES ((SELECT MAX(ToDate) FROM #t1)),((SELECT MAX(ToDate) FROM #t2))) MaxDate(MaxDate)
), AllDates AS --generate sequence of days
(
SELECT MinDate D, MaxDate Limit
FROM DateRange
UNION ALL
SELECT DATEADD(DAY, 1, D), Limit
FROM AllDates
WHERE DATEADD(DAY, 1, D)<=Limit
) --select all days existing in any range in both tables
SELECT D
FROM AllDates
WHERE EXISTS (SELECT * FROM #t1 WHERE D>=FromDate AND D<=ToDate)
AND EXISTS (SELECT * FROM #t2 WHERE D>=FromDate AND D<=ToDate)
It's possible to do this with CTE's and recursion.
--Your sample data
DECLARE #table1 TABLE (id int PRIMARY KEY, FromDate date, ToDate date)
DECLARE #table2 TABLE (id int PRIMARY KEY, FromDate date, ToDate date)
INSERT INTO #table1 VALUES (1, '2000-01-01', '2000-02-04') , (2, '2000-03-01', '2000-03-29')
INSERT INTO #table2 VALUES (1, '2000-02-01', '2000-02-07') , (2, '2000-03-27', '2000-03-29')
--A couple CTE's
;WITH cteDates AS (
SELECT T1.id --get the min and max dates for each id
,CASE WHEN T1.FromDate > T2.FromDate THEN T1.FromDate ELSE T2.FromDate END [mindate]
,CASE WHEN T1.ToDate < T2.ToDate THEN T1.ToDate ELSE T2.ToDate END [maxdate]
FROM #table1 T1 INNER JOIN #table2 T2 ON T1.id = T2.id
)
, cteRecursion AS ( --date range for each id
SELECT id, mindate AS DateValue
FROM cteDates
UNION ALL
SELECT id, DATEADD(DAY, 1, DateValue)
FROM cteRecursion C1
WHERE DATEADD(DAY, 1, DateValue) <= (
SELECT maxDate
FROM cteDates C2
WHERE C2.id = C1.id
)
)
--SELECT query
SELECT DateValue FROM cteRecursion ORDER BY DateValue OPTION (MAXRECURSION 0)
Produces Output:
DateValue
---------
2000-02-01
2000-02-02
2000-02-03
2000-02-04
2000-03-27
2000-03-28
2000-03-29
One possible solution is the with the use of a Numbers or Tally table
;WITH cteNumbers (N)
AS(
SELECT ROW_NUMBER() OVER(ORDER BY N1.N)
FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N1(N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N2 (N)
CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N3 (N)
)
SELECT T1.FromDate
FROM(
SELECT
T1.FromDate
FROM dbo.Table1 T1
UNION
SELECT
DATEADD(DAY, N, T1.FromDate)
FROM
dbo.Table1 T1
CROSS APPLY cteNumbers N
WHERE N <= DATEDIFF(DAY, T1.FromDate, T1.ToDate)
) T1
WHERE t1.FromDate IN
(
SELECT
T2.FromDate
FROM dbo.Table2 T2
UNION
SELECT
DATEADD(DAY, N, T2.FromDate)
FROM
dbo.Table2 T2
CROSS APPLY cteNumbers N
WHERE N <= DATEDIFF(DAY, T2.FromDate, T2.ToDate)
)
Result is
FromDate
2000-02-01 00:00:00.000
2000-02-02 00:00:00.000
2000-02-03 00:00:00.000
2000-02-04 00:00:00.000
2000-03-27 00:00:00.000
2000-03-28 00:00:00.000
2000-03-29 00:00:00.000
The Numbers/tally table will allow for a daterange of up to 1000 days. If you need more then add another line like so, CROSS JOIN (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N4 (N)
SQL Server 2012-2017. Can this be done with a CTE? Trying to avoid using a cursor.
I have a report request to return the inventory for the first of each month between dateFrom and dateTo, excluding the inventory on the dateFrom and dateTo.
Inventory is tracked by status history for each item. Each status history is coded as either in-inventory or out-of-inventory.
There could be many status history entries with an in-inventory status to track process steps. There will be another status history entry when the item is shipped, broken, lost, etc, and those are coded as out-of-inventory.
For reporting, an item is in inventory if the most recent status in status history before the reporting date is one that we code as in-inventory.
DECLARE #dateFrom dateTime, #dateTo dateTime
SET #dateFrom = '2-Nov-2017'
SET #dateTo = '20-Feb-2018 23:59:59.9'
--this proves out the dates are calculating correctly
;WITH cteDateTest AS
(
SELECT
1 roundCount,
DATEADD(M, DATEDIFF(M, 0, #dateFrom), 31) invDate --returns first of the month following dateFrom
UNION ALL
SELECT
roundCount + 1,
DATEADD(M, 1, invDate) --this one would go into the row_number join
FROM
cteDateTest
WHERE
DATEADD(M, 1, invDate) < #DateTo
)
SELECT * FROM cteDateTest
I've simplified the tables, using temp tables to be explicit that these are NOT the issue but created for ease in others understanding the problem.
CREATE TABLE #tempItems
(
id INT PRIMARY KEY,
itemDesc NVARCHAR (15) NULL,
isActive BIT
)
INSERT INTO #tempItems (id, itemDesc, isActive)
SELECT 1, 'widget 1',1 UNION ALL
SELECT 2, 'toy 2',1 UNION ALL
SELECT 3, 'something 3',1 UNION ALL
SELECT 4, 'prize 4',1
CREATE TABLE #tempStatusHistory
(
historyID INT PRIMARY KEY,
itemId INT,
itemStatus NVARCHAR (25) NULL,
statusDate DATETIME,
statusIsInInventory BIT,
)
INSERT INTO #tempStatusHistory (historyID, itemId, itemStatus, statusDate, statusIsInInventory)
SELECT 1, 1, 'in receiving', '2017-10-10',1 UNION ALL
SELECT 2, 1, 'in test', '2017-10-11',1 UNION ALL
SELECT 3, 1, 'on shelves', '2017-10-31',1 UNION ALL
SELECT 4, 2, 'in receiving', '2017-11-15',1 UNION ALL
SELECT 5, 2, 'in test', '2017-11-16',1 UNION ALL
SELECT 6, 2, 'on shelves', '2017-12-17',1 UNION ALL
SELECT 7, 2, 'sold', '2017-12-24',0 UNION ALL
SELECT 8, 3, 'in test', '2017-11-18',1 UNION ALL
SELECT 9, 3, 'in repair', '2017-12-19',1 UNION
SELECT 10, 3, 'returned to vendor', '2018-02-03',0 UNION ALL
SELECT 11, 4, 'in receiving', '2018-01-20',1 UNION ALL
SELECT 12, 4, 'on shelves', '2018-01-21',1 UNION ALL
SELECT 13, 4, 'sold', '2018-03-20',0
--select * from #tempStatusHistory
/* Per above data:
widget 1 in inventory all these months. Toy 2 in Dec 1 inventory. something 3 in Dec1, Jan 1, Feb 1 inventory, prize 4 in Feb 1 and Mar 1 inventory
Dec 1 inventory = 3 (widget 1, toy 2, something 3)
Jan 1 inventory = 2 (widget 1, something 3)
Feb 1 inventory = 3 (widget 1, something 3, prize 4)
Mar 1 inventory = 2 (widget 1, prize 4)
*/
--Our normal way of getting inventory for #dateFrom
SELECT
SH.historyId historyId, I.itemDesc
FROM
#tempItems I
JOIN
(SELECT
ROW_NUMBER () OVER (PARTITION BY itemId ORDER BY statusDate DESC) AS [Index],
itemId, historyId, statusDate, statusIsInInventory
FROM
#tempStatusHistory
WHERE
statusDate < #dateFrom) SH ON I.id = SH.itemId AND SH.[Index] = 1
WHERE
SH.statusIsInInventory = 1
--trying to pull inventory for each month between #dateFrom and #dateTo (exclusive of the end dates)
--anchor part of cte
;WITH cteInv AS
(
SELECT
1 roundCount,
DATEADD(M, DATEDIFF(M, 0, #dateFrom), 31) invDate,
DATEADD(M, 1, #dateFrom) staticDate,
1 linkField,
SH.historyId historyId,
I.itemDesc
FROM
#tempItems I
JOIN
(SELECT
ROW_NUMBER () OVER (PARTITION BY itemId ORDER BY statusDate DESC) AS [Index],
itemId, historyId, statusDate, statusIsInInventory
FROM
#tempStatusHistory
WHERE
statusDate < DATEADD(M, DATEDIFF(M, 0, #dateFrom), 31)) SH ON I.id = SH.itemId AND SH.[Index] = 1
WHERE
SH.statusIsInInventory = 1
--recursive part
UNION ALL
SELECT
roundCount + 1
, DATEADD(M,1,invDate)
, DATEADD(M,1,#dateFrom) staticDate
, 1
, SH.historyId
, I.itemDesc
FROM #tempItems I
--invDate not happy below
JOIN (SELECT ROW_NUMBER () OVER (PARTITION BY itemId ORDER BY statusDate DESC) AS [Index], itemId, historyId, statusDate, statusIsInInventory
FROM #tempStatusHistory WHERE statusDate < DATEADD(M,1,invDate)) SH ON I.id = SH.itemId AND SH.[Index] = 1
JOIN cteInv C ON I.isActive = C.linkField
WHERE DATEADD(M,1,invDate)< #dateTo AND SH.statusIsInInventory = 1
)
SELECT * from cteInv order by roundCount, invDate, itemDesc
drop table #tempItems
drop table #tempStatusHistory
the reference to invDate in the status history link shows as an error "invalid column name invDate". I can't figure a way around this. I also suspect an issue because if I replace invDate with #dateFrom in the same spot, I had expected the same inventory result for each month calculation, but it started multiplying itself.
Is cte a good solution for this? Is there a better way?
Thanks for anyone helping me on my first post here.
Addition: Expected output would be:
roundCount invDate linkField historyId itemDesc
-----------------------------------------------------------
1 2017-12-01 1 8 something 3
1 2017-12-01 1 5 toy 2
1 2017-12-01 1 3 widget 1
2 2018-01-01 1 9 something 3
2 2018-01-01 1 5 toy 2
3 2018-02-01 1 12 prize 4
3 2018-02-01 1 9 something 3
3 2018-02-01 1 3 widget 1
You are actually very very closed. Just need one OUTER APPLY
-- this is your cteDateTest query
;WITH
cteDateTest AS
(
SELECT
1 roundCount
,DATEADD(M,DATEDIFF(M,0,#dateFrom),31) invDate --returns first of the month following dateFrom
UNION ALL
SELECT
roundCount + 1
,DATEADD(M,1,invDate) --this one would go into the row_number join
FROM cteDateTest
WHERE DATEADD(M,1,invDate)< #DateTo
)
SELECT *
from cteDateTest d
OUTER APPLY
(
-- this is your normal query of getting inventory for #dateFrom
SELECT SH.historyID
, I.itemDesc
FROM #tempItems I
INNER JOIN
(
SELECT ROW_NUMBER () OVER (PARTITION BY itemId ORDER BY statusDate DESC) AS [Index],
itemId, historyID, statusDate, statusIsInInventory
FROM #tempStatusHistory
WHERE statusDate < d.invDate -- change to invDate from cteDateTest
) SH ON I.id = SH.itemId
AND SH.[Index] = 1
WHERE SH.statusIsInInventory = 1
) h
I have a table that looks like this:-
tblMeterReadings
id meter date total
1 1 03/01/2014 100.1
1 1 04/01/2014 184.1
1 1 05/01/2014 134.1
1 1 06/01/2014 132.1
1 1 07/01/2014 126.1
1 1 08/01/2014 190.1
This is an 8 day "contiguous block" from '2014-01-03' to '2014-01-08'.
In the real table there are "contiguous blocks" of years in length.
I need to select the MOST RESCENT CONTINUOUS 365 DAY BLOCK (filtered by meter column). If 365 cannot be found, then it should select next largest continuous block.
When I say CONTINUOUS I mean there must be no days missing.
This is beyond me, so if someone can solve... I will be very impressed.
using distinct to not count days with 2 sets of data
declare #gapdays int = 2 -- replace this with 365 in your case
;with x as
(
select datediff(d, '2014-01-01', [date])-dense_rank()over(order by [date]) grp
,[date]
from #t
)
select top 1 max([date]) last_date, min([date]) first_date, count(distinct [date]) days_in_a_row
from x
group by grp
having count(distinct [date]) >= #gapdays
order by max([date]) desc
There you go:
declare #tblMeterReadings table (id int, meter int, [date] date, total money)
insert into #tblMeterReadings ( id, meter, date, total )
values
(1, 1, '03/01/2014', 100.1),
(1, 1, '04/01/2014', 184.1),
(1, 1, '05/01/2014', 134.1),
(1, 1, '06/01/2014', 132.1),
(1, 1, '07/01/2014', 126.1),
(1, 1, '08/01/2014', 190.1),
(1, 1, '10/01/2014', 200.1),
(1, 1, '12/01/2014', 202.1),
(1, 1, '13/01/2014', 204.1)
;with data as (
select i = datediff(day, '2014', [date]), *
from #tblMeterReadings l
)
, islands as (
select island = l.i - row_number() over (order by i), l.*
from data l
)
, spans as (
select l = min(i), r = max(i)
from islands i
group by island
)
select *
from spans s
left join data l on s.l = l.i
left join data r on s.r = r.i
Most recent continuous block not exceeding 365 days in length will be as follows:
select top 1 *
from spans s
left join data l on s.l = l.i
left join data r on s.r = r.i
where s.l - s.r < 365
order by s.l - s.r desc, s.r desc
With recursive CTE and datepart(dayofyear, date):
with cte as
(
select id, meter, date, datepart(dayofyear, date) as x, cast(1 as int) as level, t1.date as startDate from tblMeterReadings t1
where meter = 1
and not exists(select * from tblMeterReadings t2 where (datepart(dayofyear, t1.date) - 1) = datepart(dayofyear, t2.date))
union all
select t1.id, t1.meter, t1.date, datepart(dayofyear, t1.date) as x, t2.level + 1, t2.startDate from tblMeterReadings t1
inner join cte t2 ON (datepart(dayofyear, t1.date)) = (datepart(dayofyear, t2.date) + 1)
)
select TOP 365 * from cte
where cte.startDate = (select top 1 startdate
from cte
--where Level <= 365
order by Level desc, startDate desc)
order by Level desc
OPTION ( MAXRECURSION 365 )
SQL Fiddle example
I have been creating a date range, but in some cases a have a problem:
This is what I have: TABLE_1
date customer_id status total
---- ------------- -------- -------
20120201 1 a 10
20120202 1 a 20
20120203 1 b 20
20120204 1 b 20
20120205 1 a 20
20120206 1 a 20
20120201 2 d 30
20120202 2 e 40
After the execution of my procedure, I have this: TABLE_2
customer_id status start_date end_date
------------- -------- ----------- ---------
1 a 20120201 NULL
1 b 20120203 20120131
2 d 20120201 20120201
2 e 20120202 NULL
But this is what i want, a table with date ranges based on customer_id and status (end_date represents register with most recent date): TABLE_3
customer_id status start_date end_date
------------- -------- ----------- ---------
1 a 20120201 20120202
1 b 20120203 20120204
1 a 20120205 NULL
2 d 20120201 20120201
2 e 20120202 NULL
My store procedure look like this:
;WITH TEMP AS (
SELECT
Date
customer_id
status
FROM table_1
GROUP BY
date,
customer_id,
status
)
,TEMP2 AS (
SELECT
ID = ROW_NUMBER() OVER(PARTITION BY customer_id ORDER BY MAX(date) DESC),
start_date = MIN(date),
end_date = MAX(date),
[customer_id],
[status]
FROM TEMP
GROUP BY
[customer_id],
[status]
)
SELECT
A.customer_id,
A.status,
A.start_date,
end_date = DATEADD(DAY,-1,B.start_date)
FROM TEMP2 A
LEFT JOIN TEMP2 B
ON A.customer_id = B.customer_id
AND A.ID = B.ID + 1
I know my error is in the creation of CTE TEMP2, because this code can´t discriminate for a customer_id with a status with two occurrences in different ranges of time, based on the 'group by' sentence
I can´t figure out how to do that...
Try this. Hope it works now.
DECLARE #table_1 TABLE (
date DATETIME,
customer_id INT,
status CHAR(1),
total INT
)
INSERT #table_1 (date, customer_id, status, total)
VALUES
('20120201', 1, 'a', 10),
('20120202', 1, 'a', 20),
('20120203', 1, 'b', 20),
('20120204', 1, 'b', 20),
('20120205', 1, 'a', 20),
('20120206', 1, 'a', 20),
('20120201', 2, 'd', 30),
('20120202', 2, 'e', 40)
;WITH CTE_1 AS (
SELECT
customer_id,
status,
date,
ROW_NUMBER() OVER(PARTITION BY customer_id ORDER BY date ASC) AS seq
FROM #table_1
),
CTE_2 AS (
SELECT
customer_id,
status,
date,
seq,
1 AS flg,
1 AS seq2
FROM CTE_1
WHERE
seq = 1
UNION ALL
SELECT
CTE_1.customer_id,
CTE_1.status,
CTE_1.date,
CTE_1.seq,
CASE WHEN CTE_2.status = CTE_1.status THEN 0 ELSE 1 END,
CASE WHEN CTE_2.status = CTE_1.status THEN CTE_2.seq2 ELSE CTE_2.seq2 + 1 END
FROM CTE_1
INNER JOIN CTE_2
ON CTE_1.customer_id = CTE_2.customer_id
AND CTE_1.seq = CTE_2.seq + 1
)
SELECT
st.customer_id,
st.status,
st.date AS start_date,
DATEADD(DAY, -1, en.date) AS end_date
FROM CTE_2 AS st
LEFT JOIN CTE_2 AS en
ON st.customer_id = en.customer_id
AND st.seq2 = en.seq2 - 1
AND en.flg = 1
WHERE
st.flg = 1
ORDER BY
st.customer_id,
st.seq2
Is it possible to write single query for following scenario?
Scenario -
Table -
column name - id date isPaid
values - 1 1/1/2011 1
2 1/2/2011 1
3 1/3/2011 0
4 1/4/2011 0
5 1/5/2011 0
I want a result set which contains (all ispaid = 1) and (only 1 row of ispaid = 0 whose date is smaller).
Result set:
column name - id date isPaid
values - 1 1/1/2011 1
2 1/2/2011 1
3 1/3/2011 0
Thanks
You can use UNIONdocs
SELECT
[id],
[date],
[isPaid]
FROM
[tablename]
WHERE
[ispaid] = 1
UNION ALL
SELECT TOP 1
[id],
[date],
[isPaid]
FROM
[tablename]
WHERE
[ispaid] = 0
ORDER BY
[date] ASC
This should do what you need in SQL Server 2005 and higher.
select
[id],
[date],
isPaid
from (
select
[id],
[date],
isPaid,
ROW_NUMBER() over (partition by ispaid order by date) as row
from table_name t ) a
where ispaid = 1
or row = 1
order by [date]
Assuming date will be provided to the query by user, for which data is to be retrieved
select t.*
from table t,
(select Top 1 id, date, ispaid
from table
where ispaid = 0 and date<?) np
where (t.ispaid=1 and t.date = ? ) OR (t.id = np.id)