通过连接表执行聚合和分组查询

时间:2013-08-15 18:47:31

标签: sql oracle group-by aggregate-functions

目前我正面临SQL挑战,并且想知道,如果我的方法是正确的话。 让我们考虑以下简化数据模型:

Table CAT:
----------
ID
COLOR

Table DOMESTIC_CAT:
-------------------
CAT_ID
DOMESTIC_ATTRIBUTE

Table PERSIAN_CAT:
------------------
CAT_ID
PERSIAN_ATTRIBUTE

我们假设表格中有以下数据:

Table CAT:
ID   COLOR
--------------
1    'BLACK'
2    'WHITE'
3    'BLACK'
4    'WHITE'
5    'BLACK'
6    'RED'
7    'WHITE'
8    'WHITE'
9    'RED'
10   'BLACK'

Table DOMESTIC_CAT:
CAT_ID    DOMESTIC_ATTRIBUTE
----------------------------
1         'Domestic1'
2         'Domestic2'
3         'Domestic3'
7         'Domestic4'
8         'Domestic5'

Table PERSIAN_CAT
CAT_ID    PERSIAN_ATTRIBUTE
---------------------------
4         'Persian1'
5         'Persian2'
6         'Persian3'
9         'Persian4'
10        'Persian5'

我想使用以下结果执行聚合查询:

CAT_TYPE       CAT_COLOR   COUNT
---------------------------------
'DOMESTIC_CAT'    'BLACK'       2
'DOMESTIC_CAT'    'WHITE'       3
'PERSIAN_CAT'     'WHITE'       1
'PERSIAN_CAT'     'BLACK'       2
'PERSIAN_CAT'     'RED'         2

如您所见,我想通过以下值对'count'结果进行分组: - 事实上,给定的猫是国内的还是波斯的 - 猫的颜色

第一个是难事 - 我实际上不知道是否有可能执行“加入表组”?我打破了我的脑袋,但找不到任何解决方案:(实际使用的RDBMS将是Oracle 11。

5 个答案:

答案 0 :(得分:2)

您可以使用cat中的外部联接到其他表,并确定哪个表匹配,并使用它来填充cat_type列:

select case when dc.cat_id is not null then 'DOMESTIC_CAT'
    when pc.cat_id is not null then 'PERSIAN_CAT' end as cat_type,
  c.color,
  count(*) as "COUNT"
from cat c
left join domestic_cat dc on dc.cat_id = c.id
left join persian_cat pc on pc.cat_id = c.id
group by case when dc.cat_id is not null then 'DOMESTIC_CAT'
    when pc.cat_id is not null then 'PERSIAN_CAT' end,
  c.color
order by 1,2;

SQL Fiddle

根据您的实际问题,这可能比内部联接/联合选项更好,但您可能需要尝试两者以查看哪个更好(更快,更高效,更易维护......)。 / p>

答案 1 :(得分:1)

只做

SELECT 'DOMESTIC_CAT', c.color, count(*)
FROM domestic_cat d INNER JOIN cat c ON c.id = d.cat_id
GROUP BY c.color
UNION ALL
SELECT 'PERSIAN_CAT' .... the same for the other table

答案 2 :(得分:1)

另一种方法(Oracle 11g及更高版本):

select cat_type
     , color
     , cat_cnt
  from (select c.color
             , count(dc.domestic_attribute) as domestic_cat
             , count(pc.persian_attribute)  as persian_cat
         from cat c
         left join domestic_cat dc
           on (c.id1 = dc.cat_id)
         left join persian_cat  pc
           on (c.id1 = pc.cat_id)
        group by c.color
        )
unpivot(
  cat_cnt for  cat_type in (domestic_cat, persian_cat)
)
order by cat_type

结果:

CAT_TYPE           COLOR    CAT_CNT
------------------------------------
DOMESTIC_CAT    RED         0
DOMESTIC_CAT    WHITE       3
DOMESTIC_CAT    BLACK       2
PERSIAN_CAT     WHITE       1
PERSIAN_CAT     BLACK       2
PERSIAN_CAT     RED         2

SQLFiddle demo

答案 3 :(得分:1)

与安格斯的反应差别不大,但我更喜欢:

select ct.cat_type, c.color, count(*)
from cat c
    inner join (
        select 'DOMESTIC_CAT' cat_type, cat_id
        from domestic_cat
        union all
        select 'PERSIAN_CAT' cat_type, cat_id
        from persian_cat
    ) ct
        on ct.cat_id = c.id
group by ct.cat_type, c.color
order by ct.cat_type, c.color;

这只会在cat表上打一次,并且不会有太多重复的代码需要维护。

答案 4 :(得分:0)

WITH cat_types AS (
  SELECT CASE
         WHEN EXISTS ( SELECT 1 FROM domestic_cat d WHERE d.cat_id = c.id )
         THEN 'Domestic_Cat'
         WHEN EXISTS ( SELECT 1 FROM persian_cat d WHERE d.cat_id = c.id )
         THEN 'Persian_Cat'
         ELSE 'Unknown_Cat' END AS Cat_Type,
         id,
         color
  FROM   cat c
)
SELECT Cat_Type,
       Color,
       COUNT( 1 ) AS cat_cnt
FROM   cat_types
GROUP BY Cat_Type, color
ORDER BY Cat_Type, cat_cnt;

SQLFIDDLE