Hi I have a input table format like.
ID1 ID2 date
1002 9648 2011-01-02
1003 9648 2011-06-06
1004 9648 2012-08-08
1005 9648 2016-01-06
1006 9648 2016-09-12
1007 9648 2018-01-22
1009 9744 2009-10-03
1010 9744 2012-01-10
1011 9744 2016-09-23
1012 9744 2017-10-25
1013 9923 2006-10-10
1014 10124 2017-10-11
1015 10124 2018-01-24
am looking for an output table as shown below.
Could you please help me with a sql query or how it can be achieved in talend.
if no of days between two dates exceed 1096 which is approximately 3 years I want to take it as zero and update the type to new.
ID1 ID2 date daysdifference type
1002 9648 2011-01-02 0 new
1003 9648 2011-06-06 156 old
1004 9648 2012-08-08 429 old
1005 9648 2016-01-06 0 new
1006 9648 2016-09-12 250 old
1007 9648 2018-01-22 497 old
1009 9744 2009-10-03 0 new
1010 9744 2012-01-10 829 old
1011 9744 2016-09-23 0 new
1012 9744 2017-10-25 397 old
1013 9923 2006-10-10 0 new
1014 10124 2017-10-11 0 new
1015 10124 2018-01-24 91 old
Thanks,
Ankush Reddy.
You can use LAG function to get the desired result you want. Basically, LAG function access the data of the previous row. From there, you can now calculate the difference between the previous date and the current date using DATEDIFF function. However, this function exist starting version 2012.
SELECT ID1, ID2, Date,
DaysDifference = CASE WHEN PreviousDate IS NULL THEN 0 ELSE
CASE WHEN Date_Diff < 1096 THEN Date_Diff ELSE 0 END END,
CASE WHEN PreviousDate IS NULL THEN 'NEW' ELSE
CASE WHEN Date_Diff < 1096 THEN 'OLD' ELSE 'NEW' END END
FROM
(
SELECT *,
LAG(date, 1,NULL) OVER (PARTITION BY ID2 ORDER BY ID1) AS PreviousDate ,
DATEDIFF(DAY, LAG(date, 1,0) OVER (PARTITION BY ID2 ORDER BY ID1), date) Date_Diff
FROM TableA
) a
Here's a Demo.
However, if you are using version below 2012, you can still have the result you want using ROW_NUMBER()
;WITH rows AS
(
SELECT *,
RN = ROW_NUMBER() OVER (PARTITION BY ID2 ORDER BY ID1)
FROM TableA
)
SELECT ID1, ID2, Date,
DaysDifference = CASE WHEN PreviousDate IS NULL THEN 0 ELSE
CASE WHEN Date_Diff < 1096 THEN Date_Diff ELSE 0 END END,
CASE WHEN PreviousDate IS NULL THEN 'NEW' ELSE
CASE WHEN Date_Diff < 1096 THEN 'OLD' ELSE 'NEW' END END
FROM
(
SELECT a.ID1, a.ID2, a.Date, b.Date as PreviousDate,
DATEDIFF(DAY, b.date, a.date) Date_Diff
FROM rows a
LEFT JOIN rows b
ON a.RN = b.RN + 1
AND a.ID2 = b.ID2
) a
ORDER BY ID1, ID2
Here's a Demo.
Try this:
select [id1], [id2], [date],
case when [daysdifference] > 1096 then 0 else [daysdifference] end [daysdifference],
case when [daysdifference] > 1096 then 'new' else 'old' end [type]
from (
select *, abs(isnull(datediff(day, LAG([date], 1) over (order by id2, id1),
[date]), 0)) [daysdifference] from #x
) [a]
Related
My question involves how to identify an index discharge.
The index discharge is the earliest discharge. On that date, the 30 day window starts. Any admissions during that time period are considered readmissions, and they should be ignored. Once the 30 day window is over, then any subsequent discharge is considered an index and the 30 day window begins again.
I can't seem to work out the logic for this. I've tried different windowing functions, I've tried cross joins and cross applies. The issue I keep encountering is that a readmission cannot be an index admission. It must be excluded.
I have successfully written a while loop to solve this problem, but I'd really like to get this in a set based format, if it's possible. I haven't been successful so far.
Ultimate goal is this -
id
AdmitDate
DischargeDate
MedicalRecordNumber
IndexYN
1
2021-03-03 00:00:00.000
2021-03-09 13:20:00.000
X0090362
1
4
2021-03-05 00:00:00.000
2021-03-10 16:00:00.000
X0012614
1
6
2021-05-18 00:00:00.000
2021-05-21 22:20:00.000
X0012614
1
7
2021-06-21 00:00:00.000
2021-07-08 13:30:00.000
X0012614
1
8
2021-02-03 00:00:00.000
2021-02-09 17:00:00.000
X0019655
1
10
2021-03-23 00:00:00.000
2021-03-26 16:40:00.000
X0019655
1
11
2021-03-15 00:00:00.000
2021-03-18 15:53:00.000
X4135958
1
13
2021-05-17 00:00:00.000
2021-05-23 14:55:00.000
X4135958
1
15
2021-06-24 00:00:00.000
2021-07-13 15:06:00.000
X4135958
1
Sample code is below.
CREATE TABLE #Admissions
(
[id] INT,
[AdmitDate] DATETIME,
[DischargeDateTime] DATETIME,
[UnitNumber] VARCHAR(20),
[IndexYN] INT
)
INSERT INTO #Admissions
VALUES( 1 ,'2021-03-03' ,'2021-03-09 13:20:00.000' ,'X0090362', NULL)
,(2 ,'2021-03-27' ,'2021-03-30 19:59:00.000' ,'X0090362', NULL)
,(3 ,'2021-03-31' ,'2021-04-04 05:57:00.000' ,'X0090362', NULL)
,(4 ,'2021-03-05' ,'2021-03-10 16:00:00.000' ,'X0012614', NULL)
,(5 ,'2021-03-28' ,'2021-04-16 13:55:00.000' ,'X0012614', NULL)
,(6 ,'2021-05-18' ,'2021-05-21 22:20:00.000' ,'X0012614', NULL)
,(7 ,'2021-06-21' ,'2021-07-08 13:30:00.000' ,'X0012614', NULL)
,(8 ,'2021-02-03' ,'2021-02-09 17:00:00.000' ,'X0019655', NULL)
,(9 ,'2021-02-17' ,'2021-02-22 17:25:00.000' ,'X0019655', NULL)
,(10 ,'2021-03-23' ,'2021-03-26 16:40:00.000' ,'X0019655', NULL)
,(11 ,'2021-03-15' ,'2021-03-18 15:53:00.000' ,'X4135958', NULL)
,(12 ,'2021-04-08' ,'2021-04-13 19:42:00.000' ,'X4135958', NULL)
,(13 ,'2021-05-17' ,'2021-05-23 14:55:00.000' ,'X4135958', NULL)
,(14 ,'2021-06-09' ,'2021-06-14 12:45:00.000' ,'X4135958', NULL)
,(15 ,'2021-06-24' ,'2021-07-13 15:06:00.000' ,'X4135958', NULL)
You can use a recursive CTE to identify all rows associated with each "index" discharge:
with a as (
select a.*, row_number() over (order by dischargedatetime) as seqnum
from admissions a
),
cte as (
select id, admitdate, dischargedatetime, unitnumber, seqnum, dischargedatetime as index_dischargedatetime
from a
where seqnum = 1
union all
select a.id, a.admitdate, a.dischargedatetime, a.unitnumber, a.seqnum,
(case when a.dischargedatetime > dateadd(day, 30, cte.index_dischargedatetime)
then a.dischargedatetime else cte.index_dischargedatetime
end) as index_dischargedatetime
from cte join
a
on a.seqnum = cte.seqnum + 1
)
select *
from cte;
You can then incorporate this into an update:
update admissions
set indexyn = (case when admissions.dischargedatetime = cte.index_dischargedatetime then 'Y' else 'N' end)
from cte
where cte.id = admissions.id;
Here is a db<>fiddle. Note that I changed the type of IndexYN to a character to assign 'Y'/'N', which makes sense given the column name.
I'm trying to get the number of days difference in dates between the effdate status 0 that follows the most recent status 1
the code below yields the following results
SELECT * FROM
(SELECT FILEKEY, STATUS, EFFDATE FROM ASTATUSHIST
UNION
SELECT FILEKEY, ASTATUS, ASTATUSEFFDATE FROM USERS ) A
ORDER BY 1, 3 DESC
130 0 2019-10-25 00:00:00.000
130 0 2017-03-01 00:00:00.000
130 0 2017-01-01 00:00:00.000
130 1 2005-02-01 00:00:00.000
130 0 2001-03-03 00:00:00.000
130 0 2000-01-30 00:00:00.000
130 0 2000-01-01 00:00:00.000
this code combines 2 tables to get the complete history for a given user.
Ideally I could produce something that looks like this:
130 4352
or
125 null
where the null is filekey without a status 1 or a filekey with a status 1 but without a following status 0
Thanks
In all supported versions of SQL Server, you can use window functions:
with t as (
<your query here>
)
select t.*,
datediff(day, date, next_date) as days_diff
from (select t.*,
row_number() over (partition by filekey, status order by date desc) as seqnum,
lead(date) over (partition by filekey order by date) as next_date
from t
) t
where seqnum = 1;
Table 1: Daily attendance data:
att_date emp_code emp_name in_time out_time
2018-10-21 9999 Test 2018-10-21 08:00:00.000 2018-10-22 06:00:00.000
Table 2: Trnevents
emp_readr_id DT EVENTID
9999 2018-10-24 07:00:00.000 0
9999 2018-10-24 05:00:00.000 0
9999 2018-10-24 03:00:00.000 0
9999 2018-10-23 21:00:00.000 0
9999 2018-10-23 19:00:00.000 0
9999 2018-10-23 06:00:00.000 0
9999 2018-10-22 06:00:00.000 0
9999 2018-10-21 08:00:00.000 0
I used this query to get all times in between in time and out time ,below query works fine but i try to make in row by using pivot. While using pivot out time shows in next row.
declare #tempProcesstable as table(
[id] [nvarchar](200) NULL,
[time_stamp] datetime NULL,
[AccessType] varchar(3) NULL)
insert into #tempProcesstable
select distinct t1.emp_Reader_id, t1.DT,t1.eventid from daily_attendance_data t2 join trnevents t1
on t1.emp_reader_id=t2.emp_reader_id where (CONVERT(VARCHAR(26), t2.att_Date, 23) >=CONVERT(VARCHAR(26), '2018-10-20', 23)
and CONVERT(VARCHAR(26), t2.att_date, 23) <=CONVERT(VARCHAR(26), '2018-10-21', 23))
and
(t1.DT >=t2.in_time
and t1.DT <=t2.out_time)
-- and t1.emp_reader_id=1000
group by t1.emp_Reader_id,t1.dt,t1.eventid order by t1.emp_reader_id,DT asc
; With CheckIns
As (Select Rowemp_reader_id = Row_Number() Over (Partition by id, Cast(time_stamp As Date) Order By time_stamp),
id, time_stamp,
[Date] = Cast(time_stamp As Date),
[Time] = Cast(time_stamp As Time(0))
From #tempProcesstable)
Select Pvt.id,B.emp_name , [Date], CHECK1, CHECK2,Cast(dateadd(ss,datediff(ss,CHECK1,CHECK2),0) As Time(0)) Total1,
CHECK3, CHECK4,Cast(dateadd(ss,datediff(ss,CHECK3,CHECK4),0) As Time(0)) Total2
From (Select id, [Date], [Time],
CHECKNum = 'CHECK' + Cast(Rowemp_reader_id As varchar(11))
From CheckIns) As P
Pivot (Min([Time])
For CheckNum In (Check1, [Check2], Check3, Check4)
) As Pvt
LEFT OUTER JOIN
dbo.employee AS B ON Pvt.id= B.emp_reader_id
My output:
id emp_name Date CHECK1 CHECK2 Total1 CHECK3 CHECK4 Total2
1048 Singh 2018-10-21 07:06:07 17:34:05 10:27:58 NULL NULL NULL
9999 Test 2018-10-21 08:00:00 NULL NULL NULL NULL NULL NULL
9999 Test 2018-10-22 06:00:00 NULL NULL NULL NULL NULL NULL
Expected output:
I want all times between in time and out time in night to morning also.
can any one help me to rectify this.
id emp_name Date CHECK1 CHECK2 Total1 CHECK3 CHECK4 Total2
1048 Singh 2018-10-21 07:06:07 17:34:05 10:27:58 NULL NULL NULL
9999 Test 2018-10-21 08:00:00 06:00:00 NULL NULL NULL NULL NULL
You can try to use ROW_NUMBER() window function make row number by each date.
then use condition aggregate function to do pivot
SELECT emp_readr_id,
emp_name,
[Date],
MAX(CASE WHEN RN = 1 THEN time END) CHECK1,
MAX(CASE WHEN RN = 2 THEN time END) CHECK2,
MAX(CASE WHEN RN = 3 THEN time END) CHECK3,
MAX(CASE WHEN RN = 4 THEN time END) CHECK4
FROM (
SELECT emp_readr_id,
emp_name,
CONVERT(VARCHAR(10),DT,120) 'Date',
ROW_NUMBER() OVER(PARTITION BY CONVERT(VARCHAR(10),DT,120) ORDER BY DT) rn,
CONVERT(VARCHAR(10),DT,108) time
FROM Daily d
JOIN Trnevents t on t.DT between d.in_time and d.out_time
) t1
group by emp_readr_id,
emp_name,
[Date]
sqlifddle
I Have a OPL_Dates Table with Start Date and End Dates as Below:
dbo.OPL_Dates
ID Start_date End_date
--------------------------------------
12345 1975-01-01 2001-12-31
12345 1989-01-01 2004-12-31
12345 2005-01-01 NULL
12345 2007-01-01 NULL
12377 2009-06-01 2009-12-31
12377 2013-02-07 NULL
12377 2010-01-01 2012-01-01
12489 2011-12-31 NULL
12489 2012-03-01 2012-04-01
The Output I am looking for is:
ID Start_date End_date
-------------------------------------
12345 1975-01-01 2004-12-31
12345 2005-01-01 NULL
12377 2009-06-01 2009-12-31
12377 2010-01-01 2012-01-01
12377 2013-02-07 NULL
12489 2011-12-31 NULL
Basically, I want to show the gap between the OPL periods(IF Any) else I need min of Start Date and Max of End Dates, for a particular ID.NULL means Open-Ended Date which can be converted to "9999-12-31".
The following pretty much does what you want:
with p as (
select v.*, sum(inc) over (partition by v.id order by v.dte) as running_inc
from t cross apply
(values (id, start_date, 1),
(id, coalesce(end_date, '2999-12-31'), -1)
) v(id, dte, inc)
)
select id, min(dte), max(dte)
from (select p.*, sum(case when running_inc = 0 then 1 else 0 end) over (partition by id order by dte desc) as grp
from p
) p
group by id, grp;
Note that it changes the "inifinite" end date from NULL to 2999-12-31. This is a convenience, because NULL orders first in SQL Server ascending sorts.
Here is a SQL Fiddle.
What is this doing? It is unpivoting the dates into a single column, with a 1/-1 flag (inc) indicating whether the record is a start or end. The running sum of this flag then indicates the groups that should be combined. When the running sum is 0, then a group has ended. To include the end date in the right group, a reverse running sum is needed -- but that's a detail.
I have a set of data that looks like this I want to remove one row for each of the debnrs that has a p in it for type. I don't care which one. The two rows with P in the type are identical except for the date. How would I select just one with a P in the type.
debnr docno date type num amount
4 NULL 2013-08-29 07:26:25.000 P 1761 -12
4 NULL 2013-09-12 00:00:00.000 P 1761 -12
4 168371 2013-08-29 00:00:00.000 I 168371 12
5 NULL 2013-10-11 09:24:58.000 P 7287 -24
5 NULL 2013-10-14 00:00:00.000 P 7287 -24
5 170366 2013-10-11 00:00:00.000 I 170366 24
6 NULL 2013-10-24 00:00:00.000 P 4023 -465
6 NULL 2013-10-24 09:42:18.000 P 4023 -465
6 171095 2013-10-24 00:00:00.000 I 171095 465
7 NULL 2013-12-16 00:00:00.000 P 171502 -394.2
7 NULL 2013-12-16 00:00:00.000 P 6601 -394.2
7 171502 2013-10-30 00:00:00.000 I 171502 394.2
how would I get it to look like this.
4 NULL 2013-09-12 00:00:00.000 P 1761 -12
4 168371 2013-08-29 00:00:00.000 I 168371 12
5 NULL 2013-10-14 00:00:00.000 P 7287 -24
5 170366 2013-10-11 00:00:00.000 I 170366 24
6 NULL 2013-10-24 09:42:18.000 P 4023 -465
6 171095 2013-10-24 00:00:00.000 I 171095 465
7 NULL 2013-12-16 00:00:00.000 P 6601 -394.2
7 171502 2013-10-30 00:00:00.000 I 171502 394.2
Shot in the dark:
select
debnr,
docno,
max(date),
type,
num,
amount
from magical_table
group by
debnr,
docno,
type,
num,
amount
You could GROUP and use an aggregate given your sample above, if however the amount field weren't identical, for instance, then you could use the ROW_NUMBER() function for this to avoid needing an aggregate:
;WITH cte AS (SELECT *
,CASE WHEN TYPE = 'P' THEN ROW_NUMBER() OVER(PARTITION BY debnr ORDER BY (SELECT 1))
ELSE 0
END AS RN
FROM Table1)
SELECT *
FROM cte
WHERE RN <= 1
Demo: SQL Fiddle
The ORDER BY (SELECT 1) could be changed to any field, that's just one way to get an arbitrary result if you don't want a min/max.
Want you line with type "I" ungrouped ?
select debnr, docno, max(date), type, num, amount
from magical_table
where type = "P"
group by debnr, docno, type, num, amount
UNION
select debnr, docno, date, type, num, amount
from magical_table
where type = "I"