SQL 语法问题 - 分组依据 - Oracle

Posted

技术标签:

【中文标题】SQL 语法问题 - 分组依据 - Oracle【英文标题】:SQL Syntax Issue - Group By - Oracle 【发布时间】:2014-12-06 20:03:41 【问题描述】:

虽然我知道标题不是很具体并且我很抱歉,但我需要帮助解决我在使用 SQL 时遇到的语法问题,而且由于我不完全确定错误的语法部分,我再具体不过了。

如果有帮助,我正在使用 Oracle SQL Developer。

    SELECT DISTINCT pet.PET_NAME,
    CASE
      WHEN dog.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Dog'
      WHEN cat.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Cat'
      ELSE  ''
    END AS "Pet Type",
    SUM(res.RESERVATION_START_DATE - res.RESERVATION_END_DATE) AS "Days Stayed"
    FROM HVK_PET pet, HVK_DOG dog, HVK_CAT cat, HVK_RESERVATION res, HVK_PET_RESERVATION petRes
    WHERE (pet.PET_NUMBER = dog.PET_PET_NUMBER
    OR pet.PET_NUMBER = cat.PET_PET_NUMBER)
    AND res.RESERVATION_NUMBER = petRes.RES_RESERVATION_NUMBER  
    AND petRes.PET_PET_NUMBER = pet.PET_NUMBER
    GROUP BY pet.PET_NAME, dog.pet_pet_number, cat.pet_pet_number;

是我的完整代码,前 7 行带有黄色下划线,建议将 CASE 添加到我的 group by 语句中。我在 SQL 方面不是最棒的,所以如果它很明显,请不要犹豫,叫我出来。

【问题讨论】:

【参考方案1】:
SELECT pet.PET_NAME,
       CASE
          WHEN dog.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Dog'
          WHEN cat.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Cat'
          ELSE  ''
      END AS "Pet Type",
      SUM(res.RESERVATION_START_DATE - res.RESERVATION_END_DATE) AS "Days Stayed"
    FROM HVK_PET pet, HVK_DOG dog, HVK_CAT cat, HVK_RESERVATION res, HVK_PET_RESERVATION petRes
    WHERE (pet.PET_NUMBER = dog.PET_PET_NUMBER OR pet.PET_NUMBER = cat.PET_PET_NUMBER)
      AND res.RESERVATION_NUMBER = petRes.RES_RESERVATION_NUMBER  
      AND petRes.PET_PET_NUMBER = pet.PET_NUMBER
    GROUP BY pet.PET_NAME, 
             CASE
              WHEN dog.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Dog'
              WHEN cat.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Cat'
              ELSE  ''
            END;

dog.pet_pet_number, cat.pet_pet_number 分组不起作用,因为您在选择中的 CASE 以不适合 GROUP BY 的方式转换结果。

我想您不需要 DISTINCT,因为此关键字应用于选择列表中的所有表达式,并且在您的情况下使用它没有意义(在您分组时已经没有重复项)

【讨论】:

【参考方案2】:

有两种方法:

1.

 GROUP BY pet.PET_NAME,
          CASE
             WHEN dog.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Dog'
             WHEN cat.PET_PET_NUMBER = pet.PET_NUMBER THEN 'Cat'
             ELSE  ''
          END;
    使用INLINE 视图。

这里有一个类似的问题How do I use Group By based on a Case statement in Oracle?

【讨论】:

【参考方案3】:

首先,您不需要select distinctgroup by 几乎不需要这种结构。

您写的case 语句的问题在于它提到了三列,但group by 中只有两列。这个缺失的列是pet.PET_NUMBER。您可以将其添加到 group by,但有更简单的方法来编写您的查询。

关键是修复join语法,不要使用隐式连接:

SELECT pet.PET_NAME,
       MAX(CASE WHEN dog.PET_PET_NUMBER IS NOT NULL THEN 'Dog' ELSE 'CAT' END) AS "Pet Type",
       SUM(res.RESERVATION_START_DATE - res.RESERVATION_END_DATE) AS "Days Stayed"
