T-SQL to create an ID column - sql-server

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

Related

SSMS SQL Row_Number incorrect sort

I'm trying to sort by USID and then Date and restart the row number on USID, Utilized. But for some reason the Date is in the incorrect order, so the row numbering isn't doing what I need.
Currently this is what my code is getting me:
USID | Date | Utilized | RowNumber
123 | 1/1/19 | T | 1
123 | 1/2/19 | T | 2
123 | 1/3/19 | T | 3
123 | 1/19/19| T | 4
123 | 1/20/19| T | 5
123 | 1/21/19| T | 6
123 | 1/4/19 | F | 1
123 | 1/5/19 | F | 2
123 | 1/6/19 | F | 3
123 | 1/7/19 | F | 4
123 | 1/8/19 | F | 5
123 | 1/9/19 | F | 6
125 | 1/1/19 | T | 1
125 | 1/2/19 | T | 2
125 | 1/3/19 | T | 3
125 | 1/10/19| T | 4
125 | 1/11/19| T | 5
125 | 1/12/19| T | 6
125 | 1/4/19 | F | 1
125 | 1/5/19 | F | 2
125 | 1/6/19 | F | 3
125 | 1/7/19 | F | 4
125 | 1/8/19 | F | 5
125 | 1/9/19 | F | 6
However I would want it to look like:
USID | Date | Utilized | RowNumber
123 | 1/1/19 | T | 1
123 | 1/2/19 | T | 2
123 | 1/3/19 | T | 3
123 | 1/4/19 | F | 1
123 | 1/5/19 | F | 2
123 | 1/6/19 | F | 3
123 | 1/7/19 | F | 4
123 | 1/8/19 | F | 5
123 | 1/9/19 | F | 6
123 | 1/19/19| T | 1
123 | 1/20/19| T | 2
123 | 1/21/19| T | 3
125 | 1/1/19 | T | 1
125 | 1/2/19 | T | 2
125 | 1/3/19 | T | 3
125 | 1/4/19 | F | 1
125 | 1/5/19 | F | 2
125 | 1/6/19 | F | 3
125 | 1/7/19 | F | 4
125 | 1/8/19 | F | 5
125 | 1/9/19 | F | 6
125 | 1/10/19| T | 1
125 | 1/11/19| T | 2
125 | 1/12/19| T | 3
Here is what I have so far:
select
USID, cast(Date as datetime) as Date, Utilized,
ROW_NUMBER() OVER(PARTITION BY USID, Utilized
ORDER BY USID, cast(Date as datetime) ASC, Utilized)
from vps_time_FullyUtilized
Where am I going wrong?
Here is one gaps and islands solution.
SQL Fiddle
MS SQL Server 2017 Schema Setup:
CREATE TABLE T(USID INT, Date DATETIME, Utilized NVARCHAR(10))
INSERT INTO T VALUES
(123, '1/1/19', 'T'),
(123, '1/2/19', 'T'),
(123, '1/3/19', 'T'),
(123, '1/4/19', 'F'),
(123, '1/5/19', 'F'),
(123, '1/6/19', 'F'),
(123, '1/7/19', 'F'),
(123, '1/8/19', 'F'),
(123, '1/9/19', 'F'),
(123, '1/19/19', 'T'),
(123, '1/20/19', 'T'),
(123, '1/21/19', 'T'),
(223, '1/1/19', 'T'),
(223, '1/2/19', 'T'),
(223, '1/3/19', 'T'),
(223, '1/4/19', 'F'),
(223, '1/5/19', 'F'),
(223, '1/6/19', 'F'),
(223, '1/7/19', 'F'),
(223, '1/8/19', 'F'),
(223, '1/9/19', 'F'),
(223, '1/19/19', 'T'),
(223, '1/20/19', 'T'),
(223, '1/21/19', 'T')
Query 1:
WITH DataWithEndBoundries AS
(
SELECT
USID,Date,Utilized,
--Mark your groups here
IsNewGroup = CASE WHEN ISNULL(LAG(Utilized) OVER (ORDER BY USID,Date),Utilized)<>Utilized THEN 1 ELSE 0 END
FROM
T
)
,VirtualGroup AS
(
SELECT
*,
--This serialzes the marked groups into clusters
VirtualGroupID = SUM(IsNewGroup) OVER (ORDER BY USID, Date ROWS UNBOUNDED PRECEDING)
FROM
DataWithEndBoundries
)
SELECT
USID, Date, Utilized,
--Now you can row number agianst the Virtualized value
RowNumber = ROW_NUMBER() OVER (PARTITION BY USID, VirtualGroupID ORDER BY Date)
FROM
VirtualGroup
ORDER BY
USID,Date
Results:
| USID | Date | Utilized | RowNumber |
|------|----------------------|----------|-----------|
| 123 | 2019-01-01T00:00:00Z | T | 1 |
| 123 | 2019-01-02T00:00:00Z | T | 2 |
| 123 | 2019-01-03T00:00:00Z | T | 3 |
| 123 | 2019-01-04T00:00:00Z | F | 1 |
| 123 | 2019-01-05T00:00:00Z | F | 2 |
| 123 | 2019-01-06T00:00:00Z | F | 3 |
| 123 | 2019-01-07T00:00:00Z | F | 4 |
| 123 | 2019-01-08T00:00:00Z | F | 5 |
| 123 | 2019-01-09T00:00:00Z | F | 6 |
| 123 | 2019-01-19T00:00:00Z | T | 1 |
| 123 | 2019-01-20T00:00:00Z | T | 2 |
| 123 | 2019-01-21T00:00:00Z | T | 3 |
| 223 | 2019-01-01T00:00:00Z | T | 1 |
| 223 | 2019-01-02T00:00:00Z | T | 2 |
| 223 | 2019-01-03T00:00:00Z | T | 3 |
| 223 | 2019-01-04T00:00:00Z | F | 1 |
| 223 | 2019-01-05T00:00:00Z | F | 2 |
| 223 | 2019-01-06T00:00:00Z | F | 3 |
| 223 | 2019-01-07T00:00:00Z | F | 4 |
| 223 | 2019-01-08T00:00:00Z | F | 5 |
| 223 | 2019-01-09T00:00:00Z | F | 6 |
| 223 | 2019-01-19T00:00:00Z | T | 1 |
| 223 | 2019-01-20T00:00:00Z | T | 2 |
| 223 | 2019-01-21T00:00:00Z | T | 3 |

