【问题标题】:How to use conditional group by aggregations correctly如何正确使用聚合条件组
【发布时间】:2019-07-01 02:32:46
【问题描述】:

我希望能够计算每个大陆的苹果总类型(仅限有机),按国家/地区分类;如果它们混合在一起,包括总数。

例如,食品 B1 是来自美国的有机金苹果。因此应该有一个计数“1”golden_bag 和“1”有机。现在,A1 也是来自阿根廷的有机产品 - 但是,它既有美味的奶奶苹果,也有美味的红苹果 - 因此它被计为“1”mixed_bag 和“1”用于 granny_bag 和“1”用于 red_bag。

最后,E1和F1都是老挝的富士苹果,一个是有机的,一个不是;所以总计数是 2 fuji_bag,它的总计数应该是 Organic_fd。

Table X:
food_item | food_area | food_loc   | food_exp
A1          lxgs        argentina   1/1/20
B1          iyan        usa         5/31/21
C1          lxgs        peru        4/1/20
D1          wa8e        norway      10/1/19
E1          894a        laos        5/1/19
F1          894a        laos        9/17/19


Table Y:
food_item | organic
A1          Y
B1          Y
C1          N
D1          N
E1          Y
F1          N

Table Z:
food_item | food_type
A1          189
A1          190
B1          191
C1          189
D1          192
E1          193
F1          193

SELECT continent, country,
      SUM(organic)  AS organic_fd, SUM(Granny) AS granny_bag,
      SUM(Red_delc) AS red_bag,    SUM(Golden) AS golden_bag,
      SUM(Gala)     AS gala_bag,   SUM(Fuji)   AS fuji_bag,
      SUM(CASE WHEN Granny + Red_delc + Golden + Gala + Fuji > 1 THEN 1  ELSE 0 END) AS mixed_bag     
FROM (SELECT (CASE SUBSTR (x.food_area, 4, 1)
              WHEN 's' THEN 'SA' WHEN 'n' THEN 'NA'
              WHEN 'e' THEN 'EU' WHEN 'a' THEN 'AS' ELSE NULL END) continent,
          x.food_loc country, COUNT(y.organic) AS Organic
          COUNT(CASE WHEN z.food_type = '189' THEN 1 END) AS Granny,
          COUNT(CASE WHEN z.food_type = '190' THEN 1 END) AS Red_delc,
          COUNT(CASE WHEN z.food_type = '191' THEN 1 END) AS Golden,
          COUNT(CASE WHEN z.food_type = '192' THEN 1 END) AS Gala,
          COUNT(CASE WHEN z.food_type = '193' THEN 1 END) AS Fuji      
    FROM x LEFT JOIN z ON x.food_item = z.food_item
           LEFT JOIN y on x.food_item = y.food_item and y.organic = 'Y'    
               WHERE  x.exp_date > sysdate
    GROUP BY SUBSTR (x.food_area, 4, 1), x.food_loc, y.organic) h
GROUP BY h.continent, h.country, h.organic

我没有得到正确的输出,例如,老挝将显示 TWICE 来说明有机计数和非有机计数。因此它将显示1 organic_fd0 organic_fd1 fuji_bag,另一行将是另一行1 fuji_bag。我想要总数。 (另外,如果我添加更多的食物,我的混合包会显示每条记录/行的计数大多为“1”)。

以下是所需的输出:

| continent | country   |organic_fd | granny_bag| red_bag| golden_bag| gala_bag|fuji_bag | mixed_bag
| SA        | argentina |    1      | 1         |   1    | 0         | 0       | 0       | 1
| SA        | peru      |    0      | 1         |   0    | 0         | 0       | 0       | 0
| NA        | usa       |    1      | 0         |   0    | 1         | 0       | 0       | 0
| EU        | norway    |    0      | 0         |   0    | 0         | 1       | 0       | 0
| AS        | laos      |    1      | 0         |   0    | 0         | 0       | 2       | 0

所以,假设我想添加另一种食品,来自挪威的 G1,它有 3 种有机苹果:fuji, red, granny... 那么挪威现在将有 1 的以下列计数:@987654329 @、organic_fdfuji_bagred_baggranny_bag(除了之前的1 gala_bag计数)。如果添加与 G1 完全相同的 H1,那么它现在将具有以下总数 2mixed_bagorganic_fdfuji_bagred_baggranny_bag

