简体   繁体   中英

difference between two fields from different rows

let's say this is the result of my Select query :

ID    Name    Status    Edit    Date
1     n1      closed    edt1      01/01/2005
1     n1      closed    edt2      15/01/2005
1     n1      closed    edt3      20/01/2005

What I'm trying to do, is to get the diff between the date of edit1 and the date of edit2 (how many days the edit took) and put it on a separate column.

keep in mind that I get a result (for testing purpose), something like this :

select x.id, x.name, x.status, y.edit, y.date
from (table1 x left join table2 y on x.id = y.id)
where x.id = 1 

So how can I get the number of days spent between each edit and put it on a decicated column? of course there won't be a where x.id = 1 anymore...my query result should look like this :

id    name    status    edit_1(edt2 - edt1)   edit_2(edt3 - edt2)   
1     n1      closed    14                    5

Thanks for helping ^^

You can use the LEAD() analytic function:

SELECT id, name, status, edit, date, LEAD(date) OVER ( PARTITION BY id ORDER BY date ) - date AS edit_diff
  FROM mytable;

If you want to put a certain number of edits into their own columns, you could then PIVOT the date returned from the above query; if the # of edits is arbitrary then you'll need to use PL/SQL to do it.

Note that I'm assuming that name and status won't vary by id ; if you want to track edits to these then you'll want to add those columns to the LEAD() partition.


Assuming that you'll always have a fixed number of dates (let's assume three as in your example, giving two date differences), you can pivot by using conditional aggregation. We'll use our query above as a common table expression (CTE); you can also use it as a subquery if that's more your style. I think this way is cleaner though. I'm going to add a call to ROW_NUMBER() :

WITH mydata AS (
    SELECT id, name, status, edit, date
         , LEAD(date) OVER ( PARTITION BY id ORDER BY date ) - date AS edit_diff
         , ROW_NUMBER() OVER ( PARTITION BY id ORDER BY date ) AS rn
      FROM mytable
)
SELECT id, name, status, edit, date
     , MAX(CASE WHEN rn = 1 THEN edit_diff END) AS edit_1
     , MAX(CASE WHEN rn = 2 THEN edit_diff END) AS edit_2
  FROM mydata
 GROUP BY id, name, status, edit, date;

(By the way, date is not a good name for a column. I'm assuming that's just an example and not the actual name.)

I would add an incrementing id column like this: http://www.orafaq.com/wiki/AutoNumber_and_Identity_columns and then write your query like this:

select x.id, x.name, x.status, y.edit, y.date, y.date - z.date
from (table1 x left join table2 y on x.id = y.id left join table2 z on y.newid = z.newid - 1)
where x.id = 1
CREATE TABLE [dbo].[EditTry]
(
[ID] [int] NULL,
[Name] [varchar](50) NULL,
[Status] [varchar](50) NULL,
[Edit] [varchar](50) NULL,
[Date] [datetime] NULL
) 

INSERT [dbo].[EditTry] ([ID], [Name], [Status], [Edit], [Date]) VALUES (1, N'n1', N'closed', N'edt1', '2005-01-01')
INSERT [dbo].[EditTry] ([ID], [Name], [Status], [Edit], [Date]) VALUES (1, N'n1', N'closed', N'edt2', '2005-01-15')
INSERT [dbo].[EditTry] ([ID], [Name], [Status], [Edit], [Date]) VALUES (1, N'n1', N'closed', N'edt3', '2005-01-20')


with tempss as
(
SELECT ID,Edit,[Date],RANK() OVER (ORDER BY Edit) AS Rank FROM EditTry 
)

select t1.*,datediff(dd,t1.date,(select top 1 date from tempss t2 where t2.id = t1.id and t1.rank < t2.rank)) as Dif from tempss t1 

Working in SQL Server

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM