【问题标题】:SQL How to show & group by two same columns of which one is more filtered?SQL如何按两个相同的列显示和分组,其中一个更过滤?
【发布时间】:2017-11-08 13:16:14
【问题描述】:

需要显示一些列,例如年、周、严重性、警报和与以前相同的警报,只是过滤更多。如何添加最后一列,和上一列一样,只是过滤更多?

例子:

SELECT 
CAST(DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) AS VARCHAR) AS YEAR,
CAST(DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) AS VARCHAR) AS MONTH,
rSEV.NAME AS SEVERITY,
COUNT(rSTA.ALARMIDKEY) AS ALARMS
FROM 
    REPORTER.reporter.REPORTER_STATUS rSTA
INNER JOIN
    REPORTER.reporter.REP_SEVERITY_TYPES rSEV
    ON
    rSTA.ORIGINALSEVERITY = rSEV.SEVERITY
WHERE
    rSTA.FIRSTOCCURRENCEDAY > DATEADD(week, -10, GETDATE())
    AND
    rSEV.NAME != 'Clear'
GROUP BY
    DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ),
    DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ),
    rSEV.NAME
ORDER BY
    DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) DESC,
    DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) DESC

此查询正确生成前 4 列,附上图片:ALARMS

第五列应该和ALARMS一样,但是有条件:

SELECT ALARMIDKEY AS ALARMS_CC FROM REPORTER.reporter.REPORTER_STATUS WHERE
                    (MAINTMODECRONTAB != 'Y'
                     AND SUPPRESSESCL < 4
                     AND SPMAUTO != 1
                     AND ORIGINALSEVERITY > 0)
                     AND ((AIWAVER = 3 AND EVENTACTOR = 1)
                          OR
                          ((AIWAVER < 3 OR AIWAVER IS NULL)
                           AND ((CONTROLCENTREVIEW = 1
                                 AND ORIGINALSEVERITY = 5)
                                OR (CONTROLCENTREVIEW = 2)
                                OR (ALERTGROUP = 'CHECKLIST')
                               )
                          )
                         )

现在我想知道如何将此条件添加到主(第一个)查询中并将其分组,以便生成正确的数据。对于每年,每周和严重性显示警报和警报CC(同一列,只是不同的条件)。 我希望它看起来像这样:ALARMS_CC

希望它能清楚地说明我想要实现的目标。如果实现这一目标的方法更加优化,那就太好了。也许JOIN是可能的?

【问题讨论】:

  • 您确定需要两个不同数据库的答案吗?
  • 这是同一个数据库,年、周和警报位于同一个表中。严重性取自另一个表。
  • 您已经标记了 Microsoft SQL Server 和 MySQL 的问题。这是两个不同的关系数据库管理系统。两者都需要一个答案吗?
  • 对不起,不知何故搞砸了标签。现在修好了。正在使用 MSSQL 服务器。

标签: sql sql-server join subquery


【解决方案1】:

您可以尝试使用本文中引用的 case 语句 - How to count by filter in SQL query?

所以查询看起来像

    SELECT 
        CAST(DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) AS VARCHAR) AS YEAR,
        CAST(DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) AS VARCHAR) AS MONTH,
        rSEV.NAME AS SEVERITY,
        COUNT(rSTA.ALARMIDKEY) AS ALARMS,

        SUM(CASE WHEN rSTA.MAINTMODECRONTAB != 'Y'
                             AND rSTA.SUPPRESSESCL < 4
                             AND rSTA.SPMAUTO != 1
                             AND rSTA.ORIGINALSEVERITY > 0)
                             AND ((rSTA.AIWAVER = 3 AND rSTA.EVENTACTOR = 1)
                                  OR
                                  ((rSTA.AIWAVER < 3 OR rSTA.AIWAVER IS NULL)
                                   AND ((rSTA.CONTROLCENTREVIEW = 1
                                         AND rSTA.ORIGINALSEVERITY = 5)
                                        OR (rSTA.CONTROLCENTREVIEW = 2)
                                        OR (rSTA.ALERTGROUP = 'CHECKLIST')
                                       )
                                  ))
                    THEN 1
                    ELSE 0 END) AS ALARMS_CC
    FROM 
        REPORTER.reporter.REPORTER_STATUS rSTA
    INNER JOIN
        REPORTER.reporter.REP_SEVERITY_TYPES rSEV
        ON
        rSTA.ORIGINALSEVERITY = rSEV.SEVERITY
    WHERE
        rSTA.FIRSTOCCURRENCEDAY > DATEADD(week, -10, GETDATE())
        AND
        rSEV.NAME != 'Clear'
    GROUP BY
        DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ),
        DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ),
        rSEV.NAME
    ORDER BY
        DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) DESC,
        DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) DESC

更新

我正在下面添加一个更优化的查询。

    WITH REPORTER_STATUS_FILTERED AS
    (
        SELECT ALARMIDKEY
        FROM REPORTER.reporter.REPORTER_STATUS
        WHERE MAINTMODECRONTAB != 'Y'
            AND SUPPRESSESCL < 4
            AND SPMAUTO != 1
            AND ORIGINALSEVERITY > 0)
            AND ((AIWAVER = 3 AND EVENTACTOR = 1)
                OR
                ((AIWAVER < 3 OR AIWAVER IS NULL)
                AND ((CONTROLCENTREVIEW = 1
                        AND ORIGINALSEVERITY = 5)
                    OR (CONTROLCENTREVIEW = 2)
                    OR (ALERTGROUP = 'CHECKLIST')
                    )
                ))
    )

    SELECT 
        CAST(DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) AS VARCHAR) AS YEAR,
        CAST(DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) AS VARCHAR) AS MONTH,
        rSEV.NAME AS SEVERITY,
        COUNT(rSTA.ALARMIDKEY) AS ALARMS,
        COUNT(rSTA1.ALARMIDKEY) AS ALARMS_CC
    FROM 
        REPORTER.reporter.REPORTER_STATUS rSTA
    INNER JOIN
        REPORTER.reporter.REP_SEVERITY_TYPES rSEV
        ON
        rSTA.ORIGINALSEVERITY = rSEV.SEVERITY
    LEFT JOIN
        REPORTER_STATUS_FILTERED rSTA1
        ON
        rSTA.ALARMIDKEY = rSTA1.ALARMIDKEY
    WHERE
        rSTA.FIRSTOCCURRENCEDAY > DATEADD(week, -10, GETDATE())
        AND
        rSEV.NAME != 'Clear'
    GROUP BY
        DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ),
        DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ),
        rSEV.NAME
    ORDER BY
        DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) DESC,
        DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) DESC

【讨论】:

  • 是的,它似乎可以使用 10 周,如果我设置 54 周,则需要相当长的时间。想知道它是否可以优化,或者就是这样?
  • 我已经用更优化的答案更新了答案。你能试试吗?
【解决方案2】:

您可以通过子查询选择附加过滤警报,如下所示:

SELECT 
    CAST(DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) AS VARCHAR) AS YEAR,
    CAST(DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) AS VARCHAR) AS MONTH,
    rSEV.NAME AS SEVERITY,
    COUNT(rSTA.ALARMIDKEY) AS ALARMS,
    filtered.ALARMS_CC
FROM REPORTER.reporter.REPORTER_STATUS rSTA
INNER JOIN REPORTER.reporter.REP_SEVERITY_TYPES rSEV
           ON rSTA.ORIGINALSEVERITY = rSEV.SEVERITY
INNER JOIN (SELECT COUNT(ALARMIDKEY) AS ALARMS_CC, 
                   DATEPART( yy, FIRSTOCCURRENCEDAY ) AS year, 
                   DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) AS month,
                   ORIGINALSEVERITY AS os
            FROM REPORTER.reporter.REPORTER_STATUS 
            WHERE
                (MAINTMODECRONTAB != 'Y'
                 AND SUPPRESSESCL < 4
                 AND SPMAUTO != 1
                 AND ORIGINALSEVERITY > 0)
                 AND ((AIWAVER = 3 AND EVENTACTOR = 1)
                      OR
                      ((AIWAVER < 3 OR AIWAVER IS NULL)
                       AND ((CONTROLCENTREVIEW = 1
                             AND ORIGINALSEVERITY = 5)
                            OR (CONTROLCENTREVIEW = 2)
                            OR (ALERTGROUP = 'CHECKLIST')
                           )
                      )
                     )
            GROUP BY DATEPART( yy, FIRSTOCCURRENCEDAY ), 
                     DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ),
                     ORIGINALSEVERITY 
          ) AS filtered ON DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) = filtered.year AND
                           DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) = filtered.month AND
                           rSTA.ORIGINALSEVERITY = filtered.os
WHERE
    rSTA.FIRSTOCCURRENCEDAY > DATEADD(week, -10, GETDATE())
    AND
    rSEV.NAME != 'Clear'
GROUP BY
    DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ),
    DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ),
    rSEV.NAME
ORDER BY
    DATEPART( yy, rSTA.FIRSTOCCURRENCEDAY ) DESC,
    DATEPART( wk, rSTA.FIRSTOCCURRENCEDAY ) DESC

【讨论】:

  • 它似乎确实有效!如果我添加 54 周而不是 10 周,它不会影响完成查询的时间。谢谢!
【解决方案3】:
select YEAR, MONTH, SEVERITY, ALARMS, ALARMS_CC 
from (Q1) as T1 left join (Q2) as T2 on
T1.YEAR = T2.YEAR 
and T1.MONTH = T2.MONTH
and T1.SEVERITY = T1.SEVERITY
ORDER BY YEAR DESC, MON DESC

Q1 是您的查询,没有按部分排序 并且 Q2 是带有附加条件的第一个查询,并且最后一个 column_name 已更改。 重要的是把 Q1、Q2 放在括号 () 中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多