1

目前我正面临一个 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

如您所见,我想按以下值对“计数”结果进行分组: - 事实上,给定的猫是家猫还是波斯猫 - 猫的颜色

第一个是困难的 - 我实际上不知道是否有可能执行“按连接表分组”?我很头疼,但找不到任何解决方案:(实际使用的 RDBMS 将是 Oracle 11。

4

5 回答 5

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 小提琴

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

于 2013-08-15T19:04:13.393 回答
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
于 2013-08-15T18:59:30.373 回答
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 演示

于 2013-08-15T19:15:52.517 回答
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 表一次,并且不会有太多重复的代码需要维护。

于 2013-08-15T20:26:46.640 回答
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

于 2013-11-14T21:00:51.490 回答