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 表达式添加连接

当窗口/分区使用前向填充时,向 pyspark sql 中的 last() 函数添加条件

mybatis-向sql中添加判断条件

mybatis-向sql中添加判断条件

如何使用循环根据条件向html标签添加属性

往sql表里添加数据怎样先访问数据库没有此数据就能添加,