TSQL 根据提供的记录集获取以前的和任何进行的记录
Posted
技术标签:
【中文标题】TSQL 根据提供的记录集获取以前的和任何进行的记录【英文标题】:TSQL get the previous and any proceeding records based on recordset provided 【发布时间】:2021-11-11 15:04:28 【问题描述】:我有以下疑问:
SELECT
fs.FILOID currentfilo,
ISNULL(LEAD(af.FILOID) OVER (ORDER BY StartTransactionTimeUTC), fs.Next_FILOID) Nextfilo,
ISNULL(LAG(af.FILOID) OVER (ORDER BY StartTransactionTimeUTC), fs.Previous_FILOID) lf
FROM
[DataWarehouseCore].[DWC_FILOSummary] fs
JOIN
[AttendanceCore].[AC_FILO] af ON af.FILOID = fs.FILOID
WHERE
fs.Employee_ID = 15049
AND Client_ID = 306
返回以下结果:
currentfilo Nextfilo lf
----------------------------
5 2 NULL
2 3 5
3 6 2
6 7 3
7 1 6
1 NULL 7
如果传入了 ID 6,我只想查看 currentfilo 3, 6, 7 , 1。因此,与其返回结果集中的内容,不如只返回实际上基于日期字段的上一个和下一个记录.
这是一些数据示例,我希望看到的是父表:AC_FILO
FILOID ClientID EmployeeID StartTransactionTimeUTC
-----------------------------------------------------------
5 306 15049 2021-08-29 02:53:00.0000000
2 306 15049 2021-09-01 06:46:00.0000000
3 306 15049 2021-09-02 07:50:00.0000000
6 306 15049 2021-09-06 08:56:00.0000000
7 306 15049 2021-09-10 07:58:00.0000000
1 306 15049 2021-09-15 07:45:00.0000000
我想要在我的新表中是当前 FILOID 的有序列表,下一个 FILOID 和前一个 FILOID 是基于 StartTransactionTimeUTC
例如,当插入 FILOID 6 时,我希望查看前一个 FILOID 到 FILOID 6,然后是基于日期的所有正在进行的 FILOID!
例如我想看看
CurrentFilo NextFilo LastFilo
-----------------------------
3 6 2
6 7 3
7 1 6
1 NULL 7
【问题讨论】:
您需要使用子查询和STRING_AGG
来实现此目的,并且由于三角连接,此查询不太可能高效。
in the order they are in this table
数据在表中没有订单,如果没有提供order by
,数据库引擎将返回未排序的数据,所以你的方法是行不通的
在这个数据和这个结果集中,当你说“ID = 6”时,“ID”是什么。我对您的数据了解不够,无法在此处提供指导。我假设FILOID
但它存在于两个表中,并且存在于结果集中的所有三列中。这是该数据中的父/子关系吗?如果是这样,递归 CTE 将解决您的问题。
【参考方案1】:
目前尚不完全清楚您在追求什么,但考虑到最终所需的结果和 6
的输入值,我认为这意味着您想要由 StartTransactionTimeUTC
排序的 (CurrentFilo, NextFilo,LastFilo)
集合,从以下点开始鉴于NextFilo
发生,因为6
输入与预期结果中该位置的6
匹配。
作为第一步,从不关心传入的任何内容开始,只为整个表创建下一个/最后一个结果。我们可以使用LAG()
和LEAD()
窗口函数来做到这一点。
您已经在问题的第一个代码清单中完成了大部分工作,但我们现在还包括 StartTransactionTimeUTC
字段,以便我们能够在后面的步骤中重现正确的顺序。我现在也在使用一个简化的模式,所以我可以在 SQL Fiddle 上重现它:
SELECT FILOID as CurrentFILO,
LEAD(FILOID) OVER (ORDER BY StartTransactionTimeUTC) as NextFILO,
LAG(FILOID) OVER (ORDER BY StartTransactionTimeUTC) as LastFILO,
StartTransactionTimeUTC
FROM AC_FILO
现在,对于给定的 NextFILO
值,例如 6
,我们可以使用公用表表达式 (CTE) 找到该记录所需的 StartTransactionTimeUTC
时间,如下所示:
WITH FILOTree AS (
SELECT FILOID as CurrentFILO,
LEAD(FILOID) OVER (ORDER BY StartTransactionTimeUTC) as NextFILO,
LAG(FILOID) OVER (ORDER BY StartTransactionTimeUTC) as LastFILO,
StartTransactionTimeUTC
FROM AC_FILO
)
SELECT StartTransactionTimeUTC
FROM FILOTree
WHERE NextFILO = 6
我们也可以使用嵌套的内部 SELECT 来代替 CTE。重要的是我们需要在初始查询周围设置一层间接层,以便将WHERE
子句与LAG()
或LEAD()
等窗口函数一起使用。但在这种情况下,我更喜欢 CTE,原因稍后会清楚。
一旦我们知道正确的StartTransactionTimeUTC
,我们就可以使用相同的技术获得最终结果:
WITH FILOTree AS (
SELECT FILOID as CurrentFILO,
LEAD(FILOID) OVER (ORDER BY StartTransactionTimeUTC) as NextFILO,
LAG(FILOID) OVER (ORDER BY StartTransactionTimeUTC) as LastFILO,
StartTransactionTimeUTC
FROM AC_FILO
)
SELECT CurrentFILO, NextFILO, LastFILO
FROM FILOTree
WHERE StartTransactionTimeUTC >= '2021-09-02 07:50:00'
ORDER BY StartTransactionTimeUTC
这会产生正确的结果,但输入错误。但是,现在我们可以使用相同的 CTE(啊哈!)将两个部分放在同一个查询中,而无需为初始当前/下一个/最后一个投影重复代码,如下所示:
WITH FILOTree As (
SELECT FILOID as CurrentFILO,
LEAD(FILOID) OVER (ORDER BY StartTransactionTimeUTC) as NextFILO,
LAG(FILOID) OVER (ORDER BY StartTransactionTimeUTC) as LastFILO,
StartTransactionTimeUTC
FROM AC_FILO
)
SELECT CurrentFILO, NextFILO, LastFILO
FROM FILOTree
WHERE StartTransactionTimeUTC >= (
SELECT StartTransactionTimeUTC
FROM FILOTree
WHERE NextFILO = 6
)
ORDER BY StartTransactionTimeUTC
在这里查看它的工作原理:
http://sqlfiddle.com/#!18/24979/2
最后,正如我之前所说,这些示例使用来自实际生产系统的简化模式。因此,让我们将原始查询插入 CTE:
WITH FILOTree As (
SELECT fs.FILOID currentfilo
, ISNULL(LEAD(af.FILOID) over (order by StartTransactionTimeUTC), fs.Next_FILOID) Nextfilo
, ISNULL(LAG(af.FILOID) over (order by StartTransactionTimeUTC), fs.Previous_FILOID) LastFILO
, StartTransactionTimeUTC
FROM [DataWarehouseCore].[DWC_FILOSummary] fs
JOIN [AttendanceCore].[AC_FILO] af ON af.FILOID = fs.FILOID
WHERE fs.Employee_ID = 15049
AND Client_ID = 306
)
SELECT CurrentFILO, NextFILO, LastFILO
FROM FILOTree
WHERE StartTransactionTimeUTC >= (
SELECT StartTransactionTimeUTC
FROM FILOTree
WHERE NextFILO = 6
)
ORDER BY StartTransactionTimeUTC
我必须从最初的 SQL 命令更改的唯一事情是将 StartTransactionTimeUTC
添加到 SELECT
列表和 LastFILO
列的别名。
请注意,这将运行 CTE 两次,并且它不会缓存两次运行之间的任何结果,因此请注意这是性能问题。
【讨论】:
这正是我想到的,非常感谢!以上是关于TSQL 根据提供的记录集获取以前的和任何进行的记录的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 TSQL 而不是 linq 获取和跳过记录 [重复]