Substract date from previous row by group SQL query - sql-server

Data
id date
2380 10/30/12 09:00:00
2380 10/30/12 09:05:00
2380 10/30/12 09:10:00
2380 10/30/12 09:15:00
2381 10/30/12 10:00:00
2381 10/30/12 10:05:00
2381 10/30/12 10:10:00
2381 10/30/12 10:15:00
2382 10/30/12 11:00:00
2382 10/30/12 11:05:00
2382 10/30/12 10:10:00
2382 10/30/12 10:15:00
and I want the following solution
id date duration
2380 10/30/12 09:00:00 00:00:00
2380 10/30/12 09:05:00 00:05:00
2380 10/30/12 09:10:00 00:10:00
2380 10/30/12 09:15:00 00:15:00
2381 10/30/12 10:00:00 00:00:00
2381 10/30/12 10:05:00 00:05:00
2381 10/30/12 10:10:00 00:10:00
2381 10/30/12 10:15:00 00:15:00
2382 10/30/12 11:00:00 00:00:00
2382 10/30/12 11:05:00 00:05:00
2382 10/30/12 10:10:00 00:10:00
2382 10/30/12 10:15:00 00:10:00
I have tried to understand the logic behind the following thread but it's difficult to understand.
Substract date from previous row by group (using R)
select id, date, date - (select min(date) from date group by id) as duration
from date
Closest I have got is for one id.

Try this below example hope this is what you are looking as output,
declare #t1 table
(
id int,
dtdate datetime
)
insert into #t1 values(2380,'10/30/12 09:00:00')
insert into #t1 values(2380,'10/30/12 09:05:00')
insert into #t1 values(2380,'10/30/12 09:10:00')
insert into #t1 values(2380,'10/30/12 09:15:00')
insert into #t1 values(2381,'10/30/12 10:00:00')
insert into #t1 values(2381,'10/30/12 10:05:00')
insert into #t1 values(2381,'10/30/12 10:10:00')
insert into #t1 values(2381,'10/30/12 10:15:00')
insert into #t1 values(2382,'10/30/12 11:00:00')
insert into #t1 values(2382,'10/30/12 11:05:00')
insert into #t1 values(2382,'10/30/12 10:10:00')
insert into #t1 values(2382,'10/30/12 10:15:00')
;WITH CTE AS (
SELECT
rownum = ROW_NUMBER() OVER (partition by id ORDER BY id,dtDate),
id,dtDate
FROM #t1 p
)
SELECT
a.id,
a.dtDate,
CASE WHEN prev.dtdate is NULL THEN '00:00:00' ELSE convert(nvarchar(8),a.dtdate- prev.dtdate,108) END as duration
FROM CTE a
LEFT JOIN CTE prev ON a.id = prev.id AND prev.rownum = a.rownum - 1

