繁体   English   中英

如何在 SQL 服务器中使用带有 UNION ALL 的 WITH 子句

[英]How to use WITH clause with UNION ALL in SQL Server

我正在尝试,但我不知道如何将两个 SQL 语句(包括WITH子句)与UNION ALL结合起来。 在每个WITH SQL 语句中,不同之处在于WHERE子句。

WITH cte AS 
(
    SELECT 
        CMCONTRACTS.CMSERIALNUMBER, CMACTIVITIES.CMID, 
        CMACTIVITIES.CMSTART, CMACTIVITIES.CMFINISH, 
        CMACTIVITIES.CMSTATUSTYPE,
        ROW_NUMBER() OVER (PARTITION BY CMCONTRACTS.CMSERIALNUMBER 
                           ORDER BY CMACTIVITIES.CMFINISH DESC) RN
    FROM 
        CMACTIVITIES
    LEFT JOIN 
        CMCONTRACTS ON CMACTIVITIES.CMCONTRACTID = CMCONTRACTS.CMID
    WHERE 
        CMACTIVITIES.CMSTATUSTYPE = 3
)
SELECT 
    CMID, CMSTART, CMFINISH, CMSERIALNUMBER, CMSTATUSTYPE
FROM 
    cte
WHERE 
    RN = 1

UNION ALL

WITH cte AS 
(
    SELECT 
        CMCONTRACTS.CMSERIALNUMBER, CMACTIVITIES.CMID, 
        CMACTIVITIES.CMSTART, CMACTIVITIES.CMFINISH, 
        CMACTIVITIES.CMSTATUSTYPE,
        ROW_NUMBER() OVER (PARTITION BY CMCONTRACTS.CMSERIALNUMBER 
                           ORDER BY CMACTIVITIES.CMFINISH ASC) RN
    FROM 
        CMACTIVITIES
    LEFT JOIN 
        CMCONTRACTS ON CMACTIVITIES.CMCONTRACTID = CMCONTRACTS.CMID
    WHERE 
        CMACTIVITIES.CMSTATUSTYPE = '2'
)
SELECT 
    CMID, CMSTART, CMFINISH, CMSERIALNUMBER, CMSTATUSTYPE 
    -- GXSTARTDATE, GXENDDATE, GXFORMULA, GXPRLSID
FROM
    cte
WHERE 
    RN = 1

当我运行它时,出现以下错误:

消息 156,15 级,State 1,第 26 行
关键字“WITH”附近的语法不正确。

消息 319,15 级,State 1,第 26 行
关键字“with”附近的语法不正确。 如果此语句是公用表表达式、xmlnamespaces 子句或更改跟踪上下文子句,则前一个语句必须以分号结尾。

运行这两个单独的 SQL 查询会得到预期的结果。 但是我想从之前的两个 SQL 查询中获取所有结果,包括一个查询中的WITH子句。

你应该首先像这样制作 CTE:

 WITH cte
AS (SELECT
          CMCONTRACTS.CMSERIALNUMBER,
          CMACTIVITIES.CMID,
          CMACTIVITIES.CMSTART,
          CMACTIVITIES.CMFINISH,
          CMACTIVITIES.CMSTATUSTYPE,
          ROW_NUMBER() OVER (PARTITION BY CMCONTRACTS.CMSERIALNUMBER
                             ORDER BY CMACTIVITIES.CMFINISH DESC
                            ) RN
    FROM  CMACTIVITIES
          LEFT JOIN CMCONTRACTS ON CMACTIVITIES.CMCONTRACTID = CMCONTRACTS.CMID
    WHERE CMACTIVITIES.CMSTATUSTYPE = 3),
     cte2
AS (SELECT
          CMCONTRACTS.CMSERIALNUMBER,
          CMACTIVITIES.CMID,
          CMACTIVITIES.CMSTART,
          CMACTIVITIES.CMFINISH,
          CMACTIVITIES.CMSTATUSTYPE,
          ROW_NUMBER() OVER (PARTITION BY CMCONTRACTS.CMSERIALNUMBER
                             ORDER BY CMACTIVITIES.CMFINISH ASC
                            ) RN
    FROM  CMACTIVITIES
          LEFT JOIN CMCONTRACTS ON CMACTIVITIES.CMCONTRACTID = CMCONTRACTS.CMID
    WHERE CMACTIVITIES.CMSTATUSTYPE = '2')
SELECT
      CMID,
      CMSTART,
      CMFINISH,
      CMSERIALNUMBER,
      CMSTATUSTYPE
FROM  cte
WHERE RN = 1
UNION ALL
SELECT
      CMID,
      CMSTART,
      CMFINISH,
      CMSERIALNUMBER,
      CMSTATUSTYPE -- GXSTARTDATE, GXENDDATE, GXFORMULA, GXPRLSID
FROM  cte2
WHERE RN = 1;

在此特定实例中,您不需要两个 CTE,只需将CMACTIVITIES.CMSTATUSTYPE添加到PARTITION BY子句即可。

WITH cte AS (
    SELECT
          c.CMSERIALNUMBER,
          a.CMID,
          a.CMSTART,
          a.CMFINISH,
          a.CMSTATUSTYPE,
          ROW_NUMBER() OVER (PARTITION BY c.CMSERIALNUMBER, a.CMSTATUSTYPE
              ORDER BY
                  CASE WHEN a.CMSTATUSTYPE = 2 THEN a.CMFINISH END ASC,
                  CASE WHEN a.CMSTATUSTYPE = 3 THEN a.CMFINISH END DESC
                            ) RN
    FROM  CMACTIVITIES a
    LEFT JOIN CMCONTRACTS c ON a.CMCONTRACTID = c.CMID
    WHERE a.CMSTATUSTYPE IN (2, 3)
)
SELECT
      CMID,
      CMSTART,
      CMFINISH,
      CMSERIALNUMBER,
      CMSTATUSTYPE
FROM  cte
WHERE RN = 1;

不清楚CMSTATUSTYPE是字符串还是数字。 您应该坚持列被定义为的那个。

您接受的答案不是很干。

除了在不同的CMSTATUSTYPE上过滤和行编号的不同排序方向外,CTE 的两个分支几乎完全相同。

您无需使用LAGLEAD在两个方向上进行排序即可有效地获得此结果。

在下面,所有行的IsStartOfGroupIsEndOfGroup值都将具有0 ,除非没有上一行或下一行(分别),在这种情况下,该标志将设置为1

WITH CTE AS
(
SELECT   CMCONTRACTS.CMSERIALNUMBER,
                    CMACTIVITIES.CMID,
                    CMACTIVITIES.CMSTART,
                    CMACTIVITIES.CMFINISH,
                    CMACTIVITIES.CMSTATUSTYPE,
                    LAG(0,1,1) OVER (PARTITION BY CMCONTRACTS.CMSERIALNUMBER ORDER BY CMACTIVITIES.CMFINISH  ASC) AS IsStartOfGroup,
                    LEAD(0,1,1) OVER (PARTITION BY CMCONTRACTS.CMSERIALNUMBER ORDER BY CMACTIVITIES.CMFINISH ASC) AS IsEndOfGroup
          FROM      CMACTIVITIES
          LEFT JOIN CMCONTRACTS
          ON        CMACTIVITIES.CMCONTRACTID = CMCONTRACTS.CMID
          WHERE     CMACTIVITIES.CMSTATUSTYPE IN (2,3)
)
SELECT *
FROM CTE
WHERE (CMSTATUSTYPE = 2 AND IsStartOfGroup = 1) 
    OR (CMSTATUSTYPE = 3 AND IsEndOfGroup = 1)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM