SQL Cut Stretch Date into various stretchs - sql

I have a large stretch of dates in one table and some dates to cut in other table.
With this I need to get another table with all the stretchs inside the large one cut by the others dates.
I have this for the moment:
DECLARE #UTCSTARTDATE DATETIME='2020-01-20 00:00:00.00'
DECLARE #UTCENDDATE DATETIME='2020-01-20 04:00:00.00'
DECLARE #T1 TABLE
(
StartTime DATETIME,
EndTime DATETIME,
table_id int
)
DECLARE #T2 TABLE
(
CutTime DATETIME,
table2_id int
)
INSERT INTO #T1 SELECT #UTCSTARTDATE,#UTCENDDATE,1
INSERT INTO #T2 SELECT myCut,myID FROM (VALUES('2020-01-20 01:00:00.00',1),('2020-01-20 02:30:00.00',1),('2020-01-20 03:00:00.00',2))t2(myCut,myID)
SELECT * FROM #T1
SELECT * FROM #T2 order by CutTime ASC
DECLARE #STRETCHHOURSTABLE TABLE
(
startDate DATETIME,
endDate DATETIME
);
;WITH DATESPLITTER AS
(
SELECT
StartTime AS stretchStartDate,
(SELECT TOP(1) CutTime FROM #T2 where CutTime < EndTime AND table_id = table2_id order by CutTime ASC) AS stretchEndDate,
EndTime AS RealEndTime,
table_id AS RealID
FROM #T1
UNION ALL
SELECT
stretchEndDate,
(SELECT TOP(1) CutTime FROM #T2 where CutTime > stretchEndDate AND CutTime < RealEndTime AND table2_id = RealID order by CutTime ASC) AS stretchEndDate,
RealEndTime,
RealID
FROM DATESPLITTER
WHERE stretchEndDate < #UTCENDDATE
)
INSERT INTO #STRETCHHOURSTABLE (startDate, endDate)
SELECT
stretchStartDate,
CASE
WHEN #UTCENDDATE < stretchEndDate THEN #UTCENDDATE
ELSE stretchEndDate
END
FROM DATESPLITTER
SELECT * FROM #STRETCHHOURSTABLE

This seems to basically be lead() after union all:
select dt, lead(dt) over (order by dt)
from ((select v.dt
from #t1 t1 cross apply
(values (t1.startTime), (t1.endTime)) v(dt)
) union all
(select t2.cuttime
from #t2 t2
)
) t
Here is a db<>fiddle.

Try this, I have made changes:
DECLARE #UTCSTARTDATE DATETIME='2020-01-20 00:00:00.00'
DECLARE #UTCENDDATE DATETIME='2020-01-20 04:00:00.00'
DECLARE #T1 TABLE( StartTime DATETIME, EndTime DATETIME, table_id int);
DECLARE #T2 TABLE ( CutTime DATETIME, table2_id int);
INSERT INTO #T1 SELECT #UTCSTARTDATE,#UTCENDDATE,1
INSERT INTO #T2 VALUES('2020-01-20 01:00:00.00',1),('2020-01-20 02:30:00.00',1),('2020-01-20 03:00:00.00',2);
SELECT * FROM #T1
SELECT * FROM #T2 order by CutTime ASC;
DECLARE #STRETCHHOURSTABLE TABLE (startDate DATETIME, endDate DATETIME);
WITH DATESPLITTER AS
(
SELECT
StartTime AS stretchStartDate,
(select cuttime from (SELECT row_number() over(partition by table2_id order by CutTime ASC) rn, CutTime FROM #T2 where CutTime < EndTime AND table_id = table2_id)a
where a.rn = 1) AS stretchEndDate,
EndTime AS RealEndTime,
table_id AS RealID
FROM #T1
UNION ALL
SELECT
stretchEndDate,
ISNULL((select cuttime from (SELECT row_number() over(partition by table2_id order by CutTime ASC) rn, CutTime FROM #T2 where CutTime > stretchEndDate AND CutTime < RealEndTime AND table2_id = RealID)a
where a.rn = 1), RealEndTime) AS stretchEndDate,
RealEndTime,
RealID
FROM DATESPLITTER
WHERE stretchEndDate < #UTCENDDATE
)
INSERT INTO #STRETCHHOURSTABLE (startDate, endDate)
SELECT stretchStartDate,
CASE
WHEN #UTCENDDATE < stretchEndDate THEN #UTCENDDATE
ELSE stretchEndDate
END as sommm
FROM DATESPLITTER
SELECT * FROM #STRETCHHOURSTABLE

Related

Sum of last 6 rows for same day as today in SQL Server

I need to calculate sum of past six rows for same day for given id.
Have a look at the sample data and result expected..
create table #t (id int, a datetime, dy varchar(10), t int);
insert into #t values
(1,'2017-01-03','Tuesday',7),
(1,'2017-01-10','Tuesday',5),
(1,'2017-01-17','Tuesday',5),
(1,'2017-01-24','Tuesday',2),
(1,'2017-01-31','Tuesday',6),
(1,'2017-02-07','Tuesday',4),
(1,'2017-02-14','Tuesday',5),
(1,'2017-02-21','Monday',2),
(1,'2017-02-28','Monday',4),
(1,'2017-03-07','Monday',4),
(1,'2017-03-17','Monday',4),
(1,'2017-03-21','Monday',4);
(1,'2017-03-2','Monday',4);
create table #t_result (id int, a datetime, dy varchar(10),t int);
insert into #t_result values
(1,'2017-01-03','Tuesday',29),
(1,'2017-02-14','Monday',22)
select * from #t
select * from #t_result
Thanks in advance
You can do some window function manipulation and output every 6th row (modulo operator on ROW_NUMBER).
SELECT
id, a, [sum]
FROM
(
SELECT
id
, FIRST_VALUE( a ) OVER (ORDER BY a ROWS 5 PRECEDING) AS a
, SUM( t ) OVER (ORDER BY a ROWS 5 PRECEDING) AS [sum]
, ROW_NUMBER() OVER (ORDER BY a) AS rownum
FROM
#t
) AS data
WHERE
rownum % 6 = 0
--Try Using While Loop
BEGIN TRAN
CREATE TABLE #t (id INT, a DATETIME ,dy VARCHAR(10), t INT);
CREATE TABLE #t_result (id INT, a DATETIME,dy VARCHAR(10),t INT);
CREATE TABLE #Temp (id INT, a DATETIME, t INT, dy VARCHAR(10),temp_count INT);
INSERT INTO #T VALUES
(1,'2017-01-03','Thursday',7),
(1,'2017-01-10','Thursday',5),
(1,'2017-01-17','Thursday',5),
(1,'2017-01-24','Thursday',2),
(1,'2017-01-31','Thursday',6),
(1,'2017-02-07','Thursday',4),
(1,'2017-02-14','Thursday',5),
(1,'2017-02-21','Monday',2),
(1,'2017-02-28','Monday',4),
(1,'2017-03-07','Monday',4),
(1,'2017-03-17','Monday',4),
(1,'2017-03-21','Monday',4),
(1,'2017-03-2' ,'Monday',4)
DECLARE #Strt INT,#End INT
SELECT *, ROW_NUMBER()OVER(ORDER BY ID)rownum INTO #Temp_data FROM #t
SET #Strt=1
SELECT #End= MAX(rownum) FROM #Temp_data
WHILE #Strt<= #End BEGIN
DECLARE #Id INT , #T INT , #Date DATETIME, #total INT, #count INT, #Temp_count INT, #D DATETIME, #Dy VARCHAR(10)
SELECT #Id= Id, #T=t, #Dy=dy, #Date= a FROM #Temp_data WHERE rownum= #Strt
INSERT INTO #Temp
SELECT #Id, #Date, #T, #Dy,1
SELECT #Temp_count= COUNT(*) FROM #Temp
IF #Temp_count=6 BEGIN
SELECT *,ROW_NUMBER()OVER(Order by ID)rownum INTO #tt FROM #Temp
SELECT #D=a FROM #tt WHERE rownum=1
INSERT INTO #t_result
SELECT ID, #D,dy,SUM(t)
FROM #Temp
WHERE DATEPART(yyyy, a) = YEAR(DATEADD(year,-1,GETDATE()))AND dy = DATENAME(DW,GETDATE())
GROUP BY id,dy
HAVING COUNT(*)=6
DELETE FROM #Temp
DROP TABLE #tt
END
SET #Strt= #Strt +1
END
SELECT * FROM #t_result
ROLLBACK TRAN
Try this:
SELECT MIN(D.id)Id,MIN(D.a)a,D.dy,SUM(D.t)T
FROM(
select *,ROW_NUMBER() OVER(PARTITION BY id,dy ORDER BY a)RN
from #t
)D
WHERE D.RN<=6
GROUP BY D.dy
ORDER BY a
OutPut:
Id a dy T
1 2017-01-03 00:00:00.000 Tuesday 29
1 2017-02-21 00:00:00.000 Monday 22

how to join two tables in hive with unique value in column

I have two tables in hive, table1 and table2 with the following values:
TABLE1:........................................TABLE2:
date.................value.....................date.....................value
'2016-01-01'....one.......................'2016-01-01'..........two
'2016-01-01'....three.....................'2016-01-01'..........four
'2016-01-01'....five
and I need to join both tables to create a third table as (with three rows) :
date.......................value1...........................value2
'2016-01-01'..........one................................two
'2016-01-01'..........three..............................four
'2016-01-01'..........five
I have tried many options but none of them worked.
Any idea.
DECLARE #table1 TABLE ([Date] Date, [Value] VarChar(10))
DECLARE #table2 TABLE ([Date] Date, [Value] VarChar(10))
INSERT INTO #table1([Date], [Value])
SELECT '2016-01-01', 'one'
UNION ALL
SELECT '2016-01-01', 'three'
UNION ALL
SELECT '2016-01-01', 'five'
INSERT INTO #table2([Date], [Value])
SELECT '2016-01-01', 'two'
UNION ALL
SELECT '2016-01-01', 'four'
SELECT [Date] = t1.[Date],
[Value1] = t1.[Value],
[Value2] = t3.[Value]
FROM
(SELECT [Date] = t.[Date],
[Value] = t.[Value],
[ID] = ROW_NUMBER() OVER(ORDER BY t.[Date] DESC)
FROM #table1 t) t1
OUTER APPLY
(
SELECT TOP 1 t2.[Value]
FROM
(SELECT [Date] = t.[Date],
[Value] = t.[Value],
[ID] = ROW_NUMBER() OVER(ORDER BY t.[Date] DESC)
FROM #table2 t) t2
WHERE t2.[Date] = t1.[Date]
AND t2.[ID] = t1.[ID]
) t3

Selection One Entry Only As Non Zero In SQl Select

I have a scenario where I have to select multiple rows from table, I have multiple rows of one record but with different status,
at times I have two identical rows with identical data for status < for that case I canted to select Non zero for the first occurrence and set 0 for the remaining occurrences.
Below is the Image to show and I have marked strike-out and marked 0 for the remaining occurrence.
And body could suggest better SQL Query:
Here is the Query: I am getting zero value for status 1 for ID =1 but I need to show first as regular and then 0 if that status repeats again.
CREATE TABLE #Temp
(ID INT,
ItemName varchar(10),
Price Money,
[Status] INT,
[Date] Datetime)
INSERT INTO #Temp VALUES(1,'ABC',10,1,'2014-08-27')
INSERT INTO #Temp VALUES(1,'ABC',10,2,'2014-08-27')
INSERT INTO #Temp VALUES(1,'ABC',10,1,'2014-08-28')
INSERT INTO #Temp VALUES(2,'DEF',25,1,'2014-08-26')
INSERT INTO #Temp VALUES(2,'DEF',25,3,'2014-08-27')
INSERT INTO #Temp VALUES(2,'DEF',25,1,'2014-08-28')
INSERT INTO #Temp VALUES(3,'GHI',30,1,'2014-08-27')
SELECT CASE WHEN Temp.Status = 1 THEN
0
ELSE
Temp.Price END AS Price,
* FROM (SELECT * FROM #Temp) Temp
DROP TABLE #Temp
Here is the result:
You might modify your inner select using Row_Number() and set price to Zero for RowNumber > 1.
SELECT CASE WHEN Temp.RowNumber > 1 THEN
0
ELSE
Temp.Price END AS Price,
* FROM (
SELECT *,Row_Number() over (PARTITION by ID,Status ORDER BY ID,Date) AS 'RowNumber'
FROM #Temp
) Temp
Order by ID,Date
You can try this:
;WITH DataSource AS
(
SELECT RANK() OVER (PARTITION BY [ID], [ItemName], [Price], [Status] ORDER BY Date) AS [RankID]
,*
FROM #Temp
)
SELECT [ID]
,[ItemName]
,IIF([RankID] = 1, [Price], 0)
,[Status]
,[Date]
FROM DataSource
ORDER BY [ID]
,[Date]
Here is the output:
please try this below code . it is working for me.
CREATE TABLE #Temp
(ID INT,
ItemName varchar(10),
Price Money,
[Status] INT,
[Date] Datetime)
INSERT INTO #Temp VALUES(1,'ABC',10,1,'2014-08-27')
INSERT INTO #Temp VALUES(1,'ABC',10,2,'2014-08-27')
INSERT INTO #Temp VALUES(1,'ABC',10,1,'2014-08-28')
INSERT INTO #Temp VALUES(2,'DEF',25,1,'2014-08-26')
INSERT INTO #Temp VALUES(2,'DEF',25,3,'2014-08-27')
INSERT INTO #Temp VALUES(2,'DEF',25,1,'2014-08-28')
INSERT INTO #Temp VALUES(3,'GHI',30,1,'2014-08-27')
select *,case when a.rn=1 and status!=2 then price else 0 end as price from
(select *,ROW_NUMBER() over(partition by status,date order by date asc) rn from #Temp) a
order by ItemName asc
You can do this with UNION:
SELECT * FROM #Temp t
WHERE NOT EXISTS
(SELECT * FROM #Temp
WHERE t.id = id and t.status = status and t.date < date)
UNION ALL
SELECT ID, ItemName, 0 as Price, status, date
WHERE EXISTS
(SELECT * FROM #Temp
WHERE t.id = id and t.status = status and t.date < date)
Or subquery:
SELECT CASE
WHEN (SELECT COUNT(*)
FROM #Temp
WHERE t.id = id and t.status = status
and t.date > date) > 1 THEN 0 ELSE price END as NewPrice, t.*
FROM #Temp t
Or possibly RANK() function:
SELECT CASE
WHEN RANK() OVER (PARTITION BY id, status ORDER BY date) > 1
THEN 0 ELSE Price END,
t.*
FROM #Temp t

SQL: Remove duplicates

How do I remove duplicates from a table that is set up in the following way?
unique_ID | worker_ID | date | type_ID
A worker can have multiple type_ID's associated with them and I want to remove any duplicate types. If there is a duplicate, I want to remove the type with the most recent entry.
A textbook candidate for the window function row_number():
;WITH x AS (
SELECT unique_ID
,row_number() OVER (PARTITION BY worker_ID,type_ID ORDER BY date) AS rn
FROM tbl
)
DELETE FROM tbl
FROM x
WHERE tbl.unique_ID = x.unique_ID
AND x.rn > 1
This also takes care of the situation where a set of dupes on (worker_ID,type_ID) shares the same date.
See the simplified demo on data.SE.
Update with simpler version
Turns out, this can be simplified: In SQL Server you can delete from the CTE directly:
;WITH x AS (
SELECT unique_ID
,row_number() OVER (PARTITION BY worker_ID,type_ID ORDER BY date) AS rn
FROM tbl
)
DELETE x
WHERE rn > 1
delete from table t
where exists ( select 1 from table t2
where t2.worker_id = t.worker_id
and t2.type_id = t.type_id
and t2.date < t.date )
HTH
DELETE FROM #t WHERE unique_Id IN
(
SELECT unique_Id FROM
(
SELECT unique_Id
,Type_Id
,ROW_NUMBER() OVER (PARTITION BY worker_Id, type_Id ORDER BY date) AS rn
FROM #t
) Q
WHERE rn > 1
)
And to test...
DECLARE #t TABLE
(
unique_ID INT IDENTITY,
worker_ID INT,
date DATETIME,
type_ID INT
)
INSERT INTO #t VALUES (1, DATEADD(DAY, 1, GETDATE()), 1)
INSERT INTO #t VALUES (1, GETDATE(), 1)
INSERT INTO #t VALUES (2, GETDATE(), 1)
INSERT INTO #t VALUES (1, DATEADD(DAY, 2, GETDATE()), 1)
INSERT INTO #t VALUES (1, DATEADD(DAY, 3, GETDATE()), 2)
SELECT * FROM #t
DELETE FROM #t WHERE unique_Id IN
(
SELECT unique_Id FROM
(
SELECT unique_Id
,Type_Id
,ROW_NUMBER() OVER (PARTITION BY worker_Id, type_Id ORDER BY date) AS rn
FROM #t
) Q
WHERE rn > 1
)
SELECT * FROM #t
you may use this query
delete from worker where unique_id in (
select max(unique_id) from worker group by worker_ID , type_ID having count(type_id)>1)
here i am assuming worker as your table name

Query to merge continuous temporal records

I have a table like this:
id START_DATE end_date
1 01/01/2011 01/10/2011
2 01/11/2011 01/20/2011
3 01/25/2011 02/01/2011
4 02/10/2011 02/15/2011
5 02/16/2011 02/27/2011
I want to merge the records where the start_date is just next day of end_date of another record: So the end record should be something like this:
new_id START_DATE end_date
1 01/01/2011 01/20/2011
2 01/25/2011 02/01/2011
3 02/10/2011 02/27/2011
One way that I know to do this will be to create a row based temp table with various rows as dates (each record for one date, between the total range of days) and thus making the table flat.
But there has to be a cleaner way to do this in a single query... e.g. something using row_num?
Thanks guys.
declare #T table
(
id int,
start_date datetime,
end_date datetime
)
insert into #T values
(1, '01/01/2011', '01/10/2011'),
(2, '01/11/2011', '01/20/2011'),
(3, '01/25/2011', '02/01/2011'),
(4, '02/10/2011', '02/15/2011'),
(5, '02/16/2011', '02/27/2011')
select row_number() over(order by min(dt)) as new_id,
min(dt) as start_date,
max(dt) as end_date
from (
select dateadd(day, N.Number, start_date) as dt,
dateadd(day, N.Number - row_number() over(order by dateadd(day, N.Number, start_date)), start_date) as grp
from #T
inner join master..spt_values as N
on N.number between 0 and datediff(day, start_date, end_date) and
N.type = 'P'
) as T
group by grp
order by new_id
You can use a numbers table instead of using master..spt_values.
Try This
Declare #chgRecs Table
(updId int primary key not null,
delId int not null,
endt datetime not null)
While Exists (Select * from Table a
Where Exists
(Select * from table
Where start_date =
DateAdd(day, 1, a.End_Date)))
Begin
Insert #chgRecs (updId, delId , endt)
Select a.id, b.id, b.End_Date,
From table a
Where Exists
(Select * from table
Where start_date =
DateAdd(day, 1, a.End_Date)))
And Not Exists
(Select * from table
Where end_Date =
DateAdd(day, -1, a.Start_Date)))
Delete table Where id In (Select delId from #chgRecs )
Update table set
End_Date = u.endt
From table t join #chgRecs u
On u.updId = t.Id
Delete #delRecs
End
No, was not looking for a loop...
I guess this is a good solution:
taking all the data in a #temp table
SELECT * FROM #temp
SELECT t2.start_date , t1.end_date FROM #temp t1 JOIN #temp t2 ON t1.start_date = DATEADD(DAY,1,t2.end_date)
UNION
SELECT START_DATE,end_date FROM #temp WHERE start_date NOT IN (SELECT t2.START_DATE FROM #temp t1 JOIN #temp t2 ON t1.start_date = DATEADD(DAY,1,t2.end_date))
AND end_date NOT IN (SELECT t1.end_Date FROM #temp t1 JOIN #temp t2 ON t1.start_date = DATEADD(DAY,1,t2.end_date))
DROP TABLE #temp
Please let me know if there is anything better than this.
Thanks guys.
A recursive solution:
CREATE TABLE TestData
(
Id INT PRIMARY KEY,
StartDate DATETIME NOT NULL,
EndDate DATETIME NOT NULL
);
SET DATEFORMAT MDY;
INSERT TestData
SELECT 1, '01/01/2011', '01/10/2011'
UNION ALL
SELECT 2, '01/11/2011', '01/20/2011'
UNION ALL
SELECT 3, '01/25/2011', '02/01/2011'
UNION ALL
SELECT 4, '02/10/2011', '02/15/2011'
UNION ALL
SELECT 5, '02/16/2011', '02/27/2011'
UNION ALL
SELECT 6, '02/28/2011', '03/06/2011'
UNION ALL
SELECT 7, '02/28/2011', '03/03/2011'
UNION ALL
SELECT 8, '03/10/2011', '03/18/2011'
UNION ALL
SELECT 9, '03/19/2011', '03/25/2011';
WITH RecursiveCTE
AS
(
SELECT t.Id, t.StartDate, t.EndDate
,1 AS GroupID
FROM TestData t
WHERE t.Id=1
UNION ALL
SELECT crt.Id, crt.StartDate, crt.EndDate
,CASE WHEN DATEDIFF(DAY,prev.EndDate,crt.StartDate)=1 THEN prev.GroupID ELSE prev.GroupID+1 END
FROM TestData crt
JOIN RecursiveCTE prev ON crt.Id-1=prev.Id
--WHERE crt.Id > 1
)
SELECT cte.GroupID, MIN(cte.StartDate) AS StartDate, MAX(cte.EndDate) AS EndDate
FROM RecursiveCTE cte
GROUP BY cte.GroupID
ORDER BY cte.GroupID;
DROP TABLE TestData;