I would like to get 2 consecutive rows from an SQL table.
One of the columns storing UNIX datestamp and between 2 rows the difference only this value.
For example:
id_int dt_int
1. row 8211721 509794233
2. row 8211722 509794233
I need only those rows where dt_int the same (edited)
Do you want both lines to be shown?
A solution could be this:
with foo as
(
select
*
from (values (8211721),(8211722),(8211728),(8211740),(8211741)) a(id_int)
)
select
id_int
from
(
select
id_int
,id_int-isnull(lag(id_int,1) over (order by id_int) ,id_int-6) prev
,isnull(lead(id_int,1) over (order by id_int) ,id_int+6)-id_int nxt
from foo
) a
where prev<=5 or nxt<=5
We use lead and lag, to find the differences between rows, and keep the rows where there is less than or equal to 5 for the row before or after.
If you use 2008r2, then lag and lead are not available. You could use rownumber in stead:
with foo as
(
select
*
from (values (8211721),(8211722),(8211728),(8211740),(8211741)) a(id_int)
)
, rownums as
(
select
id_int
,row_number() over (order by id_int) rn
from foo
)
select
id_int
from
(
select
cur.id_int
,cur.id_int-prev.id_int prev
,nxt.id_int-cur.id_int nxt
from rownums cur
left join rownums prev
on cur.rn-1=prev.rn
left join rownums nxt
on cur.rn+1=nxt.rn
) a
where isnull(prev,6)<=5 or isnull(nxt,6)<=5
Assuming:
lead() analytical function available.
ID_INT is what we need to sort by to determine table order...
you may need to partition by some value lead(ID_int) over(partition by SomeKeysuchasOrderNumber order by ID_int asc) so that orders and dates don't get mixed together.
.
WITH CTE AS (
SELECT A.*
, lead(ID_int) over ([missing partition info] ORDER BY id_Int asc) - id_int as ID_INT_DIFF
FROM Table A)
SELECT *
FROM CTE
WHERE ID_INT_DIFF < 5;
You can try it. This version works on SQL Server 2000 and above. Today I don not a more recent SQL Server to write on.
declare #t table (id_int int, dt_int int)
INSERT #T SELECT 8211721 , 509794233
INSERT #T SELECT 8211722 , 509794233
INSERT #T SELECT 8211723 , 509794235
INSERT #T SELECT 8211724 , 509794236
INSERT #T SELECT 8211729 , 509794237
INSERT #T SELECT 8211731 , 509794238
;with cte_t as
(SELECT
ROW_NUMBER() OVER (ORDER BY id_int) id
,id_int
,dt_int
FROM #t),
cte_diff as
( SELECT
id_int
,dt_int
,(SELECT TOP 1 dt_int FROM cte_t b WHERE a.id < b.id) dt_int1
,dt_int - (SELECT TOP 1 dt_int FROM cte_t b WHERE a.id < b.id) Difference
FROM cte_t a
)
SELECT DISTINCT id_int , dt_int FROM #t a
WHERE
EXISTS(SELECT 1 FROM cte_diff b where b.Difference =0 and a.dt_int = b.dt_int)
I have been struggling for a while now with that problem and I need some help.
I have the following query :
CREATE TABLE Example(
Start NVARCHAR(8),
Endd NVARCHAR(8),
Col1 NVARCHAR(2),
Col2 NVARCHAR(2));
INSERT into Example (Start,Endd,Col1,Col2)
VALUES ('20130801','20140316','02','01'),
('20140317','20140319','04','02'),
('20140320','20140320','04','02'),
('20140321','20140421','02','Z8'),
('20140422','20140429','02','Z9'),
('20140430','20140902','04','02'),
('20140903','20150201','04','02'),
('20150202','20150223','04','02'),
('20150224','20150527','04','02'),
('20150528','99991231','04','02')
;
select MIN(Start)AS Start,MAX(Endd) AS Endd,Col1,Col2 from
(
SELECT top (100000000) Start, Endd,Col1, Col2,dense_rank() over(partition by Col1, Col2 order by Start,Endd) as rank
,LEAD (Col1) OVER (order by Start,Endd DESC) as l1
,LEAD (Col2) OVER (order by Start,Endd DESC) as l2
,LAG (Col1) OVER (order by Start,Endd DESC) as l11
,LAG (Col2) OVER (order by Start,Endd DESC) as l22
FROM Example sp
order by Start,Endd
)rq
GROUP BY Col1,Col2,case when (rq.l1=Col1 and rq.l2=Col2) or (rq.l11=Col1 and rq.l22=Col2) then 0 else rank end
order by Start,Endd;
My goal is to merge those data to have the following result:
However as you can see in the query result, when i have the same values for Col1 and Col2 on different time periods, the merge is not done correctly. It basically tries to merge them all in one, which create issues in the value for the new period.
Would someone be able to help me?
You were getting close in your query and you may have found a solution by now. This is a classic Islands and Gaps problem. I am giving the longer version with no use of LEAD AND LAG. You can replace perhaps 45% of the code below by using those windowing functions with perhaps a dense rank.
DECLARE #Example TABLE(
Start NVARCHAR(8),
Endd NVARCHAR(8),
Col1 NVARCHAR(2),
Col2 NVARCHAR(2));
INSERT into #Example (Start,Endd,Col1,Col2)
VALUES ('20130801','20140316','02','01'),
('20140317','20140319','04','02'),
('20140320','20140320','04','02'),
('20140321','20140421','02','Z8'),
('20140422','20140429','02','Z9'),
('20140430','20140902','04','02'),
('20140903','20150201','04','02'),
('20150202','20150223','04','02'),
('20150224','20150527','04','02'),
('20150528','99991231','04','02')
SELECT
TableID=MAX(TableID),Col1=MAX(Col1),Col2=MAX(Col2),Start=MIN(Start),Endd=MAX(Endd)
FROM
(
SELECT
TableID,Col1,Col2,Start,Endd,ChangeID=MAX(ChangeOnlyTableID)
FROM
(
SELECT
AllRecords.TableID,AllRecords.Col1,AllRecords.Col2,AllRecords.Start,AllRecords.Endd,ChangeOnlyTableID=ChangesOnly.TableID
FROM
(
SELECT * FROM
(
SELECT
This.Start,This.Endd,This.TableID,This.Col1,This.Col2,
Changed=CASE WHEN (Next.Col1=This.Col1 AND Next.Col2=This.Col2) THEN 0 ELSE 1 END
FROM
(
SELECT TableID=ROW_NUMBER() OVER(ORDER BY Start,Endd,Col1,Col2),Start,Endd,Col1,Col2 FROM #Example
)AS This
LEFT OUTER JOIN
(
SELECT TableID=ROW_NUMBER() OVER(ORDER BY Start,Endd,Col1,Col2),Start,Endd,Col1,Col2 FROM #Example
)
AS Next ON This.TableID=Next.TableID+1
)
AS ChangeMarkers
WHERE Changed=1
)
AS AllRecords
INNER JOIN
(
SELECT * FROM
(
SELECT
This.Start,This.Endd,This.TableID,This.Col1,This.Col2,
Changed=CASE WHEN (Next.Col1=This.Col1 AND Next.Col2=This.Col2) THEN 0 ELSE 1 END
FROM
(
SELECT TableID=ROW_NUMBER() OVER(ORDER BY Start,Endd,Col1,Col2),Start,Endd,Col1,Col2 FROM #Example
) AS This
LEFT OUTER JOIN
(
SELECT TableID=ROW_NUMBER() OVER(ORDER BY Start,Endd,Col1,Col2),Start,Endd,Col1,Col2 FROM #Example
) AS Next ON This.TableID=Next.TableID+1
)
AS ChangeMarkers
WHERE Changed=1
)
AS ChangesOnly ON ChangesOnly.Col1=AllRecords.Col1 AND ChangesOnly.Col2=AllRecords.Col2 AND ChangesOnly.TableID<=AllRecords.TableID
)AS JoinedResults
GROUP BY
TableID,Col1,Col2,Start,Endd
)
AS Final
GROUP BY
Col1,Col2,ChangeID
ORDER BY
MAX(TableID)
You may choose to shorten this somewhat with a few CTE's to produce a query such as:
;WITH TableWithIDs AS
(
SELECT TableID=ROW_NUMBER() OVER(ORDER BY Start,Endd,Col1,Col2),Start,Endd,Col1,Col2 FROM #Example
)
,ChangeMarkers AS
(
SELECT
This.Start,This.Endd,This.TableID,This.Col1,This.Col2,
Changed=CASE WHEN (Next.Col1=This.Col1 AND Next.Col2=This.Col2) THEN 0 ELSE 1 END
FROM
TableWithIDs AS This
LEFT OUTER JOIN TableWithIDs AS Next ON This.TableID=Next.TableID+1
)
,ChangesOnly AS
(
SELECT * FROM ChangeMarkers WHERE Changed=1
)
,
JoinedResults AS
(
SELECT
AllRecords.TableID,AllRecords.Col1,AllRecords.Col2,AllRecords.Start,AllRecords.Endd,ChangeOnlyTableID=ChangesOnly.TableID
FROM
ChangeMarkers AllRecords
INNER JOIN ChangesOnly ON ChangesOnly.Col1=AllRecords.Col1 AND ChangesOnly.Col2=AllRecords.Col2 AND ChangesOnly.TableID<=AllRecords.TableID
)
SELECT
TableID=MAX(TableID),Col1=MAX(Col1),Col2=MAX(Col2),Start=MIN(Start),Endd=MAX(Endd)
FROM
(
SELECT
TableID,Col1,Col2,Start,Endd,ChangeID=MAX(ChangeOnlyTableID)
FROM
JoinedResults
GROUP BY
TableID,Col1,Col2,Start,Endd
)
AS Final
GROUP BY
Col1,Col2,ChangeID
ORDER BY
MAX(TableID)
There are also some clever hacks that can be applied further using virtual keys however I went the most direct but more verbose route. You should be able to improve on this using a DENSE_RANK() with LEAD() OR LAG()
I am trying to get a list of records showing changes in location and dates to display as one row for each record showing previous location.
Basically a query to take data like:
And display it like:
I tried using lag, but it mixes up some of the records. Would anyone be able suggest a good way to do this?
Thanks!
DECLARE #TABLE TABLE
(ID INT ,NAME VARCHAR(20), LOCATIONDATE DATETIME, REASON VARCHAR(20))
INSERT INTO #TABLE
(ID,NAME, LOCATIONDATE, REASON)
VALUES
( 1,'abc',CAST('2016/01/01' AS SMALLDATETIME),'move'),
( 2,'def',CAST('2016/02/01' AS SMALLDATETIME),'move'),
( 1,'abc',CAST('2016/06/01' AS SMALLDATETIME),'move'),
( 2,'def',CAST('2016/07/01' AS SMALLDATETIME),'move'),
( 1,'abc',CAST('2016/08/01' AS SMALLDATETIME),'move'),
( 3,'ghi',CAST('2016/08/01' AS SMALLDATETIME),'move')
select s.*
,t1.*
from
(
select t.*,
row_number() over (partition by id order by locationdate desc) rn
from #table t
) s
left join
(
select t.*,
row_number() over (partition by id order by locationdate desc) rn
from #table t
) t1
on t1.id = s.id and t1.rn = s.rn + 1
You can try it:
SELECT a.id,a.name,a.location as currentLocation,a.locationdatedate as currrentLocate,b.location as preLocation,b.locationdatedate as prevLocate,a.changereason
FROM test as a
JOIN test as b ON a.name = b.name
where a.locationdatedate > b.locationdatedate
group by a.name
Pleas try this one. it works here
SELECT l.id,
,l.name
,l.location as currentLocation
,l.locationdatedate as currrentLocate
,r.location as preLocation
,r.locationdatedate as prevLocate
,r.changereason
FROM tableName AS l inner join
tableName AS r ON r.id=l.id
WHERE l.locationdatedate !=r.locationdatedate AND l.locationdatedate > r.locationdatedate
I am looking for a simple query to get result of 2 rows with latest invoice date in each group. Although this task can be accomplished by a row_number() that you can see in below code ,I need an alternative to this with minimum complexity.
Code :
create table #tt
(
id int,
invoiceDT datetime
)
insert into #tt
values(1,'01-01-2016 00:12'),(1,'01-02-2016 06:16'),(1,'01-01-2016 00:16')
,(2,'01-01-2016 01:12'),(2,'04-02-2016 06:16'),(2,'01-06-2016 00:16')
select *
from (
SELECT id,invoiceDT,row_number() over(partition by id order by invoiceDT desc) as rownum
FROM #tt
)tmp
where rownum <=2
I need same result that is returned by above query
Please suggest an alternative.
Strange request, but here you go:
WITH CTE as
(
SELECT distinct id FROM #tt t1
)
SELECT x.*
FROM CTE
CROSS APPLY
(
SELECT top 2 *
FROM #tt
WHERE CTE.id = id
ORDER BY invoiceDT desc
) x
What I am trying to accomplish:
Dataset 1
Name1
Name2
Name3
Dataset 2
Number1
Number2
Number3
will become 2 columns:
dataset1 dataset2
Name1 Number1
Name2 Number2
Name3 Number3
My datasets 1 & 2 will always have equal rows.
Which name linked to which number I don't care as long as two names are not linked to the same number and vice versa.
How can I solve this with SQL / SQL Server ?
If you don't want to add an identity column to the tables, you can use the ROW_NUMBER() function like this:
SELECT
T1.Col1,
T2.Col1
FROM
(SELECT Col1, ROW_NUMBER() OVER (ORDER BY Col1) AS N FROM Table1) T1
INNER JOIN
(SELECT Col1, ROW_NUMBER() OVER (ORDER BY Col1) AS N FROM Table2) T2
ON T1.N = T2.N
Here, replace Table1 and Table2 with the name of your tables, and replace Col1 with the name of the column (or columns) that you want to output from the two tables.
Add identity columns to both the tables and perform join on basis of these column
ALTER TABLE Table1
ADD ID INT IDENTITY(1,1) NOT NULL
ALTER TABLE Table2
ADD ID INT IDENTITY(1,1) NOT NULL
SELECT Table1.dataset1col , Table2.dataset2Col
From Table1 INNER JOIN Table2
ON Table1.ID = Table2.ID
This may work for you :
;WITH cte1 (name, rn)
AS (SELECT Name,
row_number()
OVER(
ORDER BY Name) rn
FROM Dataset1),
cte2 (Number, rn)
AS (SELECT Number,
row_number()
OVER(
ORDER BY Number) rn
FROM Dataset2)
SELECT name,
Number
FROM cte1
JOIN cte2
ON cte1.rn = cte2.rn
WITH Table1 AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Dataset1) as Rnk,Dataset1
FROM TA1
)
With Table2 AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Dataset2) as Rnk, Dataset2
FROM TA2
)
Select Table.Dataset1 as 'DataSet1', Table2.DataSet2 as 'DataSet2'
From Table1
inner join Table2 on Table1.Rnk = Table2.Rnk
Because you haven't added table name so I considered it as TA1 and TA2.
Another way of writing the query is:
select row_number() over (order by Names asc) as rownum,
Names
into #Temp1
from NameTable
select row_number() over (order by Numbers asc) as rownum,
Numbers
into #Temp2
from NumberTable
select Names, Numbers
from #Temp1
inner join #Temp2 on #Temp1.rownum = #Temp2.rownum
Demo
There are 3 possible solutions to this.
First: Use following trick (Warning: Use this in case of small datasets)
SELECT DISTINCT tbl1.col1, tbl2.col2
FROM
(SELECT FirstName AS col1, ROW_NUMBER() OVER (ORDER BY FirstName) Number FROM dbo.User) tbl1
INNER JOIN
(SELECT LastName AS col2, ROW_NUMBER() OVER (ORDER BY LastName) Number FROM dbo.User) tbl2
ON tbl1.Number = tbl2.Number
Second: Use variable tables to store result temporarily. This solution is for relatively large datasets. (approx records to 100s)
Third:
Use identitfy field in both tables as already mentioned by mmhasannn. But i will prefer this method least, as we need to modify our DB structure.
RECOMMENDED: Use variable tables approach