Related
I'm new to SQL, trying to self teach, and struggling already with what seems to me should be a very simple query, or at least a very common one. I'm not even sure I know the lexicon to describe what I am trying to achieve, so apologies if the title of this thread turns out to be misleading! :)
I have a big database. I want to identify rows where 2 results in one column appear together, or another 2 results in the same column appear together over a set time period.
I started using AND but turned up zero results. I have spent the last 2-3 hours searching all over the net with limited success. There appear to be lots of similar threads that suggest UNION, SELECT DISTINCT, JOINs or other solutions but I have completely failed to adapt them for my needs.
Any pointers much appreciated.
So, my table is called VNH.dbo.ClinicalCaseItem
Data table looks like this:
ActualDateTime | CaseId | ProcedureTestId | Description | FeeAmount
I need to limit the ActualDateTime to greater than 2017-04-03 or the number of entries will run into the 100s of thousands. The ProcedureTestId is the key column. I need to, exclusively, identify those CaseId with ProcedureTestId 309 which occur together with ProcedureTestId 245, and those CaseId with ProcedureTestId 309 which occur together with ProcedureTestId 326.
I won't detail all the different queries I've tried as there have been half a dozen or so and none have come close to achieving the result I need, and most have failed completely.
Many thanks in advance
Example data:
ActualDateTime | CaseId | ProcedureTestId | Description | FeeAmount
2017-04-25 | 123456 | 309 | Place iv catheter | 30.00
2017-04-25 | 123456 | 329 | GA Patient | 100.00
2017-04-27 | 134523 | 309 | Place iv catheter | 30.00
2017-04-27 | 234567 | 245 | Sedate Patient | 45.00
2017-04-28 | 234567 | 309 | Place iv catheter | 30.00
2017-04-28 | 345321 | 245 | Sedate Patient | 45.00
2017-04-29 | 451324 | 309 | Place iv catheter | 30.00
2017-04-30 | 451324 | 309 | Place iv catheter | 30.00
2017-04-30 | 451324 | 375 | Surgical Pack | 28.00
2017-04-25 | 989898 | 309 | Place iv catheter | 30.00
2017-04-27 | 989898 | 245 | Sedate Patient | 45.00
2017-04-25 | 999999 | 309 | Place iv catheter | 30.00
2017-04-27 | 999999 | 245 | Sedate Patient | 45.00
2017-04-27 | 999999 | 326 | Bathe Patient | 45.00
2017-04-27 | 987654 | 375 | Surgical Pack | 28.00
2017-04-25 | 987654 | 309 | Place iv catheter | 30.00
2017-04-27 | 987654 | 245 | Sedate Patient | 45.00
2017-04-27 | 987654 | 329 | GA Patient | 100.00
2017-04-27 | 987654 | 326 | Bathe Patient | 45.00
The expected result of the query would be:
ActualDateTime | CaseId | ProcedureTestId | Description | FeeAmount | count_of
2017-04-25 | 123456 | 309 | Place iv catheter | 30.00 | 2
2017-04-25 | 123456 | 329 | GA Patient | 100.00 | 2
2017-04-27 | 234567 | 245 | Sedate Patient | 45.00 | 2
2017-04-28 | 234567 | 309 | Place iv catheter | 30.00 | 2
2017-04-25 | 989898 | 309 | Place iv catheter | 30.00 | 2
2017-04-27 | 989898 | 245 | Sedate Patient | 45.00 | 2
2017-04-25 | 999999 | 309 | Place iv catheter | 30.00 | 2
2017-04-27 | 999999 | 245 | Sedate Patient | 45.00 | 2
2017-04-25 | 987654 | 309 | Place iv catheter | 30.00 | 3
2017-04-27 | 987654 | 245 | Sedate Patient | 45.00 | 3
2017-04-27 | 987654 | 329 | GA Patient | 100.00 | 3
Having sample data is very helpful, but unless it is coupled to an "expected result" we cannot compare any query output to that; and hence we can only invent something that might work - which is what I present below.
My interpretation of your words is that you need caseid IF the case has proceeded through at least procedures (309 and 245) or (309 and 326). Now when I compare that requirement to the sample data I cannot find any rows that meet that criteria, so I added some that do. However also note that in the logic I have adopted any case that had procedures (245 and 326 but not 309) would also be returned.
The fundamental "trick" here (aka "method") is to use a case expression inside a SUM() function and evaluate this using a having clause (which permits filtering of results based on aggregated values).
This SQL Fiddle let's you perform your own trial queries.
MS SQL Server 2014 Schema Setup:
CREATE TABLE Table1
([ActualDateTime] datetime, [CaseId] int, [ProcedureTestId] int, [Description] varchar(17), [FeeAmount] int)
;
INSERT INTO Table1
([ActualDateTime], [CaseId], [ProcedureTestId], [Description], [FeeAmount])
VALUES
('2017-04-25 00:00:00', 989898, 309, 'Place iv catheter', 30.00),
('2017-04-27 00:00:00', 989898, 245, 'Sedate Patient', 45.00),
('2017-04-25 00:00:00', 999999, 309, 'Place iv catheter', 30.00),
('2017-04-27 00:00:00', 999999, 245, 'Sedate Patient', 45.00),
('2017-04-27 00:00:00', 999999, 326, 'whatever 326 is', 45.00),
('2017-04-25 00:00:00', 123456, 309, 'Place iv catheter', 30.00),
('2017-04-25 00:00:00', 123456, 329, 'GA Patient', 100.00),
('2017-04-27 00:00:00', 134523, 309, 'Place iv catheter', 30.00),
('2017-04-27 00:00:00', 234567, 245, 'Sedate Patient', 45.00),
('2017-04-28 00:00:00', 234567, 309, 'Place iv catheter', 30.00),
('2017-04-28 00:00:00', 345321, 245, 'Sedate Patient', 45.00),
('2017-04-29 00:00:00', 451324, 309, 'Place iv catheter', 30.00),
('2017-04-30 00:00:00', 451324, 309, 'Place iv catheter', 30.00),
('2017-04-30 00:00:00', 451324, 375, 'Surgical Pack', 28.00)
;
Query 1:
select CaseId
, sum(case when ProcedureTestId in (309,245,326) then 1 else 0 end) count_of
from Table1
group by CaseId
having sum(case when ProcedureTestId in (309,245,326) then 1 else 0 end) > 1
Results:
| CaseId | count_of |
|--------|----------|
| 234567 | 2 |
| 451324 | 2 |
| 989898 | 2 |
| 999999 | 3 |
Query 2:
select
t.*, d.count_of
from Table1 t
inner join (
select CaseId
, sum(case when ProcedureTestId in (309,245,326) then 1 else 0 end) count_of
from Table1
group by CaseId
having sum(case when ProcedureTestId in (309,245,326) then 1 else 0 end) > 1
) d on t.CaseId = d.CaseId
order by caseid, ProcedureTestId
Results:
| ActualDateTime | CaseId | ProcedureTestId | Description | FeeAmount | count_of |
|----------------------|--------|-----------------|-------------------|-----------|----------|
| 2017-04-27T00:00:00Z | 234567 | 245 | Sedate Patient | 45 | 2 |
| 2017-04-28T00:00:00Z | 234567 | 309 | Place iv catheter | 30 | 2 |
| 2017-04-29T00:00:00Z | 451324 | 309 | Place iv catheter | 30 | 2 |
| 2017-04-30T00:00:00Z | 451324 | 309 | Place iv catheter | 30 | 2 |
| 2017-04-30T00:00:00Z | 451324 | 375 | Surgical Pack | 28 | 2 |
| 2017-04-27T00:00:00Z | 989898 | 245 | Sedate Patient | 45 | 2 |
| 2017-04-25T00:00:00Z | 989898 | 309 | Place iv catheter | 30 | 2 |
| 2017-04-27T00:00:00Z | 999999 | 245 | Sedate Patient | 45 | 3 |
| 2017-04-25T00:00:00Z | 999999 | 309 | Place iv catheter | 30 | 3 |
| 2017-04-27T00:00:00Z | 999999 | 326 | whatever 326 is | 45 | 3 |
Below is the data in a table Star. I want a query which returns only 1 record per StarID per assessdate but if there are same assessdate for one starid then compare the askdate and return that record which has most recent askdate.
StarID | assessdate | artid | pep |manager | Notes | followup| askdate
DEC1660 | 2016-05-18 00:00:00.000 | 20979 | Yes |BRIGGS, SIMON |NULL | 6 Weeks | NULL
DEC1660 | 2016-05-19 00:00:00.000 | 20982 | No |BRIGGS, SIMON |Other, sdf, AZT, TDF, RAL | 12 Weeks| 2016-05-11 00:00:00.000
ANW4477 | 2016-05-27 00:00:00.000 |21008 | Yes |Mundt, Susan |NFV, DRV, MVC, Other, test| 6 Weeks | 2016-05-27 00:00:00.000
ANW4477 | 2016-05-28 00:00:00.000 |21011 | No |Henley, Rebecca |NULL | 12 Weeks| NULL
REP2893 | 2016-05-30 00:00:00.000 |21305 | Yes |Henley, Rebecca |AZT, 3TC | 12 Weeks| 2016-05-30 00:00:00.000
REP2893 | 2016-05-30 00:00:00.000 |21305 | Yes |Henley, Rebecca |TDF, FTC | 12 Weeks| 2016-06-02 00:00:00.000
Thanks in advance!
WITH X AS (
Select *
, ROW_NUMBER() OVER (PARTITION BY StarID, assessdate
ORDER BY askdate DESC) rn
FROM Star )
SELECT *
FROM X
WHERE rn = 1
I have a table that contains some shift information for an employee(s)
+-------+------------+------------------+------------+------------------+------------+
| empid | StartDate | StartTime | EndDate | EndTime | ShiftDate |
+-------+------------+------------------+------------+------------------+------------+
| 391 | 2014-12-16 | 20:00:00.0000000 | 2014-12-16 | 22:00:00.0000000 | ? |
| 391 | 2014-12-16 | 22:00:00.0000000 | 2014-12-16 | 22:15:00.0000000 | ? |
| 391 | 2014-12-16 | 22:15:00.0000000 | 2014-12-17 | 00:00:00.0000000 | ? |
| 391 | 2014-12-17 | 00:00:00.0000000 | 2014-12-17 | 00:45:00.0000000 | ? |
| 391 | 2014-12-17 | 00:45:00.0000000 | 2014-12-17 | 02:30:00.0000000 | ? |
| 391 | 2014-12-17 | 02:30:00.0000000 | 2014-12-17 | 02:45:00.0000000 | ? |
| 391 | 2014-12-17 | 02:45:00.0000000 | 2014-12-17 | 04:30:00.0000000 | ? |
+-------+------------+------------------+------------+------------------+------------+
| 391 | 2014-12-17 | 20:00:00.0000000 | 2014-12-17 | 21:45:00.0000000 | ? |
| 391 | 2014-12-17 | 21:45:00.0000000 | 2014-12-17 | 22:00:00.0000000 | ? |
| 391 | 2014-12-17 | 22:00:00.0000000 | 2014-12-18 | 00:00:00.0000000 | ? |
| 391 | 2014-12-18 | 00:00:00.0000000 | 2014-12-18 | 00:45:00.0000000 | ? |
| 391 | 2014-12-18 | 00:45:00.0000000 | 2014-12-18 | 02:30:00.0000000 | ? |
| 391 | 2014-12-18 | 02:30:00.0000000 | 2014-12-18 | 02:45:00.0000000 | ? |
| 391 | 2014-12-18 | 02:45:00.0000000 | 2014-12-18 | 04:30:00.0000000 | ? |
+-------+------------+------------------+------------+------------------+------------+
I need to update the ShiftDate Column with the StartDate for this shift. So below are 2 different shifts that EACH span over 2 days. The first shift the ShiftDate for each row should be 2014-12-16 and the second shift, each row's ShiftDate should be 2014-12-17.
Expected Result:
+-------+------------+------------------+------------+------------------+------------+
| empid | StartDate | StartTime | EndDate | EndTime | ShiftDate |
+-------+------------+------------------+------------+------------------+------------+
| 391 | 2014-12-16 | 20:00:00.0000000 | 2014-12-16 | 22:00:00.0000000 | 2014-12-16 |
| 391 | 2014-12-16 | 22:00:00.0000000 | 2014-12-16 | 22:15:00.0000000 | 2014-12-16 |
| 391 | 2014-12-16 | 22:15:00.0000000 | 2014-12-17 | 00:00:00.0000000 | 2014-12-16 |
| 391 | 2014-12-17 | 00:00:00.0000000 | 2014-12-17 | 00:45:00.0000000 | 2014-12-16 |
| 391 | 2014-12-17 | 00:45:00.0000000 | 2014-12-17 | 02:30:00.0000000 | 2014-12-16 |
| 391 | 2014-12-17 | 02:30:00.0000000 | 2014-12-17 | 02:45:00.0000000 | 2014-12-16 |
| 391 | 2014-12-17 | 02:45:00.0000000 | 2014-12-17 | 04:30:00.0000000 | 2014-12-16 |
+-------+------------+------------------+------------+------------------+------------+
| 391 | 2014-12-17 | 20:00:00.0000000 | 2014-12-17 | 21:45:00.0000000 | 2014-12-17 |
| 391 | 2014-12-17 | 21:45:00.0000000 | 2014-12-17 | 22:00:00.0000000 | 2014-12-17 |
| 391 | 2014-12-17 | 22:00:00.0000000 | 2014-12-18 | 00:00:00.0000000 | 2014-12-17 |
| 391 | 2014-12-18 | 00:00:00.0000000 | 2014-12-18 | 00:45:00.0000000 | 2014-12-17 |
| 391 | 2014-12-18 | 00:45:00.0000000 | 2014-12-18 | 02:30:00.0000000 | 2014-12-17 |
| 391 | 2014-12-18 | 02:30:00.0000000 | 2014-12-18 | 02:45:00.0000000 | 2014-12-17 |
| 391 | 2014-12-18 | 02:45:00.0000000 | 2014-12-18 | 04:30:00.0000000 | 2014-12-17 |
+-------+------------+------------------+------------+------------------+------------+
I cannot work up a way to determine the shift date from the given rows. When it's a new shift, the Shift StartTime would never be the same as the Shift's previous EndTime.
I'm working with SQL 2008 R2
Any suggestions to get me going in the right direction would be great!
Use recursive CTE:
;WITH
CTE1 AS
(
SELECT empid, StartDate, StartTime, EndDate, EndTime,
ROW_NUMBER() OVER (PARTITION BY empid ORDER BY StartDate, StartTime) AS RowNumber
FROM EmployeeShift
),
CTE2 AS (
SELECT empid, StartDate, StartTime, EndDate, EndTime,
StartDate AS ShiftDate,
RowNumber
FROM CTE1
WHERE RowNumber = 1
UNION ALL
SELECT c1.empid, c1.StartDate, c1.StartTime, c1.EndDate, c1.EndTime,
CASE
WHEN c1.StartDate = c2.EndDate AND c1.StartTime = c2.EndTime THEN c2.ShiftDate
ELSE c1.StartDate
END AS ShiftDate,
c1.RowNumber
FROM CTE1 c1
INNER JOIN CTE2 c2 ON c1.empid = c2.empid AND c1.RowNumber = c2.RowNumber + 1
)
SELECT * FROM CTE2
OPTION (MAXRECURSION 0)
A commentor asked for its internals so here it goes:
Each shift entry is numbered 1,2,3,...,n by each employee, and sorted according to its start and end date. This is CTE1
For the first shift entry, the ShiftDate is the same as its StartDate. This is the first half of CTE2.
From the first shift entry, it recursively goes through the next entry for the employee. If the next entry's Start Time is the same as previous entry's End Time, it carries on the previous ShiftDate. Otherwise it sets the ShiftDate to the current shift's StartDate.
I have a table like below.
Date | Time | connect |
2013-08-23 00:00:00.000 | 05.26.13 | 1 |
2013-08-23 00:00:00.000 | 05.32.11 | 1 |
2013-08-23 00:00:00.000 | 05.26.13 | 1 |
2013-08-23 00:00:00.000 | 06.02.52 | 1 |
2013-08-23 00:00:00.000 | 06.41.09 | 1 |
2013-08-23 00:00:00.000 | 06.43.12 | 1 |
2013-08-23 00:00:00.000 | 06.52.09 | 1 |
2013-08-23 00:00:00.000 | 06.57.39 | 1 |
2013-10-21 00:00:00.000 | 03.58.35 | 1 |
2013-10-21 00:00:00.000 | 04.02.18 | 1 |
2013-10-21 00:00:00.000 | 04.12.02 | 1 |
2013-10-21 00:00:00.000 | 04.41.36 | 1 |
2013-10-21 00:00:00.000 | 11.12.27 | 1 |
2013-10-22 00:00:00.000 | 11.58.35 | 1 |
I want to get the count of connect that fall in each hour, grouped by date.
Count falling between 1:00 to 1:59, 2:00 to 2:59 and so on. The below is model of the output that I require.
Date | Count(between 4.00.00 to 4.59.59) | Count(between 5.00.00 to 5.59.59) | Count(between 6.00.00 to 6.59.59) |Count(between 11.00.00 to 11.59.59) |
2013-08-23 00:00:00.000 | 0 | 3 | 5 | 0 |
2013-10-21 00:00:00.000 | 3 | 1 | 0 | 1 |
2013-10-22 00:00:00.000 | 0 | 0 | 0 | 1 |
You can just use group by with the date time functions if you don't care about missing 0 row counts, but if you are concerned, use the tally table example Jeff mentions in 2nd page of this forum post: http://www.sqlservercentral.com/Forums/Topic288581-8-1.aspx Both examples in this post, but it note it is by half hour, should be easy to convert to hour.
This is what I want.
by Matt Watson
SELECT [Hourly], COUNT(*) as [Count] FROM (SELECT dateadd(hh, datediff(hh, '20010101', [date_created]), '20010101') as [Hourly] FROM table) idat GROUP BY [Hourly]
I'm using SQL Server 2008 R2 and I have the following dataset:
+---------+--------------+--------------+----------+------------+------------+
| Dossier | refmouvement | refadmission | refunite | datedeb | datefin |
+---------+--------------+--------------+----------+------------+------------+
| P001234 | 2567 | 1234 | 227 | 2012-01-01 | 2012-01-02 |
| P001234 | 2568 | 1234 | 227 | 2012-01-02 | 2012-01-03 |
| P001234 | 2569 | 1234 | 224 | 2012-01-03 | 2012-01-06 |
| P001234 | 2570 | 1234 | 232 | 2012-01-06 | 2012-01-10 |
| P001234 | 2571 | 1234 | 232 | 2012-01-10 | 2012-01-15 |
| P001234 | 2572 | 1234 | 232 | 2012-01-15 | 2012-01-20 |
| P001234 | 2573 | 1234 | 232 | 2012-01-20 | 2012-01-25 |
| P001234 | 2574 | 1234 | 224 | 2012-01-25 | 2012-01-29 |
| P001234 | 2575 | 1234 | 227 | 2012-01-29 | 2012-02-05 |
| P001234 | 2576 | 1234 | 227 | 2012-02-05 | 2012-02-10 |
| P001234 | 2577 | 1234 | 232 | 2012-02-10 | 2012-02-15 |
| P001234 | 2578 | 1234 | 201 | 2012-02-15 | 2012-02-26 |
+---------+--------------+--------------+----------+------------+------------+
This dataset is ordered by datedeb, otherwise known as startdate.
As you can notice this is a contiguous dataset where datefin is equal to the next line's datedeb
I need to create an ID column that is going to give an unique ID based on the refunite and the datedeb columns like this:
+----+---------+--------------+--------------+----------+------------+------------+
| ID | Dossier | refmouvement | refadmission | refunite | datedeb | datefin |
+----+---------+--------------+--------------+----------+------------+------------+
| 1 | P001234 | 2567 | 1234 | 227 | 2012-01-01 | 2012-01-02 |
| 1 | P001234 | 2568 | 1234 | 227 | 2012-01-02 | 2012-01-03 |
| 2 | P001234 | 2569 | 1234 | 224 | 2012-01-03 | 2012-01-06 |
| 3 | P001234 | 2570 | 1234 | 232 | 2012-01-06 | 2012-01-10 |
| 3 | P001234 | 2571 | 1234 | 232 | 2012-01-10 | 2012-01-15 |
| 3 | P001234 | 2572 | 1234 | 232 | 2012-01-15 | 2012-01-20 |
| 3 | P001234 | 2573 | 1234 | 232 | 2012-01-20 | 2012-01-25 |
| 4 | P001234 | 2574 | 1234 | 224 | 2012-01-25 | 2012-01-29 |
| 5 | P001234 | 2575 | 1234 | 227 | 2012-01-29 | 2012-02-05 |
| 5 | P001234 | 2576 | 1234 | 227 | 2012-02-05 | 2012-02-10 |
| 6 | P001234 | 2577 | 1234 | 232 | 2012-02-10 | 2012-02-15 |
| 7 | P001234 | 2578 | 1234 | 201 | 2012-02-15 | 2012-02-26 |
+----+---------+--------------+--------------+----------+------------+------------+
I just can't wrap my head around a RANK(), ROW_NUMBER() or DENSE_RANK() function or a combination of that could achieve this, I have looked everywhere but I cannot find anything, maybe I'm not using the proper keywords but I just can't figure it out
Any help will be appreciated
Thanks.
Here's the code that I've tried so far:
SELECT
ROW_NUMBER() over(order by t1.[datedeb]) as [ID1],
dense_Rank() over(partition by t1.[refunite] order by t1.[datedeb]) as [ID2],
t1.[Dossier]
,t1.[refmouvement]
,t1.[refadmission]
,t1.[refunite]
,t1.[datedeb]
,t1.[datefin]
,t2.[refmouvement] as [prev_refmouvement]
,t2.refunite as prev_refunite
FROM [sometable] t1
LEFT OUTER JOIN [sometable] t2 /*self join*/
ON t2.datefin = t1.datedeb
AND t1.[refadmission] = t2.[refadmission]
ORDER BY
t1.[datedeb]
This is what it gives me :
+-----+-----+---------+--------------+--------------+----------+------------+------------+-------------------+---------------+
| ID1 | ID2 | Dossier | refmouvement | refadmission | refunite | datedeb | datefin | prev_refmouvement | prev_refunite |
+-----+-----+---------+--------------+--------------+----------+------------+------------+-------------------+---------------+
| 1 | 1 | P001234 | 2567 | 1234 | 227 | 2012-01-01 | 2012-01-02 | NULL | NULL |
| 2 | 2 | P001234 | 2568 | 1234 | 227 | 2012-01-02 | 2012-01-03 | 2567 | 227 |
| 3 | 1 | P001234 | 2569 | 1234 | 224 | 2012-01-03 | 2012-01-06 | 2568 | 227 |
| 4 | 1 | P001234 | 2570 | 1234 | 232 | 2012-01-06 | 2012-01-10 | 2569 | 224 |
| 5 | 2 | P001234 | 2571 | 1234 | 232 | 2012-01-10 | 2012-01-15 | 2570 | 232 |
| 6 | 3 | P001234 | 2572 | 1234 | 232 | 2012-01-15 | 2012-01-20 | 2571 | 232 |
| 7 | 4 | P001234 | 2573 | 1234 | 232 | 2012-01-20 | 2012-01-25 | 2572 | 232 |
| 8 | 2 | P001234 | 2574 | 1234 | 224 | 2012-01-25 | 2012-01-29 | 2573 | 232 |
| 9 | 3 | P001234 | 2575 | 1234 | 227 | 2012-01-29 | 2012-02-05 | 2574 | 224 |
| 10 | 4 | P001234 | 2576 | 1234 | 227 | 2012-02-05 | 2012-02-10 | 2575 | 227 |
| 11 | 5 | P001234 | 2577 | 1234 | 232 | 2012-02-10 | 2012-02-15 | 2576 | 227 |
| 12 | 1 | P001234 | 2578 | 1234 | 201 | 2012-02-15 | 2012-02-26 | 2577 | 232 |
+-----+-----+---------+--------------+--------------+----------+------------+------------+-------------------+---------------+
Shaz
DECLARE #Results TABLE(
RowNum INT PRIMARY KEY,
refunite INT NOT NULL,
datedeb DATETIME NOT NULL
);
INSERT #Results (RowNum, refunite, datedeb)
SELECT ROW_NUMBER() OVER(ORDER BY datedeb) AS RowNum,
refunite,
datedeb
FROM dbo.MyTable;
WITH CTERecursive
AS (
SELECT crt.RowNum,
crt.refunite,
crt.datedeb,
1 AS Rnk -- Starting rank
FROM #Results crt
WHERE crt.RowNum = 1
UNION ALL
SELECT crt.RowNum,
crt.refunite,
crt.datedeb,
CASE WHEN prev.refunite = crt.refunite THEN prev.Rnk ELSE prev.Rnk + 1 END
FROM #Results crt INNER JOIN CTERecursive prev ON crt.RowNum = prev.RowNum + 1
)
SELECT *
FROM CTERecursive
-- OPTION(MAXRECURSION 1000); -- Uncomment this line if you change the number of recursion levels allowed (default 100)
Results:
RowNum refunite datedeb Rnk
----------- ----------- ----------------------- ---
1 227 2012-01-01 00:00:00.000 1
2 227 2012-01-02 00:00:00.000 1
3 224 2012-01-03 00:00:00.000 2
4 232 2012-01-06 00:00:00.000 3
5 232 2012-01-10 00:00:00.000 3
6 232 2012-01-15 00:00:00.000 3
7 232 2012-01-20 00:00:00.000 3
8 224 2012-01-25 00:00:00.000 4
9 227 2012-01-29 00:00:00.000 5
10 227 2012-02-05 00:00:00.000 5
11 232 2012-02-10 00:00:00.000 6
12 201 2012-02-15 00:00:00.000 7
You could, of course, have multiple tables in the WITH, eliminating the table variable.
Based on Bogdan Sahleans answer, you could rewrite like this:
WITH CTEHelper AS
(SELECT ROW_NUMBER() OVER(ORDER BY datedeb) AS RowNum,
refunite,
datedeb
FROM dbo.Sometable),
CTERecursive AS (
SELECT crt.RowNum,
crt.refunite,
crt.datedeb,
1 AS Id -- Starting rank
FROM CTEHelper crt
WHERE crt.RowNum = 1
UNION ALL
SELECT crt.RowNum,
crt.refunite,
crt.datedeb,
CASE WHEN prev.refunite = crt.refunite THEN prev.Id ELSE prev.Id + 1 END
FROM CTEHelper crt INNER JOIN CTERecursive prev ON crt.RowNum = prev.RowNum + 1
)
SELECT crt.id,
s.*
FROM CTERecursive crt
JOIN Sometable s ON s.refunite = crt.refunite AND s.datedeb = crt.datedeb
with sometable as (
select *
from (
values ('P001234', 2567, 1234, 227, cast('2012-01-01' as date), cast('2012-01-02' as date)),
('P001234', 2568, 1234, 227, cast('2012-01-02' as date), cast('2012-01-03' as date)),
('P001234', 2569, 1234, 224, cast('2012-01-03' as date), cast('2012-01-06' as date)),
('P001234', 2570, 1234, 232, cast('2012-01-06' as date), cast('2012-01-10' as date)),
('P001234', 2571, 1234, 232, cast('2012-01-10' as date), cast('2012-01-15' as date)),
('P001234', 2572, 1234, 232, cast('2012-01-15' as date), cast('2012-01-20' as date)),
('P001234', 2573, 1234, 232, cast('2012-01-20' as date), cast('2012-01-25' as date)),
('P001234', 2574, 1234, 224, cast('2012-01-25' as date), cast('2012-01-29' as date)),
('P001234', 2575, 1234, 227, cast('2012-01-29' as date), cast('2012-02-05' as date)),
('P001234', 2576, 1234, 227, cast('2012-02-05' as date), cast('2012-02-10' as date)),
('P001234', 2577, 1234, 232, cast('2012-02-10' as date), cast('2012-02-15' as date)),
('P001234', 2578, 1234, 201, cast('2012-02-15' as date), cast('2012-02-26' as date))
) t (Dossier, refmouvement, refadmission, refunite, datedeb, datefin)
), pos as (
select d.*, (case when d2.refunite is null then null
when d2.refunite != d.refunite then d2.datedeb
else d.datedeb end) as forward,
(case when d3.refunite is null then null
when d3.refunite != d.refunite then d3.datedeb
else d.datedeb end) as backward
from sometable d
left outer join sometable d2 on d.refadmission = d2.refadmission and d.datefin = d2.datedeb
left outer join sometable d3 on d.refadmission = d3.refadmission and d.datedeb = d3.datefin
)
select dense_rank() over (order by isnull((select min(datedeb)
from pos
where refadmission = t.refadmission
and refunite = t.refunite
and datedeb > t.datedeb
and datedeb = backward
and ((t.datedeb = t.backward and t.datedeb = t.forward)
or t.datedeb != t.backward or t.backward is null)
and datedeb != forward), datedeb)) as ID,
Dossier, refmouvement, refadmission, refunite, datedeb, datefin
from pos t
order by datedeb