SQL - 向 SELECT 添加条件
Posted
技术标签:
【中文标题】SQL - 向 SELECT 添加条件【英文标题】:SQL - Adding conditions to SELECT 【发布时间】:2020-12-21 20:30:12 【问题描述】:我有一个表,其中包含机器的时间戳和 inCycle 状态。我正在使用两个 CTE 并在行号上执行 INNER JOIN,因此我可以轻松地将一行的时间戳与下一行的时间戳进行比较。我有 DATEDIFF 工作,现在我需要查看 inCycle 状态。基本上,如果 inCycleThis 和 inCycleNext 都 = 1,我需要将它添加到 InCycle 总数中。
类似地(显示的表格会说明这一点):
incycleThis/next = 0,1 = not in cycle
incycleThis/next = 0,0 = not in cycle
incycleThis/next = 1,1 = in cycle
如果我在做这个客户端,这将非常简单。由于有很多记录,我需要在存储过程中执行此操作。我很想在 SELECT 部分使用“IF”,但它似乎不是这样。
我在最后寻找的结果很简单:InCycle = Xtime
。比如:
SUM(Diff_seconds if((InCycleThis = 1 AND InCycleNext = 1) OR (InCycleThis = 1 AND InCycleNext = 0))
这是我目前所拥有的:
WITH History_CTE (DT, MID, FRO, IC, RowNum)
AS
(
SELECT DateAndTime
,MachineID
,FeedRateOverride
,InCycle
,ROW_NUMBER()OVER(ORDER BY MachineID, DateAndTime) AS "row number"
FROM History
WHERE DateAndTime >= '2020-11-15'
AND DateAndTime < '2020-11-16'
),
History2_CTE (DT2, MID2, FRO2, IC2, RowNum2)
AS
(
SELECT DateAndTime
,MachineID
,FeedRateOverride
,InCycle
,ROW_NUMBER()OVER(ORDER BY MachineID, DateAndTime) AS "row number"
FROM History
WHERE DateAndTime >= '2020-11-15'
AND DateAndTime < '2020-11-16'
)
SELECT DT as 'TimeStamp'
,DT2 as 'TimeStamp Next Row'
,MID
,FRO
,IC as 'InCycle this'
,IC2 as 'InCycle next'
,RowNum
,DATEDIFF(s, History2_CTE.DT2, History_CTE.DT) AS 'Diff_seconds'
FROM History_CTE
INNER JOIN
History2_CTE ON History_CTE.RowNum = History2_CTE.RowNum2 + 1
【问题讨论】:
尝试在 WHERE 中使用 CASE 条件。 ***.com/questions/13858239/… 请发布想要的结果。如果使用SUM
,您要根据哪些组进行聚合?
感谢 Mihal 的链接,如果我知道如何引用结果,我想我可以让 CASE 工作。我想我会添加一个新的 SELECT SUM('Diff_seconds') AS 'EarnedValue' FROM History_CTE - 但它不喜欢那样。如何参考之前的结果?
@Parfait - 从 InCyleThis = 1 AND InCycleNext = 1 OR InCycleThis = 1 AND InCyleNext = 0 的行中求和 Diff_seconds
除非我遗漏了什么,否则您的前两个 CTE 完全相同。您不需要其中的两个 - 只需将 History_CTE 自行加入即可。通过使用DATEDIFF(s,
而不是DATEDIFF(second,
,你真的有什么收获吗?哪个更具可读性?
【参考方案1】:
考虑添加第三个 CTE 以首先有条件地计算您需要的值。然后聚合为最终语句。召回 CTE 可以引用先前定义的 CTE。确保始终在 JOIN
查询中使用表别名来限定列。
WITH
... first two ctes...
, sub AS (
SELECT h1.DT AS 'TimeStamp'
, h2.DT2 AS 'TimeStamp Next Row'
, h1.MID
, h1.FRO
, h1.IC AS 'InCycle this'
, h2.IC2 AS 'InCycle next'
, h1.RowNum
, DATEDIFF(s, h2.DT2, h1.DT) AS 'Diff_seconds'
, CASE
WHEN (h1.IC = 1 AND h2.IC2 = 1) OR (h1.IC= 1 AND h2.IC2 = 0)
THEN DATEDIFF(s, h2.DT2, h1.DT)
END AS 'IC_Diff_seconds'
FROM History_CTE h1
INNER JOIN History2_CTE h2
ON h1.RowNum = h2.RowNum2 + 1
)
SELECT SUM([Diff_seconds]) AS Diff_seconds_Total
, SUM([IC_Diff_seconds]) AS IC_Diff_seconds_Total
FROM sub
如果需要添加分组,请合并GROUP BY
:
SELECT h1.MID
, h1.FRO
, SUM([Diff_seconds]) AS Diff_seconds_Total
, SUM([IC_Diff_seconds]) AS IC_Diff_seconds_Total
FROM sub
GROUP BY h1.MID
, h1.FRO
甚至按天汇总计算:
SELECT CONVERT(date, [TimeStamp]) AS [Day]
, SUM([Diff_seconds]) AS Diff_seconds_Total
, SUM([IC_Diff_seconds]) AS IC_Diff_seconds_Total
FROM sub
GROUP BY CONVERT(date, [TimeStamp])
【讨论】:
哇,这正是我的工作方向。希望我可以让它工作。【参考方案2】:我在最后寻找的结果很简单:
InCycle = Xtime
。比如:SUM(Diff_seconds if((InCycleThis = 1 AND InCycleNext = 1) OR (InCycleThis = 1 AND InCycleNext = 0))
据我了解您的问题,您只需将“循环中”行的时间戳与下一行的时间戳之间的差相加即可。
select machineid,
sum(datediff(s, dateandtime, lead_dateandtime)) as total_in_time
from (
select h.*,
lead(dateandtime) over(partition by machineid order by dateandtime) as lead_dateandtime
from history h
) h
where inclycle = 1
group by machineid
【讨论】:
我喜欢你用这个去哪里,它很简单。当我更正大写时,SQL 仍然不喜欢第 5 行开头的“引导”。为什么会这样,因为它似乎仍在运行。另外,我得到了 3 CTE 的东西,它比这个更简单的方法运行得更快(是的,我在参数中添加了它,所以它提取了相同数量的记录) @BrianTremelling:如果多 CTE 解决方案表现更好,我会感到惊讶。这两个查询的逻辑非常相似,但上面只使用了内置的窗口函数,而不是多个自连接。以上是关于SQL - 向 SELECT 添加条件的主要内容,如果未能解决你的问题,请参考以下文章
向已有 select_from() 的 SQL Alchemy 表达式添加连接