Repair historical data

I have a historical table like this:
+------------------+------------------+---------+-------+
| valid_from | valid_to | Profit | ID |
+------------------+------------------+---------+-------+
| 20.05.2019 00:02 | 22.05.2019 23:42 | 10 | 12345 |
| 22.05.2019 23:42 | 28.05.2019 13:11 | 10 | 12345 |
| 28.05.2019 13:11 | 28.05.2019 23:59 | 10 | 12345 |
| 28.05.2019 23:59 | 29.05.2019 06:48 | 123 | 12345 |
| 29.05.2019 06:48 | 29.05.2019 13:21 | 123 | 12345 |
| 29.05.2019 13:21 | 29.05.2019 23:59 | 123 | 12345 |
| 29.05.2019 23:59 | 30.05.2019 06:39 | 10 | 12345 |
| 30.05.2019 06:39 | 30.05.2019 12:37 | 123 | 12345 |
| 30.05.2019 12:37 | 31.05.2019 00:09 | 123 | 12345 |
| 31.05.2019 00:09 | 31.05.2019 08:41 | 145 | 12345 |
| 31.05.2019 08:41 | 01.06.2019 00:22 | 145 | 12345 |
+------------------+------------------+---------+-------+
I deleted some columns. Row 1, 2 and 3 can now be summarized.
At first I tried following GROUP-BY Statement:
SELECT MIN(valid_from ) AS valid_from
,MAX(valid_to ) AS valid_to
,Profit
,ID
INTO [repaired_archiv]
FROM temp.[wrong_archiv]
GROUP BY Profit
,ID
The result is:
+------------------+------------------+---------+-------+
| valid_from | valid_to | Profit | ID |
+------------------+------------------+---------+-------+
| 20.05.2019 00:02 | 30.05.2019 06:39 | 10 | 12345 |
| 28.05.2019 23:59 | 31.05.2019 00:09 | 123 | 12345 |
| 31.05.2019 00:09 | 01.06.2019 00:22 | 145 | 12345 |
+------------------+------------------+---------+-------+
but as you see, the valid_to column in the first row ist wrong. The reason for this is the wrong GROUP-BY Statement. I don't know how to get my aspected result like this:
+------------------+------------------+---------+-------+
| valid_from | valid_to | Profit | ID |
+------------------+------------------+---------+-------+
| 20.05.2019 00:02 | 28.05.2019 23:59 | 10 | 12345 |
| 28.05.2019 23:59 | 29.05.2019 23:59 | 123 | 12345 |
| 29.05.2019 23:59 | 30.05.2019 06:39 | 10 | 12345 |
| 30.05.2019 06:39 | 31.05.2019 00:09 | 123 | 12345 |
| 31.05.2019 00:09 | 01.06.2019 00:22 | 145 | 12345 |
+------------------+------------------+---------+-------+
You need two row_number() :
select min(valid_from) as valid_from, max(valid_to) as valid_to, id, profit
from (select t.*,
row_number() over (order by valid_from) as seq1,
row_number() over (partition by id, profit order by valid_from) as seq2
from temp.[wrong_archiv] t
) t
group by id, profit, (seq1 - seq2)
order by valid_from;

