我有一个非常简单的ID和登录日期表,我想使用SQL来创建一列以显示以前的登录日期:
Table: SIGNIN
| ID | Sign-in Date |
| A | 01/01/19 |
| B | 01/01/19 |
| C | 02/01/19 |
| A | 02/01/19 |
| A | 03/01/19 |
| B | 03/01/19 |
| A | 04/01/19 |
| C | 04/01/19 |
| B | 05/01/19 |
我尝试对自己进行联接,但它显示的是以前的所有登录日期,而不仅仅是最近的登录日期。
SELECT [SIGNIN].ID
[SIGNIN].SignInDate
FROM [SIGNIN]
INNER JOIN [SIGNIN] as [Prev] on [SIGNIN].ID = [Prev].ID
and [SIGNIN].SignInDate < [Prev].SignInDate
ORDER BY [SIGNIN].ID, [SIGNIN].SignInDate
我想要的结果
Table: SIGNIN
| ID | Sign-in Date | Previous |
| A | 01/01/19 | NULL |
| B | 01/01/19 | NULL |
| C | 02/01/19 | NULL |
| A | 02/01/19 | 01/01/19 |
| A | 03/01/19 | 02/01/19 |
| B | 03/01/19 | 01/01/19 |
| A | 04/01/19 | 03/01/19 |
| C | 04/01/19 | 02/01/19 |
| B | 05/01/19 | 03/01/19 |
我得到的是什么
| ID | Sign-in Date | Previous |
| A | 01/01/19 | NULL |
| B | 01/01/19 | NULL |
| C | 02/01/19 | NULL |
| A | 02/01/19 | 01/01/19 |
| A | 03/01/19 | 01/01/19 |
| A | 03/01/19 | 02/01/19 |
| B | 03/01/19 | 01/01/19 |
| A | 04/01/19 | 01/01/19 |
| A | 04/01/19 | 02/01/19 |
| A | 04/01/19 | 03/01/19 |
| C | 04/01/19 | 02/01/19 |
| B | 05/01/19 | 01/01/19 |
| B | 05/01/19 | 03/01/19 |
我敢肯定,这已经在其他地方得到了解决,但是我遇到的最大问题是不知道如何表达我的问题!
编辑:到目前为止,这确实很有帮助,但是有没有可以更改日期“截止”日期的解决方案,例如:
Cut off: 03/01/19
Table: The same
Desired result:
| ID | Sign-in Date | Previous |
| A | 03/01/19 | 02/01/19 |
| B | 03/01/19 | 01/01/19 |
| A | 04/01/19 | 03/01/19 |
| C | 04/01/19 | 02/01/19 |
| B | 05/01/19 | 03/01/19 |
答案 0 :(得分:1)
假设您使用的是现代版本的SQL Server,请尝试使用LAG。
SELECT [SIGNIN].ID,
[SIGNIN].SignInDate,
LAG([SIGNIN].SignInDate) OVER (PARTITION BY [SIGNIN].ID ORDER BY [SIGNIN].SignInDate DESC) AS Previous
FROM [SIGNIN]
答案 1 :(得分:0)
尝试这样的事情:
SELECT ID, SignInDate, LAG(SignInDate, 1,SignInDate) OVER(order by ID partition by ID) FROM SIGNIN
答案 2 :(得分:0)
使用此:
SELECT [SIGNIN].ID,
[SIGNIN].SignInDate,
MAX([Prev].SignInDate) as Previous
FROM [SIGNIN]
LEFT JOIN [SIGNIN] as [Prev] on [SIGNIN].ID = [Prev].ID
and [SIGNIN].SignInDate > [Prev].SignInDate
GROUP BY [SIGNIN].ID, [SIGNIN].SignInDate
ORDER BY [SIGNIN].ID, [SIGNIN].SignInDate
答案 3 :(得分:0)
以下内容将为您提供几乎所有您想要的内容,只是没有空值。 您可能应该在内部查询中进行左外部联接或右外部联接,并进行一些额外的操作以添加空行。我是被点燃
select id, max(prev) as prev, signindate from
(
SELECT SIGNIN.ID,
SIGNIN.SignInDate as prev,
prev.signindate
FROM SIGNIN
JOIN SIGNIN as Prev on SIGNIN.ID = Prev.ID
and SIGNIN.SignInDate < Prev.SignInDate
ORDER BY SIGNIN.ID, SIGNIN.SignInDate
) a
group by 1,3
答案 4 :(得分:0)
我喜欢APPLY
解决方案,因为您可以从匹配的行中添加任意数量的列:
DECLARE @CutOffDate DATE = '2019-01-03'
SELECT
S.ID,
S.SignInDate,
PreviousSignInDate = R.SignInDate
FROM
[SIGNIN] AS S
OUTER APPLY (
SELECT TOP 1
P.* -- Can incorporate many columns (will also have to add them on the outmost SELECT list)
FROM
SIGNIN AS P
WHERE
S.ID = P.ID AND
P.SignInDate < S.SignInDate
ORDER BY
P.SignInDate DESC
) AS R
WHERE
S.SignInDate >= @CutOffDate
ORDER BY
S.SignInDate,
S.ID
在这种情况下,只要您具有链接TOP 1
并确保ORDER BY
,就可以使用S.ID = P.ID
+ P.SignInDate < S.SignInDate
来获取前一个。 / p>
还习惯于以YYYY-MM-DD
格式写日期,因为03/01/19
可能会引起混乱。
答案 5 :(得分:0)
相关子查询是一个非常简单的解决方案:
SELECT ID, SignInDate,
(SELECT top 1 SigInDate
FROM SIGNIN as S2
WHERE S2.ID = S1.ID and S2.SignInDate < S1.SignInDate
ORDER BY S2.SignInDate desc) as Previous
FROM SIGNIN as S1
ORDER BY S1.ID, S1.SignInDate
答案 6 :(得分:0)
我认为,如果您需要这样做,最好设置一个排序列,例如:
SELECT *, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY SignInDate) AS O FROM [SIGNIN]
所以最终结果将是:
SELECT t.ID, t.SignInDate [Sign-In Date], t2.SignInDate as Previous
FROM (SELECT *, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY SignInDate) AS O FROM [SIGNIN]) t
LEFT JOIN
(SELECT *, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY SignInDate) AS O FROM [SIGNIN]) t2 ON t.ID = t2.ID AND t.O = t2.O+1
应该给什么类似于:
A 2019-01-01 NULL
A 2019-01-04 2019-01-01
A 2019-02-01 2019-01-04
B 2019-01-01 NULL
B 2019-01-05 2019-01-01
C 2019-01-01 NULL
希望这会有所帮助。