1

我有一个复杂的查询,它连接不同的表来获取计数。有几个字段可以分组。现在,我想添加一个需要 case 语句的附加字段。而且这个字段也必须在分组列表中。我的查询最初看起来像这样 -

SELECT DMAGATR.WRK_LOC_LEVEL4 
     , DMBR.WRK_LOC_NM 
     , DMBR.RELCD 
     , COUNT(DISTINCT DMBR.DMBRKEY) AS ELIG_COUNT
      FROM DMBR 
INNER JOIN DCUST DCUST ON DMBR.DCUSTKEY = DCUST.DCUSTKEY
INNER JOIN DMAGATR DMAGATR ON DMBR.DMBRKEY = DMAGATR.DMBRKEY
 LEFT JOIN DMDYNATR DMDYNATR ON DMBR.DMBRKEY = DMDYNATR.DMBRKEY
     WHERE DMBR.C_TIMESSTAMP <= '12/31/2011'
       AND DMBR.RELCD IN ('0', '1') 
       AND DMBR.EE_STS IN ( 'A','L')
       AND (DMBR.DEL_DT IS NULL
        OR DMBR.DEL_DT > '12/31/2011')
       AND DCUST.PRCD = 'TAR'
  GROUP BY DMAGATR.WRK_LOC_LEVEL4, DMBR.WRK_LOC_NM, D_MEMBER.REL_CD

但新领域看起来像这样 -

(SELECT CASE
          WHEN (DMBR.WRK_LOC_NM = '6' AND DMBR.GDR = 'M' AND DMBR.REL_CD in ('0','1') 
            AND DMBR.EE_STS IN ('A','L')) THEN 'SEG 1'
          ELSE 'OTHER'
        END 
   FROM DMBR) as CMPN

我试图将它添加到选择列表中,但它不起作用。然后我在两个地方添加了它 - 在选择和分组列表中。那也没有用。

我得到的错误是:

  1. ORA-00904- CMPN 不是有效的列
  2. ORACLE 准备错误::ORA-22818此处不允许子查询表达式。

我在网上做了一些研究,发现了一些与我的很接近但并不完全相同的例子。

具有聚合函数的 SQL GROUP BY CASE 语句 不确定我是否理解这里的问题 SQL 查询与计数和案例语句 这与我的需要完全不同。 http://jerrytech.blogspot.com/2008/04/can-you-group-by-case-statement-in-sql.html (这很接近,但我不需要插入语句我尝试过这种方法但它没有为我工作)

任何建议,将不胜感激。

4

4 回答 4

1

我认为错误是您正在描述查询的字段(即:结果列),就像其他查询一样:DMAGATR.WRK_LOC_LEVEL4,DMBR.WRK_LOC_NM,DMBR.RELCD,COUNT (DISTINCT DMBR.DMBRKEY...

我认为错误在于,当对结果 COLUMN 使用 SQL-Select 语句时,它必须只返回一行。由于您的查询只是“... FROM DMBR ) as CMPN”,因此您返回的字段不止一行,并且没有数据库知道如何猜测您的结果。

您可能缺少的是字段上的 WHERE 子句,如果您正在从 DMBR 表中查找不同的值,则可能缺少 GROUP by。

解决这个问题,它应该会让你走得更远。不知道其余的数据结构或关系,我无法弄清楚你的最终结果是什么。


附加评论...

通过查看提供的其他答案,他们提出在您当前使用的任何“DMBR”记录上立即执行 CASE WHEN,这将是正确的,但不太有效。我认为由于两种可能的结果,它也必须是 group by 的一部分。作为 count(DISTINCT),group by 必须基于任何非聚合列...其中,这种情况/什么时候会这样......所以你的最终结果会有

Lvl, Work Loc, RelCD, Case/when, count(distinct)  where...
                        SEG 1     999
                        Other     999

此外,您的 CASE/WHEN 有两个组件与您的 WHERE 子句完全匹配,因此我将其从那里取出,因为无论如何都不会返回该集合的记录。

所以,说了这么多,我会把它写成...