The key to my approach is to find the minimum date value for each id which I refer to as the ReferenceDate. Then I join the main table to that and do the date math with the DATEDIFF() function and transform the results to hh:mi:ss with the CONVERT() function using style 108. Here is the dbfiddle.
IF OBJECT_ID('tempdb.dbo.#MyTable', 'U') IS NOT NULL
DROP TABLE #MyTable;
CREATE TABLE #MyTable
(
id INTEGER NOT NULL
, date DATETIME NOT NULL
);
INSERT INTO #MyTable (id, date) VALUES (2380, '10/30/12 09:00:00');
INSERT INTO #MyTable (id, date) VALUES (2380, '10/30/12 09:05:00');
INSERT INTO #MyTable (id, date) VALUES (2380, '10/30/12 09:10:00');
INSERT INTO #MyTable (id, date) VALUES (2380, '10/30/12 09:15:00');
INSERT INTO #MyTable (id, date) VALUES (2381, '10/30/12 10:00:00');
INSERT INTO #MyTable (id, date) VALUES (2381, '10/30/12 10:05:00');
INSERT INTO #MyTable (id, date) VALUES (2381, '10/30/12 10:10:00');
INSERT INTO #MyTable (id, date) VALUES (2381, '10/30/12 10:15:00');
INSERT INTO #MyTable (id, date) VALUES (2382, '10/30/12 11:00:00');
INSERT INTO #MyTable (id, date) VALUES (2382, '10/30/12 11:05:00');
INSERT INTO #MyTable (id, date) VALUES (2382, '10/30/12 10:10:00');
INSERT INTO #MyTable (id, date) VALUES (2382, '10/30/12 10:15:00');
INSERT INTO #MyTable (id, date) VALUES (2382, '10/30/12 12:15:00');
INSERT INTO #MyTable (id, date) VALUES (2382, '10/30/12 10:15:30');
SELECT a.*
, CONVERT(NVARCHAR(8), a.date - b.ReferenceDate, 108) AS duration
FROM #MyTable AS a
INNER JOIN (
SELECT id, MIN(date) AS ReferenceDate
FROM #MyTable GROUP BY id) AS b ON a.id = b.id;

Related

Want Result from one to many relation table by Group By

I would like to get result by "group by" but not luck. I can see other option but looking best perfomance query.
Thanks in Advance !
CREATE TABLE #Invoice (InvoiceId int, InvoiceDate datetime, NetAmount
decimal(18,2))
CREATE TABLE #Payment (PaymentId int, InvoiceId int, PaidAmount
decimal(18,2))
INSERT INTO #Invoice VALUES (101, '20180212', 5000)
INSERT INTO #Invoice VALUES (102, '20180112', 600)
INSERT INTO #Invoice VALUES (103, '20181211', 1800)
INSERT INTO #Invoice VALUES (104, '20180101', 1000)
INSERT INTO #Invoice VALUES (105, '20180212', 7000)
INSERT INTO #Payment VALUES (101,103,1800)
INSERT INTO #Payment VALUES (102,102,500)
INSERT INTO #Payment VALUES (103,101,2000)
INSERT INTO #Payment VALUES (103,101,3000)
Create this query :
SELECT
INV.InvoiceDate,
SUM(Inv.NetAmount) as NetAmount,
SUM(ISNULL(PY.PaidAmount,0)) As PaidAmount
From #Invoice INV
LEFT JOIN #Payment PY
ON PY.InvoiceId = INV.InvoiceId
GROUP BY
INV.InvoiceDate
Get Result :
InvoiceDate NetAmount PaidAmount
2018-01-01 1000.00 0.00
2018-01-12 600.00 500.00
2018-02-12 17000.00 5000.00 ****Issue: Net values should be 12000 not 17000
2018-12-11 1800.00 1800.00
Expected Result :
InvoiceDate NetAmount PaidAmount
2018-01-01 1000.00 0.00
2018-01-12 600.00 500.00
2018-02-12 5000.00 5000.00
2018-12-11 1800.00 1800.00
This assumes that the expected results the OP has provided is wrong. They have the value 5000 for the NetAmount on 20180212, however there are 2 invoices on that date with the values 5000 and 7000, making 12000. If 5000 is correct, we need details on why the value of invoice 105 (7000) is not to be included.
Anyway, on the assumption the expected results is wrong, this gets the result I believe you are looking for:
WITH CTE AS(
SELECT I.InvoiceId,
I.InvoiceDate,
I.NetAmount,
P.PaymentId,
P.PaidAmount,
ROW_NUMBER() OVER (PARTITION BY I.InvoiceId, I.InvoiceDate ORDER BY (SELECT NULL)) AS RN
FROM #Invoice I
LEFT JOIN #Payment P ON I.InvoiceId = P.InvoiceId)
SELECT C.InvoiceDate,
SUM(CASE RN WHEN 1 THEN C.NetAmount END) AS NetAmount,
ISNULL(SUM(C.PaidAmount),0) AS PaidAmount
FROM CTE C
GROUP BY C.InvoiceDate;

Retrieve column based on closest date

Thanks for your help in advance. I have an invoice table which is similar to below:
INV DATE | ITEM |SELL PRICE |COST PRICE
------------+-------+-----------+----------
30/06/2016 | DOOR1 |10 |5
The above item is sourced from the EU so I have another table (VEN_HIS) which lists a history of supplier prices for that item as below:
DATE |ITEM |CURRENCY |PRICE
------------+-------+-----------+------
17/05/2017 |DOOR1 |EUR |6
01/01/2017 |DOOR1 |EUR |5.8
29/05/2016 |DOOR1 |EUR |5.6
05/03/2016 |DOOR1 |EUR |5.5
What I want to do is join the tables to drop in the correct currency price we would have paid onto the invoice table as at the invoice date in other words the correct price is 5.6
This is my first post and I need to get some FX analysis done quickly so apologies for the formatting, any help would be greatly appreciated.
Its a simple question of Join and where clause.
create table #t1 (INV_DATE DATE,ITEM varchar(100), SELL_PRICE int, COST_PRICE int);
insert into #t1 values
('30/06/2016','DOOR1',10,5)
create table #ven_his (colDATE date, ITEM varchar(100), CURRENCY varchar(100),PRICE float);
insert into #ven_his values
('17/05/2017', 'DOOR1', 'EUR',6 ),
('01/01/2017', 'DOOR1', 'EUR',5.8),
('29/05/2016', 'DOOR1', 'EUR',5.6),
('05/03/2016', 'DOOR1', 'EUR',5.5)
SELECT top 1 a.INV_DATE, a.ITEM, b.CURRENCY, b.PRICE
FROM #t1 a
left join #ven_his b
on a.ITEM = b.ITEM
WHERE b.colDATE <=a.INV_DATE
ORDER BY b.colDATE DESC
output :
#t1
INV_DATE ITEM SELL_PRICE COST_PRICE
---------- ------ ----------- -----------
2016-06-30 DOOR1 10 5
#ven_his
colDATE ITEM CURRENCY PRICE
---------- --------- ------------ ------
2017-05-17 DOOR1 EUR 6
2017-01-01 DOOR1 EUR 5.8
2016-05-29 DOOR1 EUR 5.6
2016-03-05 DOOR1 EUR 5.5
INV_DATE ITEM CURRENCY PRICE
---------- --------- ----------- --------
2016-06-30 DOOR1 EUR 5.6
DECLARE #invoice table (INV_Date date, Item varchar(100),SellPrice numeric(5,2), Costprice numeric(5,2))
INSERT INTO #invoice
SELECT '20160630','DOOR1',10,5
SELECT * FrOm #invoice
DECLARE #ven_his table(Dates date,Item varchar(100),Currency varchar(10),Price numeric(5,2))
INSERT INTO #ven_his
SELECT '20170517','DOOR1','EUR',6
UNION ALL
SELECT '20170101','DOOR1','EUR',5.8
UNION ALL
SELECT '20160529','DOOR1','EUR',5.6
UNION ALL
SELECT '20160305','DOOR1','EUR',5.5
SELECT * FROM #ven_his
SELECT Top 1 i.Item,INV_Date,PRICE,Dates
FROM #invoice i
JOIN #ven_his v
ON i.Item = v.Item
ORDER BY ABS(DATEDIFF(DAY,i.INV_Date,v.Dates))
Use LEAD function to return the correct price for all items:
Create table #Invoice (INVDATE DATE, ITEM NVARCHAR(20), SELLPRICE SMALLMONEY, COSTPRICE SMALLMONEY)
INSERT #INVOICE VALUES ('2016-06-30', 'DOOR1', 10, 5)
--Test with additional invoices
--INSERT #INVOICE VALUES ('2017-02-22', 'DOOR1', 10, 5), ('2016-09-22', 'DOOR1', 10, 5)
CREATE TABLE #VENHIS ([DATE] DATE, ITEM NVARCHAR(20), CURRENCY NVARCHAR(5), PRICE SMALLMONEY)
INSERT #VENHIS VALUES ('2017-05-17', 'DOOR1', 'EUR', 6), ('2017-01-01', 'DOOR1', 'EUR', 5.8),('2016-05-29', 'DOOR1', 'EUR', 5.6), ('2016-03-05', 'DOOR1', 'EUR', 5.5)
SELECT I.*, V.PRICE
FROM #Invoice i
INNER JOIN (SELECT *, [DATE] as STARTDATE, LEAD([DATE]) OVER (PARTITION BY ITEM ORDER BY ITEM, [DATE] ASC) AS EndDate
FROM #VENHIS ) v ON i.ITEM=v.ITEM AND I.[INVDATE] BETWEEN V.STARTDATE AND DATEADD(D,-1,ISNULL(V.ENDDATE, '2099-01-01'))

JOIN on multilple rows to SELECT only TOP row in SQL Sever

I have a table which has only 1 row per ID/Date while the other one can have overlapping ID/Dates. I need to JOIN them in such a way that only top row is selected (actually any row from duplicates table is fine!). Its fairly easy to do this in 2 steps (Insert & Update) but I'm looking if it can be done in a single step.
CREATE TABLE #Row1Each (ID VARCHAR(10), Date_ DATETIME, Value FLOAT) INSERT INTO #Row1Each SELECT 'AAPL', '1/10/2015', 100 INSERT INTO #Row1Each SELECT 'MSFT', '1/10/2015', 20
CREATE TABLE #Table1 (ID VARCHAR(10), Date_ DATETIME, Qty FLOAT) INSERT INTO #Table1 SELECT 'AAPL', '1/10/2015', 55000
CREATE TABLE #Duplicates (ID VARCHAR(10), StartDate DATETIME, EndDate DATETIME, Quote FLOAT) INSERT INTO #Duplicates SELECT 'AAPL', '1/2/2015', '12/31/2016', 0.1 INSERT INTO #Duplicates SELECT 'AAPL', '1/4/2015', '10/05/2016', 0.11
/*
AAPL 2015-01-10 00:00:00.000 100
MSFT 2015-01-10 00:00:00.000 20
AAPL 2015-01-10 00:00:00.000 55000
AAPL 2015-01-02 00:00:00.000 2016-12-31 00:00:00.000 0.1
AAPL 2015-01-04 00:00:00.000 2016-10-05 00:00:00.000 0.1
*/
SELECT A.*
, B.Qty
, C.Quote
FROM #Row1Each A
LEFT JOIN #Table1 B ON B.ID = A.ID
AND B.Date_ = A.Date_
LEFT JOIN #Duplicates C ON C.ID = A.ID
AND A.Date_ BETWEEN C.StartDate AND C.EndDate
DROP TABLE #Row1Each DROP TABLE #Table1 DROP TABLE #Duplicates
/* Desired output
AAPL 2015-01-10 00:00:00.000 100 55000 0.1
MSFT 2015-01-10 00:00:00.000 20 NULL NULL
*/
You can do this using APPLY.
SELECT
r.Id,
r.Date_,
r.Value,
t.Qty,
d.Quote
FROM #Row1Each r
LEFT JOIN #Table1 t
ON t.ID = r.ID
AND t.Date_ = r.Date_
OUTER APPLY(
SELECT TOP 1 *
FROM #Duplicates d
WHERE
d.ID = r.ID
AND r.Date_ BETWEEN d.StartDate AND d.EndDate
ORDER BY EndDate DESC -- Returns Top 1 Based on EndDate
)d

comparing with dates?

Using SQL Server 2000
Table1
ID Name, Date, TimeIn, TimeOut, DateIn, Dateout
AEAA00294 Alexander 13/10/2008 09:00:00 18:00:00 13/10/2008 13/10/2008
AEAA00294 Alexander 14/10/2008 16:00:00 02:00:00 14/10/2008 15/10/2008
AEAA00294 Alexander 16/10/2008 09:00:00 18:00:00 16/10/2008 16/10/2008
So on…,
Table2
ID Date
DATE, TIME, ID
20081013 103417 AEAA00294
20081013 151552 AEAA00294
20081013 170836 AEAA00294
20081013 170909 AEAA00294
20081013 171015 AEAA00294
20081014 163648 AEAA00294
20081014 030838 AEAA00294
20081015 144708 AEAA00294
20081015 151133 AEAA00294
20081016 095211 AEAA00294
So on…,
From the above two table I am taking Intime that is min (time) as Intime on the date and max (time) as Outtime on the same date from table2 where table1.personid = table2.personid.
In table1 DateIn and Dateout Date is same, it should take min (time) and Max (time) on the same date from the table2
Suppose table1 DateIn and Dateout Date is different, it should take min (time) and Max (time) from table2 compare with table1.dateIn and table2.Dateout
Expected Output
ID Date Intime Outtime
AEAA00294 20081013 103417 171015
AEAA00294 20081014 030838 151133
So on…,
My Query
SELECT DISTINCT DERIVEDTBL.PERSONID, DERIVEDTBL.CARDEVENTDATE, MIN(DERIVEDTBL.CARDEVENTTIME) AS INTIME, MAX(DERIVEDTBL.CARDEVENTTIME) AS OUTTIME, tmp_Cardevent1.Normal_Intime, tmp_Cardevent1.Normal_Outtime, tmp_Cardevent1.CardEventDate AS Expr1, tmp_Cardevent1.DateIn, tmp_Cardevent1.DateOut FROM (SELECT T_PERSON.PERSONID, T_CARDEVENT.CARDEVENTDATE, CONVERT(VARCHAR(10), SUBSTRING(T_CARDEVENT.CARDEVENTTIME, 1, 2) + ':' + SUBSTRING(T_CARDEVENT.CARDEVENTTIME, 3, 2) + ':' + SUBSTRING(T_CARDEVENT.CARDEVENTTIME, 5, 2), 8) AS CARDEVENTTIME
FROM T_CARDEVENT LEFT JOIN T_PERSON ON T_CARDEVENT.PERSONID = T_PERSON.PERSONID) DERIVEDTBL INNER JOIN tmp_Cardevent1 ON DERIVEDTBL.PERSONID = tmp_Cardevent1.PERSONID AND DERIVEDTBL.CARDEVENTDATE = tmp_Cardevent1.CardEventDate GROUP BY DERIVEDTBL.CARDEVENTDATE, DERIVEDTBL.PERSONID, tmp_Cardevent1.Normal_Intime, tmp_Cardevent1.Normal_Outtime, tmp_Cardevent1.CardEventDate, tmp_Cardevent1.DateIn, tmp_Cardevent1.DateOut
Table1 as tmp_cardevent1 and Table2 as Derivedtbl in my query.
From the above i want to compare derivedtbl date with tmp_cardevent1 dateIn and DateOut values.
Need Query Help.
How to make a query for this condition?
Try something like this
DECLARE #Table1 TABLE(
ID VARCHAR(50),
PNAME VARCHAR(50),
Date DATETIME,
TimeIN VARCHAR(10),
[TimeOut] VARCHAR(10),
DateIn DATETIME,
DateOut DATETIME
)
INSERT INTO #Table1 (ID,PNAME,Date,TimeIN,[TimeOut],DateIn,DateOut)
SELECT 'AEAA00294','Alexander','13 Oct 2008', '09:00:00', '18:00:00','13 Oct 2008','13 Oct 2008'
INSERT INTO #Table1 (ID,PNAME,Date,TimeIN,[TimeOut],DateIn,DateOut)
SELECT 'AEAA00294','Alexander','14 Oct 2008', '16:00:00', '02:00:00','14 Oct 2008','15 Oct 2008'
INSERT INTO #Table1 (ID,PNAME,Date,TimeIN,[TimeOut],DateIn,DateOut)
SELECT 'AEAA00294','Alexander','16 Oct 2008', '09:00:00', '18:00:00','16 Oct 2008','16 Oct 2008'
DECLARE #Table2 TABLE(
Date DATETIME,
[Time] VARCHAR(10),
ID VARCHAR(50)
)
INSERT INTO #Table2 (Date,[Time],ID) SELECT '13 Oct 2008', '10:34:17', 'AEAA00294'
INSERT INTO #Table2 (Date,[Time],ID) SELECT '13 Oct 2008' , '15:15:52' , 'AEAA00294'
INSERT INTO #Table2 (Date,[Time],ID) SELECT '13 Oct 2008' , '17:08:36' , 'AEAA00294'
INSERT INTO #Table2 (Date,[Time],ID) SELECT '13 Oct 2008' , '17:09:09' , 'AEAA00294'
INSERT INTO #Table2 (Date,[Time],ID) SELECT '13 Oct 2008' , '17:10:15' , 'AEAA00294'
INSERT INTO #Table2 (Date,[Time],ID) SELECT '14 Oct 2008' , '16:36:48' , 'AEAA00294'
INSERT INTO #Table2 (Date,[Time],ID) SELECT '14 Oct 2008' , '03:08:38' , 'AEAA00294'
INSERT INTO #Table2 (Date,[Time],ID) SELECT '15 Oct 2008' , '14:47:08' , 'AEAA00294'
INSERT INTO #Table2 (Date,[Time],ID) SELECT '15 Oct 2008' , '15:11:33' , 'AEAA00294'
INSERT INTO #Table2 (Date,[Time],ID) SELECT '16 Oct 2008' , '09:52:11' , 'AEAA00294'
SELECT t1.ID,
t1.PNAME,
t1.DateIn,
t1.DateOut,
MIN(CAST(t2In.[Time] AS DATETIME)),
MAX(CAST(t2Out.[Time] AS DATETIME))
FROM #Table1 t1 LEFT JOIN
#Table2 t2IN ON t1.ID = t2IN.ID
AND t1.DateIn = t2IN.Date LEFT JOIN
#Table2 t2Out ON t1.ID = t2Out.ID
AND t1.DateOut = t2Out.Date
GROUP BY t1.ID,
t1.PNAME,
t1.DateIn,
t1.DateOut
I think this will do it:
update table1 set timein=t2.timein, timeout=t2.timeout from table1 t1 join
(select ID, date, min(time) as timein, max(time) as timeout from table2 group by is, date) as t2 on t1.id=t2.id

Date comparing between two dates? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Value should be 0 between the two dates?
SQL Server 2000
Table1
ID Date Workedtime
001 23-02-2009 08:00:00
001 24-02-2009 15:00:00
001 25-02-2009 17:00:00
002 ...
So on..,
Table2
ID FromDate ToDate
001 24-02-2009 25-02-2009
002 27-02-2009 03-03-2009
...
I want to compare the table1 date and ID with Table2 ID FromDate, ToDate, means
Table1 Date compare with FromDate ToDate, if Date is comes in between fromdate and todate, the worktime should display absent.
Expected Output
ID Date Workedtime
001 23-02-2009 08:00:00
001 24-02-2009 absent
001 25-02-2009 absent
002 ...
Need Query Help
This should help from what you have specified above
DECLARE #Table1 TABLE(
ID VARCHAR(10),
Date DATETIME,
Workedtime VARCHAR(10)
)
INSERT INTO #Table1 (ID,Date,Workedtime) SELECT '001', '23 Feb 2009', '08:00:00'
INSERT INTO #Table1 (ID,Date,Workedtime) SELECT '001', '24 Feb 2009', '15:00:00'
INSERT INTO #Table1 (ID,Date,Workedtime) SELECT '001', '25 Feb 2009', '17:00:00'
DECLARE #Table2 TABLE(
ID VARCHAR(10),
FromDate DATETIME,
ToDate DATETIME
)
INSERT INTO #Table2 (ID,FromDate,ToDate) SELECT '001', '24 Feb 2009', ' 25 Feb 2009'
SELECT t1.ID,
t1.Date,
CASE WHEN t2.ID IS NULL THEN t1.Workedtime ELSE 'absent' END Workedtime
FROM #Table1 t1 LEFT JOIN
#Table2 t2 ON t1.ID = t2.ID
AND t1.Date BETWEEN t2.FromDate AND t2.ToDate

Resources