FROM HVK_PET pet JOIN
     HVK_PET_RESERVATION petRes
     ON petRes.PET_PET_NUMBER = pet.PET_NUMBER JOIN
     HVK_RESERVATION res
     ON res.RESERVATION_NUMBER = petRes.RES_RESERVATION_NUMBER LEFT JOIN
     HVK_DOG dog
     ON pet.PET_NUMBER = dog.PET_PET_NUMBER LEFT JOIN
     HVK_CAT cat
     ON pet.PET_NUMBER = cat.PET_PET_NUMBER
GROUP BY pet.PET_PET_NUMBER, pet.PET_NAME;

left joins 引入了额外的,而不是,因此您将拥有“dog”列和“cat”列。这些可以很容易地用于SELECT 中的逻辑。假设给定的宠物要么是狗要么是猫,但绝不是两者兼而有之,查询只使用MAX(),而不是在group by 中包含其他列。

join 条件中删除or 应该会提高性能。

如果您正在学习 SQL,请学习正确的 ANSI 样式 join 语法。一个简单的规则:永远不要在from 子句中使用逗号。

【讨论】:

【参考方案4】:

只是另一个关于骑行和可读性的答案。从您的宠物开始并通过 LEFT-JOIN 加入 dog 或 cat 表,只能在其中一张表中找到。如果您允许其他宠物(鸟类、爬行动物等)留下来,您也可以在这些表中添加更多“LEFT JOIN”并调整 case/when 子句。

所以,情况/时间。如果找到狗的宠物号码匹配,那么您就完成了“狗”。如果没有,那么尝试“Cat”就失败了……如果没有,你就有了 else(或将来的任何其他宠物类型)。

我添加了 pet_number 以进行澄清,这也是您组的一部分...如果您有不止一只名为“闪电”的宠物(快狗或猫,每只都有不同的宠物编号),没有歧义。

另外,对于分组依据,我是在主要宠物的宠物编号列上进行的。在 dog 或 cat 表中找到它并不重要......无论在哪个表中找到它都是不同的数字。

最后,删除了 distinct。由于您按每个宠物编号/名称进行分组,并进行汇总,因此不会有任何重复基于生成的宠物类型...

SELECT 
      pet.PET_NAME,
      pet.PET_NUMBER,
      CASE WHEN dog.PET_PET_NUMBER IS NOT NULL THEN 'Dog'
           WHEN cat.PET_PET_NUMBER IS NOT NULL THEN 'Cat'
           ELSE  '' END AS "Pet Type",
      SUM(res.RESERVATION_START_DATE - res.RESERVATION_END_DATE) AS "Days Stayed"
   FROM 
      HVK_PET pet
         LEFT JOIN HVK_DOG dog
            ON pet.PET_NUMBER = dog.PET_PET_NUMBER
         LEFT JOIN HVK_CAT cat
            ON pet.PET_NUMBER = cat.PET_PET_NUMBER
         JOIN HVK_PET_RESERVATION petRes
            ON pet.PET_NUMBER = petRes.PET_PET_NUMBER 
            JOIN HVK_RESERVATION res
               ON petRes.RES_RESERVATION_NUMBER = res.RESERVATION_NUMBER
   GROUP BY 
      pet.PET_NAME, 
      pet.PET_NUMBER;

但是,如果 Oracle 表示由于您没有按宠物类型分组,因此并非所有列都属于 group by 聚合的一部分...并且宠物类型不会因特定宠物数量而改变,您可以只需将其更改为

MAX( case/when ) as PetType

(最后,我讨厌尝试在列中嵌入空格。可能会导致您意想不到的问题,尤其是如果您忘记“引用”它们。)

【讨论】:

以上是关于SQL 语法问题 - 分组依据 - Oracle的主要内容,如果未能解决你的问题,请参考以下文章

分组依据 - SQL Oracle 错误:无效项目

Oracle SQL 行到具有分组依据和总和的列

无效的请求“分组依据”(oracle)

在猪中使用过滤器和分组依据

带有排序依据的 SQL 分组依据

sql 获取分组第一行数据