SELECT
      DMAGATR.WRK_LOC_LEVEL4,
      DMBR.WRK_LOC_NM,
      DMBR.RELCD,
      CASE WHEN (DMBR.WRK_LOC_NM = '6' 
             AND DMBR.GDR = 'M' ) 
           THEN 'SEG 1'
           ELSE 'OTHER'
           END as WhenStatus,
      COUNT (DISTINCT DMBR.DMBRKEY) AS ELIG_COUNT
   FROM
      DMBR 
         JOIN DCUST 
            ON  DMBR.DCUSTKEY = DCUST.DCUSTKEY
         JOIN DMAGATR
            ON  DMBR.DMBRKEY = DMAGATR.DMBRKEY
         LEFT JOIN DMDYNATR
            ON  DMBR.DMBRKEY = DMDYNATR.DMBRKEY
   WHERE
          DMBR.C_TIMESSTAMP <= '12/31/2011'
      AND DMBR.REL_CD in ('0','1') 
      AND DMBR.EE_STS IN ('A','L')) 
      AND DCUST.PRCD = 'TAR'
      AND (    DMBR.DEL_DT IS NULL
           OR  DMBR.DEL_DT > '12/31/2011')
   GROUP BY 
      DMAGATR.WRK_LOC_LEVEL4,
      DMBR.WRK_LOC_NM,
      D_MEMBER.REL_CD,
      CASE WHEN (DMBR.WRK_LOC_NM = '6' 
            AND DMBR.GDR = 'M' ) 
          THEN 'SEG 1'
          ELSE 'OTHER'
          END

最后,有时,我看到 group by 会在复杂列上阻塞,例如 case / when。但是,不同的服务器允许对 group by(以及 order by)位置进行序号引用。因此,由于查询有 4 个非聚合列(全部列在最前面),然后是不同的计数,您可以通过将 GROUP BY 子句更改为...

按 1、2、3、4 分组

所有与开始 SQL-Select 调用的列的顺序有关。

--- 关于分组和区分大小写的澄清

首先,区分大小写,大多数引擎对关键字都区分大小写,因此 CASE WHEN ... AND ... THEN ... ELSE ... END。

至于“group by”(也适用于“order by”),它更像是查询中序数列的快捷方式,而不是显式列出长名称并必须重新键入整个 CASE 构造第二次,您可以通过查看以下(不相关的)查询让引擎知道您想要订购结果集中的哪一列......

select
      lastname,
      firstname,
      sum( orderAmount ) TotalOrders
   from
      customerOrders
   group by
      lastname,
      firstname
   order by 
     TotalOrders DESC

select
      lastname,
      firstname,
      sum( orderAmount ) TotalOrders
   from
      customerOrders
   group by
      1,
      2
   order by 
      3 DESC

每个都会产生相同的结果......虚构的 customerOrders 表将按姓氏和名字预先聚合,并显示每个人的总数(所有假设在此示例中没有重复的名称,否则,我会使用客户 ID) . 完成后,订单将启动,并将按降序排列列表顶部的给定客户的最多销售额。

这些数字仅代表查询中返回的序数列,而不是长时间键入字段名称。更多关于您的“CASE/WHEN”子句的问题,以防止 oops 重新输入并在组中丢失它并拉出您的头发找出原因。

于 2011-05-20T21:08:13.707 回答
1

我不知道您所说的“在 SELECT 列表中”是什么意思。我不知道为什么 CMPN 包含自己的 SELECT。您是否尝试执行以下操作,如果没有,目标有什么不同?

SELECT  
DMAGATR.WRK_LOC_LEVEL4 
,DMBR.WRK_LOC_NM 
,DMBR.RELCD 
,COUNT (DISTINCT DMBR.DMBRKEY) AS ELIG_COUNT
,(CASE
   WHEN (DMBR.WRK_LOC_NM = '6' 
   AND DMBR.GDR = 'M' 
   AND DMBR.REL_CD in ('0','1') 
   AND DMBR.EE_STS IN ('A','L')) 
 THEN 'SEG 1'
 ELSE 'OTHER'
END     
) as CMPN
FROM DMBR 
INNER JOIN  DCUST DCUST
    ON  DMBR.DCUSTKEY = DCUST.DCUSTKEY
INNER JOIN   DMAGATR DMAGATR
    ON  DMBR.DMBRKEY = DMAGATR.DMBRKEY
LEFT JOIN   DMDYNATR DMDYNATR
    ON  DMBR.DMBRKEY = DMDYNATR.DMBRKEY