【问题讨论】:

    标签: sql oracle group-by aggregate-functions


    【解决方案1】:

    查询:

    WITH
      t AS (
        SELECT
          CASE SUBSTR(X.food_area, LENGTH(X.food_area), 1)
            WHEN 's' THEN 'SA'
            WHEN 'n' THEN 'NA'
            WHEN 'e' THEN 'EU'
            WHEN 'a' THEN 'AS'
            ELSE NULL
          END AS continent,
          x.food_loc AS country,
          COUNT(DISTINCT CASE Y.organic WHEN 'Y' THEN X.food_item END) OVER (
            PARTITION BY x.food_loc
          ) AS organic_fd,
          CASE
            WHEN MIN(Z.food_type) OVER (
                   PARTITION BY x.food_loc, X.food_item
                 ) = Z.food_type AND
                 MAX(Z.food_type) OVER (
                   PARTITION BY x.food_loc, X.food_item
                 ) > Z.food_type THEN 1 END AS mixed,
          Z.food_type
        FROM X
        JOIN Y ON X.food_item = Y.food_item
        JOIN Z ON Y.food_item = Z.food_item
      )
    SELECT
      continent, country, organic_fd,
      COUNT(CASE WHEN food_type = '189' THEN 1 END) AS Granny,
      COUNT(CASE WHEN food_type = '190' THEN 1 END) AS Red_delc,
      COUNT(CASE WHEN food_type = '191' THEN 1 END) AS Golden,
      COUNT(CASE WHEN food_type = '192' THEN 1 END) AS Gala,
      COUNT(CASE WHEN food_type = '193' THEN 1 END) AS Fuji,
      COUNT(mixed) AS mixed_bag
    FROM t
    GROUP BY continent, country, organic_fd
    

    您可以在此处尝试此查询:https://rextester.com/TSSH87409

    【讨论】:

    • 这行得通,但我需要了解更多关于“分区...”的信息,当我添加更多列时它会变得很复杂
    • @BFF,你遇到了什么麻烦?我想为您提供此链接作为起点stackoverflow.com/a/561884/3350428
    【解决方案2】:

    xz 之间存在一对多关系,并且连接可能会为 x 中的每一行生成许多行,就像 A1 的情况一样。所以你首先必须对x 中的行进行编号,这是我的子查询t1 所做的,除了映射值。然后将它们分组为每个计数列(奶奶、有机等)采用max(),就像在子查询t2 中一样。最后求和。

    dbfiddle demo

    with
      t1 as (
        select rn, food_item, food_area, food_loc country, food_exp, food_type,
               decode(substr(food_area, 4, 1), 's', 'SA', 'n', 'NA', 'e', 'EU', 'a', 'AS') continent,
               case organic when 'Y' then 1 else 0 end org,
               case when food_type = '189' then 1 else 0 end gra,
               case when food_type = '190' then 1 else 0 end red,
               case when food_type = '191' then 1 else 0 end gol,
               case when food_type = '192' then 1 else 0 end gal,
               case when food_type = '193' then 1 else 0 end fuj 
          from (select rownum rn, x.* from x) x join y using (food_item) join z using (food_item)
          where food_exp > sysdate),
      t2 as (
        select rn, country, continent, max(org) org, max(gra) gra, 
               max(red) red, max(gol) gol, max(gal) gal, max(fuj) fuj,
               case when max(gra) + max(red) + max(gol) + max(gal) + max(fuj) > 1 
                    then 1 else 0 
                end mix
           from t1 group by rn, country, continent)
    select continent, country, sum(org) organic_fd, sum(gra) granny, sum(red) red_delc, 
           sum(gol) golden_bag, sum(gal) gala_bag, sum(fuj) fuji_bag, sum(mix) mixed_bag 
      from t2 
      group by continent, country
    

    以上查询给出了预期的输出,请对其进行测试并根据需要进行调整。我注意到你使用左连接。如果X 中的某些行可能在YZ 中没有数据,您可能需要在计算中添加nvl()s。也许您还应该将映射的硬编码值放入表中。硬编码它们不是好的做法。希望这会有所帮助:)

    【讨论】:

    • 不知道为什么,但“使用”对我不起作用。不过,我很欣赏这个解释。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-22
    • 1970-01-01
    • 1970-01-01
    • 2020-11-22
    • 2021-12-05
    • 2021-06-15
    相关资源
    最近更新 更多