T-SQL: Values are grouped by month, if there is no value for a month the month should also appear and display "NULL"

i have a SQL that displays turnover, stock and other values for stores grouped by month. Logically, if there is no value for a month, the month doesn't appear. The target is that the empty month should appear and display "NULL" for the values. The empty months should range from the #FROM to the #TO parameter (201807 to 201907) in this case.
Before:
+-------+--------+----------+----------+-------+
| Store | Month | Incoming | Turnover | Stock |
+-------+--------+----------+----------+-------+
| 123 | 201810 | 5 | 4 | 1 |
| 123 | 201811 | 0 | 1 | 0 |
| 123 | 201901 | 25 | 5 | 20 |
| 123 | 201902 | 5 | 10 | 15 |
| 123 | 201903 | 8 | 9 | 14 |
| 123 | 201904 | 5 | 4 | 15 |
| 123 | 201905 | 10 | 5 | 20 |
+-------+--------+----------+----------+-------+
After:
+-------+--------+----------+----------+-------+
| Store | Month | Incoming | Turnover | Stock |
+-------+--------+----------+----------+-------+
| 123 | 201807 | NULL | NULL | NULL |
| 123 | 201808 | NULL | NULL | NULL |
| 123 | 201809 | NULL | NULL | NULL |
| 123 | 201810 | 5 | 4 | 1 |
| 123 | 201811 | 0 | 1 | 0 |
| 123 | 201812 | NULL | NULL | NULL |
| 123 | 201901 | 25 | 5 | 20 |
| 123 | 201902 | 5 | 10 | 15 |
| 123 | 201903 | 8 | 9 | 14 |
| 123 | 201904 | 5 | 4 | 15 |
| 123 | 201905 | 10 | 5 | 20 |
| 123 | 201906 | NULL | NULL | NULL |
| 123 | 201907 | NULL | NULL | NULL |
+-------+--------+----------+----------+-------+
Code Example: db<>fiddle
I have absolutely no idea how to solve this and will thank you in advance for your help! :)
You can try to use cte recursive make a calendar table, then do outer-join
;WITH CTE AS (
SELECT CAST(CAST(#FROM AS VARCHAR(10)) + '01' AS DATE) fromDt,
CAST(CAST(#TO AS VARCHAR(10)) + '01' AS DATE) toDt,
Store
FROM (SELECT DISTINCT Store FROM #Test) t1
UNION ALL
SELECT DATEADD(MONTH,1,fromDt),toDt,Store
FROM CTE
WHERE DATEADD(MONTH,1,fromDt) <= toDt
)
SELECT FORMAT(fromDt,'yyyyMM') Month,
c.Store,
t.Incoming,
t.Turnover,
t.Stock
FROM CTE c
LEFT JOIN #Test t on
c.fromDt = CAST(CAST(t.Month AS VARCHAR(10)) + '01' AS DATE)
and
c.Store = t.Store
sqlfiddle

Check overlap by each ID, SQL Server 2008

I am trying to find a solution how to find overlap in case below.
I have two tables with employee ID, number or breaktime, hour of planned breaktime start and stop. In ideal situation number of planned break and used should be the same but it is not. What I need to do is compare by each ID and check if used break is in the same time like planned, if not how big is the gap.
My idea is to check by ID each number with every number in the second table and mark it ok/not ok an how big is the gap. I thin there is a better way, more efficient to do this. Could You help me to find the solution?
I'll appreciate every prompt.
ID | number | time_start_plan | time_stop_plan
-----+--------+-------------------------+------------------------
965 | 1 | 2017-09-11 00:00:00.000 | 2017-09-11 00:15:00.000
965 | 2 | 2017-09-11 01:15:00.000 | 2017-09-11 01:25:00.000
965 | 3 | 2017-09-11 02:40:00.000 | 2017-09-11 02:50:00.000
965 | 4 | 2017-09-11 04:20:00.000 | 2017-09-11 04:30:00.000
1122 | 1 | 2017-09-11 00:05:00.000 | 2017-09-11 00:20:00.000
1122 | 2 | 2017-09-11 01:20:00.000 | 2017-09-11 01:30:00.000
1122 | 3 | 2017-09-11 03:10:00.000 | 2017-09-11 03:20:00.000
ID | number | time_start_used | time_stop_used
-----+--------+-------------------------+------------------------
965 | 1 | 2017-09-11 00:34:41.000 | 2017-09-11 00:36:34.000
965 | 2 | 2017-09-11 02:33:00.000 | 2017-09-11 02:36:26.000
965 | 3 | 2017-09-11 04:24:17.000 | 2017-09-11 04:27:42.000
965 | 4 | 2017-09-11 06:06:02.000 | 2017-09-11 06:18:19.000
965 | 5 | 2017-09-11 22:41:02.000 | 2017-09-11 22:42:06.000
1122 | 1 | 2017-09-11 00:15:12.000 | 2017-09-11 00:15:32.000
1122 | 2 | 2017-09-11 01:07:56.000 | 2017-09-11 01:26:57.000
1122 | 3 | 2017-09-11 01:49:02.000 | 2017-09-11 01:51:13.000
1122 | 4 | 2017-09-11 03:33:50.000 | 2017-09-11 03:34:17.000
1122 | 5 | 2017-09-11 04:07:59.000 | 2017-09-11 04:09:10.000
1122 | 6 | 2017-09-11 05:51:23.000 | 2017-09-11 05:54:22.000
This solution variant only partially matching [number] in that the t1.number must be <= to the t2.number. This leads of course to many more rows of output.
See this SQL Fiddle as a demonstration.
Query:
select
coalesce(t1.id, t2.id) ids
, coalesce(t1.number, t2.number) numbers
, datediff(minute,t1.time_start_plan, t2.time_start_used) diff_start
, datediff(minute,t1.time_stop_plan, t2.time_stop_used) diff_stop
, t1.time_start_plan
, t2.time_start_used
, t1.time_stop_plan
, t2.time_stop_used
from table1 t1
LEFT outer join table2 t2 on t1.id = t2.id and t1.number <= t2.number
order by ids, numbers
Results:
| ids | numbers | diff_start | diff_stop | time_start_plan | time_start_used | time_stop_plan | time_stop_used |
|------|---------|------------|-----------|----------------------|----------------------|----------------------|----------------------|
| 965 | 1 | 34 | 21 | 2017-09-11T00:00:00Z | 2017-09-11T00:34:41Z | 2017-09-11T00:15:00Z | 2017-09-11T00:36:34Z |
| 965 | 1 | 153 | 141 | 2017-09-11T00:00:00Z | 2017-09-11T02:33:00Z | 2017-09-11T00:15:00Z | 2017-09-11T02:36:26Z |
| 965 | 1 | 264 | 252 | 2017-09-11T00:00:00Z | 2017-09-11T04:24:17Z | 2017-09-11T00:15:00Z | 2017-09-11T04:27:42Z |
| 965 | 1 | 366 | 363 | 2017-09-11T00:00:00Z | 2017-09-11T06:06:02Z | 2017-09-11T00:15:00Z | 2017-09-11T06:18:19Z |
| 965 | 1 | 1361 | 1347 | 2017-09-11T00:00:00Z | 2017-09-11T22:41:02Z | 2017-09-11T00:15:00Z | 2017-09-11T22:42:06Z |
| 965 | 2 | 78 | 71 | 2017-09-11T01:15:00Z | 2017-09-11T02:33:00Z | 2017-09-11T01:25:00Z | 2017-09-11T02:36:26Z |
| 965 | 2 | 189 | 182 | 2017-09-11T01:15:00Z | 2017-09-11T04:24:17Z | 2017-09-11T01:25:00Z | 2017-09-11T04:27:42Z |
| 965 | 2 | 291 | 293 | 2017-09-11T01:15:00Z | 2017-09-11T06:06:02Z | 2017-09-11T01:25:00Z | 2017-09-11T06:18:19Z |
| 965 | 2 | 1286 | 1277 | 2017-09-11T01:15:00Z | 2017-09-11T22:41:02Z | 2017-09-11T01:25:00Z | 2017-09-11T22:42:06Z |
| 965 | 3 | 104 | 97 | 2017-09-11T02:40:00Z | 2017-09-11T04:24:17Z | 2017-09-11T02:50:00Z | 2017-09-11T04:27:42Z |
| 965 | 3 | 206 | 208 | 2017-09-11T02:40:00Z | 2017-09-11T06:06:02Z | 2017-09-11T02:50:00Z | 2017-09-11T06:18:19Z |
| 965 | 3 | 1201 | 1192 | 2017-09-11T02:40:00Z | 2017-09-11T22:41:02Z | 2017-09-11T02:50:00Z | 2017-09-11T22:42:06Z |
| 965 | 4 | 106 | 108 | 2017-09-11T04:20:00Z | 2017-09-11T06:06:02Z | 2017-09-11T04:30:00Z | 2017-09-11T06:18:19Z |
| 965 | 4 | 1101 | 1092 | 2017-09-11T04:20:00Z | 2017-09-11T22:41:02Z | 2017-09-11T04:30:00Z | 2017-09-11T22:42:06Z |
| 1122 | 1 | 10 | -5 | 2017-09-11T00:05:00Z | 2017-09-11T00:15:12Z | 2017-09-11T00:20:00Z | 2017-09-11T00:15:32Z |
| 1122 | 1 | 62 | 66 | 2017-09-11T00:05:00Z | 2017-09-11T01:07:56Z | 2017-09-11T00:20:00Z | 2017-09-11T01:26:57Z |
| 1122 | 1 | 104 | 91 | 2017-09-11T00:05:00Z | 2017-09-11T01:49:02Z | 2017-09-11T00:20:00Z | 2017-09-11T01:51:13Z |
| 1122 | 1 | 208 | 194 | 2017-09-11T00:05:00Z | 2017-09-11T03:33:50Z | 2017-09-11T00:20:00Z | 2017-09-11T03:34:17Z |
| 1122 | 1 | 242 | 229 | 2017-09-11T00:05:00Z | 2017-09-11T04:07:59Z | 2017-09-11T00:20:00Z | 2017-09-11T04:09:10Z |
| 1122 | 1 | 346 | 334 | 2017-09-11T00:05:00Z | 2017-09-11T05:51:23Z | 2017-09-11T00:20:00Z | 2017-09-11T05:54:22Z |
| 1122 | 2 | -13 | -4 | 2017-09-11T01:20:00Z | 2017-09-11T01:07:56Z | 2017-09-11T01:30:00Z | 2017-09-11T01:26:57Z |
| 1122 | 2 | 29 | 21 | 2017-09-11T01:20:00Z | 2017-09-11T01:49:02Z | 2017-09-11T01:30:00Z | 2017-09-11T01:51:13Z |
| 1122 | 2 | 133 | 124 | 2017-09-11T01:20:00Z | 2017-09-11T03:33:50Z | 2017-09-11T01:30:00Z | 2017-09-11T03:34:17Z |
| 1122 | 2 | 167 | 159 | 2017-09-11T01:20:00Z | 2017-09-11T04:07:59Z | 2017-09-11T01:30:00Z | 2017-09-11T04:09:10Z |
| 1122 | 2 | 271 | 264 | 2017-09-11T01:20:00Z | 2017-09-11T05:51:23Z | 2017-09-11T01:30:00Z | 2017-09-11T05:54:22Z |
| 1122 | 3 | -81 | -89 | 2017-09-11T03:10:00Z | 2017-09-11T01:49:02Z | 2017-09-11T03:20:00Z | 2017-09-11T01:51:13Z |
| 1122 | 3 | 23 | 14 | 2017-09-11T03:10:00Z | 2017-09-11T03:33:50Z | 2017-09-11T03:20:00Z | 2017-09-11T03:34:17Z |
| 1122 | 3 | 57 | 49 | 2017-09-11T03:10:00Z | 2017-09-11T04:07:59Z | 2017-09-11T03:20:00Z | 2017-09-11T04:09:10Z |
| 1122 | 3 | 161 | 154 | 2017-09-11T03:10:00Z | 2017-09-11T05:51:23Z | 2017-09-11T03:20:00Z | 2017-09-11T05:54:22Z |
I think you will need a FULL OUTER JOIN like this example also available here at SQL Fiddle
CREATE TABLE Table1
([ID] int, [number] int, [time_start_plan] datetime, [time_stop_plan] datetime)
;
INSERT INTO Table1
([ID], [number], [time_start_plan], [time_stop_plan])
VALUES
(965, 1, '2017-09-11 00:00:00.000', '2017-09-11 00:15:00.000'),
(965, 2, '2017-09-11 01:15:00.000', '2017-09-11 01:25:00.000'),
(965, 3, '2017-09-11 02:40:00.000', '2017-09-11 02:50:00.000'),
(965, 4, '2017-09-11 04:20:00.000', '2017-09-11 04:30:00.000'),
(1122, 1, '2017-09-11 00:05:00.000', '2017-09-11 00:20:00.000'),
(1122, 2, '2017-09-11 01:20:00.000', '2017-09-11 01:30:00.000'),
(1122, 3, '2017-09-11 03:10:00.000', '2017-09-11 03:20:00.000');
CREATE TABLE Table2
([ID] int, [number] int, [time_start_used] datetime, [time_stop_used] datetime)
;
INSERT INTO Table2
([ID], [number], [time_start_used], [time_stop_used])
VALUES
(965, 1, '2017-09-11 00:34:41.000', '2017-09-11 00:36:34.000'),
(965, 2, '2017-09-11 02:33:00.000', '2017-09-11 02:36:26.000'),
(965, 3, '2017-09-11 04:24:17.000', '2017-09-11 04:27:42.000'),
(965, 4, '2017-09-11 06:06:02.000', '2017-09-11 06:18:19.000'),
(965, 5, '2017-09-11 22:41:02.000', '2017-09-11 22:42:06.000'),
(1122, 1, '2017-09-11 00:15:12.000', '2017-09-11 00:15:32.000'),
(1122, 2, '2017-09-11 01:07:56.000', '2017-09-11 01:26:57.000'),
(1122, 3, '2017-09-11 01:49:02.000', '2017-09-11 01:51:13.000'),
(1122, 4, '2017-09-11 03:33:50.000', '2017-09-11 03:34:17.000'),
(1122, 5, '2017-09-11 04:07:59.000', '2017-09-11 04:09:10.000'),
(1122, 6, '2017-09-11 05:51:23.000', '2017-09-11 05:54:22.000')
;
Query:
select
coalesce(t1.id, t2.id) ids
, coalesce(t1.number, t2.number) numbers
, datediff(minute,t1.time_start_plan, t2.time_start_used) diff_start
, datediff(minute,t1.time_stop_plan, t2.time_stop_used) diff_stop
, t1.time_start_plan
, t2.time_start_used
, t1.time_stop_plan
, t2.time_stop_used
from table1 t1
full outer join table2 t2 on t1.id = t2.id and t1.number = t2.number
order by ids, numbers
Results:
| ids | numbers | diff_start | diff_stop | time_start_plan | time_start_used | time_stop_plan | time_stop_used |
|------|---------|------------|-----------|----------------------|----------------------|----------------------|----------------------|
| 965 | 1 | 34 | 21 | 2017-09-11T00:00:00Z | 2017-09-11T00:34:41Z | 2017-09-11T00:15:00Z | 2017-09-11T00:36:34Z |
| 965 | 2 | 78 | 71 | 2017-09-11T01:15:00Z | 2017-09-11T02:33:00Z | 2017-09-11T01:25:00Z | 2017-09-11T02:36:26Z |
| 965 | 3 | 104 | 97 | 2017-09-11T02:40:00Z | 2017-09-11T04:24:17Z | 2017-09-11T02:50:00Z | 2017-09-11T04:27:42Z |
| 965 | 4 | 106 | 108 | 2017-09-11T04:20:00Z | 2017-09-11T06:06:02Z | 2017-09-11T04:30:00Z | 2017-09-11T06:18:19Z |
| 965 | 5 | (null) | (null) | (null) | 2017-09-11T22:41:02Z | (null) | 2017-09-11T22:42:06Z |
| 1122 | 1 | 10 | -5 | 2017-09-11T00:05:00Z | 2017-09-11T00:15:12Z | 2017-09-11T00:20:00Z | 2017-09-11T00:15:32Z |
| 1122 | 2 | -13 | -4 | 2017-09-11T01:20:00Z | 2017-09-11T01:07:56Z | 2017-09-11T01:30:00Z | 2017-09-11T01:26:57Z |
| 1122 | 3 | -81 | -89 | 2017-09-11T03:10:00Z | 2017-09-11T01:49:02Z | 2017-09-11T03:20:00Z | 2017-09-11T01:51:13Z |
| 1122 | 4 | (null) | (null) | (null) | 2017-09-11T03:33:50Z | (null) | 2017-09-11T03:34:17Z |
| 1122 | 5 | (null) | (null) | (null) | 2017-09-11T04:07:59Z | (null) | 2017-09-11T04:09:10Z |
| 1122 | 6 | (null) | (null) | (null) | 2017-09-11T05:51:23Z | (null) | 2017-09-11T05:54:22Z |

SQL Server: - Split a Single Record and divide the Amount Values and insert as Rows

PROBLEM
Have been trying to work on this where for a particular From and ToDate, we need to take the difference between the Dates and the divide the Amount values by the difference and split the single record in Sample 1 to 5 rows in Resultant.
sr| Number |From_date|To_Date|Amount_1|Amount_2|Amount_3|Amount_4|Type
----------------------------------------------------------------------------
1 |20140911204120|Jan-14 |May-14 |5000 |2500 |1000 |200 |A
2 |20140911204122|Feb-14 |Apr-14 |6000 |3500 |2000 |1200 |R
3 |20140911204124|Feb-14 |Jun-14 |7000 |4500 |3000 |2200 |R
4 |20140911204126|Jul-14 |Sep-14 |8000 |5500 |4000 |3200 |R
5 |20140911204128|Mar-14 |Aug-14 |9000 |6500 |5000 |4200 |A
Resultant: - Record 1 after the process
So here in record 1
1. We subtract the From Date and the To Date which gives us 5.
2. We then Divide the Amount Values by 5 and split them as 5 rows and add the
row values for each individual month
--------------------------------------------------------------------
Sr| Number |Months |Amount_1|Amount_2|Amount_3|Amount_4|Type
--------------------------------------------------------------------
1 |20140911204120|January |1000 |500 |200 |10 |A
2 |20140911204120|February|1000 |500 |200 |10 |A
3 |20140911204120|March |1000 |500 |200 |10 |A
4 |20140911204120|April |1000 |500 |200 |10 |A
5 |20140911204120|May |1000 |500 |200 |10 |A
You didn't mention which version of SQL Server you are using, so I did this with 2012, but it should probably work on 2008 too if needed (although theTRY_CONVERTused for parsing dates has to be changed). Also, I'm guessing your sample desired output is wrong forAmount_4as 200/5=40 not 10.
Note that all the divisions are integer which meant potential loss of precision - if you need more precise values you have to cast to some appropriate type (decimal or float).
SQL Fiddle
MS SQL Server 2012 Schema Setup:
CREATE TABLE YourTable
([sr] int, [Number] bigint, [From_date] varchar(6), [To_date] varchar(6), [Amount_1] int, [Amount_2] int, [Amount_3] int, [Amount_4] int, [Type] varchar(1));
INSERT INTO YourTable ([sr], [Number], [From_date], [To_date], [Amount_1], [Amount_2], [Amount_3], [Amount_4], [Type])
VALUES
(1, 20140911204120, 'Jan-14', 'May-14', 5000, 2500, 1000, 200, 'A'),
(2, 20140911204122, 'Feb-14', 'Apr-14', 6000, 3500, 2000, 1200, 'R'),
(3, 20140911204124, 'Feb-14', 'Jun-14', 7000, 4500, 3000, 2200, 'R'),
(4, 20140911204126, 'Jul-14', 'Sep-14', 8000, 5500, 4000, 3200, 'R'),
(5, 20140911204128, 'Mar-14', 'Aug-14', 9000, 6500, 5000, 4200, 'A');
Query 1:
;WITH cte (Date, To_date, [Number], [Amount_1], [Amount_2], [Amount_3], [Amount_4], [Type]) AS
(
SELECT
Date = TRY_PARSE(From_date AS DATE),
To_date = TRY_PARSE(To_date AS DATE),
[Number],
[Amount_1],
[Amount_2],
[Amount_3],
[Amount_4],
[Type]
FROM YourTable
UNION ALL
SELECT
DATEADD(MONTH, 1, Date),
To_date,
[Number],
[Amount_1],
[Amount_2],
[Amount_3],
[Amount_4],
[Type]
FROM cte
WHERE Date < To_date
)
SELECT
Sr = ROW_NUMBER() OVER (PARTITION BY Number ORDER BY Number, Date),
Number,
Months,
Amount_1 = Amount_1/c,
Amount_2 = Amount_2/c,
Amount_3 = Amount_3/c,
Amount_4 = Amount_4/c,
Type
FROM (
SELECT
Number,
Months = DATENAME(MONTH, Date),
Date,
Amount_1,
Amount_2,
Amount_3,
Amount_4,
Type,
(SELECT COUNT(*) FROM cte WHERE Number = c.Number GROUP BY Number) AS c
FROM cte c
) a
ORDER BY Number, Date
OPTION (MAXRECURSION 1000)
Results:
| SR | NUMBER | MONTHS | AMOUNT_1 | AMOUNT_2 | AMOUNT_3 | AMOUNT_4 | TYPE |
|----|----------------|-----------|----------|----------|----------|----------|------|
| 1 | 20140911204120 | January | 1000 | 500 | 200 | 40 | A |
| 2 | 20140911204120 | February | 1000 | 500 | 200 | 40 | A |
| 3 | 20140911204120 | March | 1000 | 500 | 200 | 40 | A |
| 4 | 20140911204120 | April | 1000 | 500 | 200 | 40 | A |
| 5 | 20140911204120 | May | 1000 | 500 | 200 | 40 | A |
| 1 | 20140911204122 | February | 2000 | 1166 | 666 | 400 | R |
| 2 | 20140911204122 | March | 2000 | 1166 | 666 | 400 | R |
| 3 | 20140911204122 | April | 2000 | 1166 | 666 | 400 | R |
| 1 | 20140911204124 | February | 1400 | 900 | 600 | 440 | R |
| 2 | 20140911204124 | March | 1400 | 900 | 600 | 440 | R |
| 3 | 20140911204124 | April | 1400 | 900 | 600 | 440 | R |
| 4 | 20140911204124 | May | 1400 | 900 | 600 | 440 | R |
| 5 | 20140911204124 | June | 1400 | 900 | 600 | 440 | R |
| 1 | 20140911204126 | July | 2666 | 1833 | 1333 | 1066 | R |
| 2 | 20140911204126 | August | 2666 | 1833 | 1333 | 1066 | R |
| 3 | 20140911204126 | September | 2666 | 1833 | 1333 | 1066 | R |
| 1 | 20140911204128 | March | 1500 | 1083 | 833 | 700 | A |
| 2 | 20140911204128 | April | 1500 | 1083 | 833 | 700 | A |
| 3 | 20140911204128 | May | 1500 | 1083 | 833 | 700 | A |
| 4 | 20140911204128 | June | 1500 | 1083 | 833 | 700 | A |
| 5 | 20140911204128 | July | 1500 | 1083 | 833 | 700 | A |
| 6 | 20140911204128 | August | 1500 | 1083 | 833 | 700 | A |
You can join your table with a month table, to expend your data, that will be more efficient than recursive query.
SQLFiddle
;WITH months (month,month_name) AS
(select number,DATENAME(MONTH,cast(rtrim(20140000+number*100+1) as datetime))
from master..spt_values
where number between 1 and 12 AND TYPE='P'
)
SELECT Sr = ROW_NUMBER() OVER (PARTITION BY Number ORDER BY Number, month),
Number,
Month_name,
Amount_1 = Amount_1/(datediff(month,TRY_PARSE(from_date AS DATE),TRY_PARSE(to_date AS DATE))+1),
Amount_2 = Amount_2/(datediff(month,TRY_PARSE(from_date AS DATE),TRY_PARSE(to_date AS DATE))+1),
Amount_3 = Amount_3/(datediff(month,TRY_PARSE(from_date AS DATE),TRY_PARSE(to_date AS DATE))+1),
Amount_4 = Amount_4/(datediff(month,TRY_PARSE(from_date AS DATE),TRY_PARSE(to_date AS DATE))+1),
Type
FROM YourTable
JOIN Months
on month between datepart(month,TRY_PARSE(from_date AS DATE)) and datepart(month,TRY_PARSE(to_date AS DATE))

Resources