WHERE    DMBR.C_TIMESSTAMP <= '12/31/2011'
AND DMBR.RELCD IN ('0', '1') 
AND DMBR.EE_STS IN ( 'A','L')
AND (DMBR.DEL_DT IS NULL
OR  DMBR.DEL_DT > '12/31/2011')
AND     DCUST.PRCD = 'TAR'
GROUP BY 
     DMAGATR.WRK_LOC_LEVEL4
    ,DMBR.WRK_LOC_NM
    ,D_MEMBER.REL_CD
    ,(CASE
   WHEN (DMBR.WRK_LOC_NM = '6' 
   AND DMBR.GDR = 'M' 
   AND DMBR.REL_CD in ('0','1') 
   AND DMBR.EE_STS IN ('A','L')) 
 THEN 'SEG 1'
 ELSE 'OTHER'
END)
于 2011-05-20T21:11:00.587 回答
1

如果其他答案不起作用,您也可以尝试这种(派生子查询)方法:

SELECT
      WRK_LOC_LEVEL4,
      WRK_LOC_NM,
      RELCD,
      CMPN,
      COUNT (DISTINCT DMBRKEY) AS ELIG_COUNT
FROM
  ( SELECT
          DMAGATR.WRK_LOC_LEVEL4,
          DMBR.WRK_LOC_NM,
          DMBR.RELCD,
          CASE WHEN (DMBR.WRK_LOC_NM = '6' 
                 AND DMBR.GDR = 'M' ) 
               THEN 'SEG 1'
               ELSE 'OTHER'
          END
            AS CMPN,
          DMBR.DMBRKEY
       FROM
          DMBR 
             JOIN DCUST 
                ON  DMBR.DCUSTKEY = DCUST.DCUSTKEY
             JOIN DMAGATR
                ON  DMBR.DMBRKEY = DMAGATR.DMBRKEY
             LEFT JOIN DMDYNATR
                ON  DMBR.DMBRKEY = DMDYNATR.DMBRKEY
       WHERE
              DMBR.C_TIMESSTAMP <= '12/31/2011'
          AND DMBR.REL_CD in ('0','1') 
          AND DMBR.EE_STS IN ('A','L')) 
          AND DCUST.PRCD = 'TAR'
          AND (    DMBR.DEL_DT IS NULL
               OR  DMBR.DEL_DT > '12/31/2011')
  ) AS TMP
GROUP BY 
   WRK_LOC_LEVEL4,
   WRK_LOC_NM,
   REL_CD,
   CMPN
于 2011-05-20T23:59:34.040 回答
0
    SELECT  
    DMAGATR.WRK_LOC_LEVEL4 
    ,DMBR.WRK_LOC_NM 
    ,DMBR.RELCD 
    ,COUNT (DISTINCT DMBR.DMBRKEY) AS ELIG_COUNT,
    (SELECT 
     CASE
    WHEN (DMBR.WRK_LOC_NM = '6' 
    AND DMBR.GDR = 'M' 
    AND DMBR.REL_CD in ('0','1') 
    AND DMBR.EE_STS IN ('A','L')) 
    THEN 'SEG 1'
    ELSE 'OTHER'
    END     
    ) as CMPN
    FROM DMBR 
    INNER JOIN  DCUST DCUST
        ON  DMBR.DCUSTKEY = DCUST.DCUSTKEY
    INNER JOIN   DMAGATR DMAGATR
        ON  DMBR.DMBRKEY = DMAGATR.DMBRKEY
    LEFT JOIN   DMDYNATR DMDYNATR
        ON  DMBR.DMBRKEY = DMDYNATR.DMBRKEY
    WHERE    DMBR.C_TIMESSTAMP <= '12/31/2011'
    AND DMBR.RELCD IN ('0', '1') 
    AND DMBR.EE_STS IN ( 'A','L')
    AND (DMBR.DEL_DT IS NULL
    OR  DMBR.DEL_DT > '12/31/2011')
    AND     DCUST.PRCD = 'TAR'
    GROUP BY 
    DMAGATR.WRK_LOC_LEVEL4
    ,DMBR.WRK_LOC_NM
    ,D_MEMBER.REL_CD,  DMBR.GDR, DBMR.EE_STS 
于 2011-05-20T21:20:40.690 回答