我有一个带有join和group-by的查询,它返回如下内容:
CONSTRUCTOR | MODEL | COLOR
------------+-------+------
Mercedes | SLK | Gray
Ferrari | 430 | Red
Mercedes | GLK | Black
Porsche | 911 | Blue
Ferrari | 458 | Red
我想按CONSTRUCTOR
添加一个组,如果每个组中的颜色相同,则获取颜色的值;如果有多个值,则获取“倍数”(对MODEL
不感兴趣)
CONSTRUCTOR | COLOR
------------+---------
Mercedes | multiple
Ferrari | Red
Porsche | Blue
此查询有效,但我想知道是否有更有效的方法来实现相同的结果而不会使查询本身复杂化
SELECT
CONSTRUCTOR,
CASE COUNT(DISTINCT COLOR)
WHEN 1 THEN MIN(COLOR)
ELSE 'multiple'
END AS COLOR
FROM MYTABLE
GROUP BY CONSTRUCTOR
我认为我无法避免MIN
(或MAX
)closely related question。
我可以避免使用CASE
或以更有效的方式使用它吗?
答案 0 :(得分:2)
编写查询的最有效方法可能是:
SELECT CONSTRUCTOR,
(CASE WHEN MIN(COLOR) = MAX(COLOR) THEN MIN(COLOR)
ELSE 'multiple'
END) AS COLOR
FROM MYTABLE
GROUP BY CONSTRUCTOR;
通常,COUNT(DISTINCT)
比其他聚合函数更昂贵。仅使用MIN()
和MAX()
应该会更有效率。使用CASE
几乎没有任何开销。
如果值为NULL
,您可以考虑附加条件:
SELECT CONSTRUCTOR,
(CASE WHEN MIN(COLOR) = MAX(COLOR) AND COUNT(COLOR) = COUNT(*)
THEN MIN(COLOR)
ELSE 'multiple'
END) AS COLOR
FROM MYTABLE
GROUP BY CONSTRUCTOR;
答案 1 :(得分:1)
CTE:
With g as (
select
CONSTRUCTOR,
count(distinct color) as n_colors,
max(color) as color
from MYTABLE
group by CONSTRUCTOR
)
select CONSTRUCTOR,
case when n_colors = 1 then color
else 'multiple' end
from g;
解释:您可以使用CTE句子烹饪数据,然后以简单的方式使用预先烹饪的数据进行最终查询。 CTE是你的朋友。
注意:优雅的方式看起来是窗口函数。但count( distinct
条款不允许over partition
。
编辑编辑OP评论:
您可以使用first_value
窗口函数来避免最大化:
With g1 as (
select
CONSTRUCTOR,
count(distinct color) as n_colors
from t
group by cons
),
g2 as (
select distinct
CONSTRUCTOR,
first_Value(color) over (partition by cons order by color) as color
from t
)
select g1.cons,
case when g1.n_colors = 1 then g2.color
else 'multiple' end
from g1 inner join g2 on g1.CONSTRUCTOR = g2.CONSTRUCTOR
最终答案
没有group by
,使用窗口函数,索引友好(通过CONSTRUCTOR和COLOR):
with cte as (
select
CONSTRUCTOR,
first_Value(color) over (partition by CONSTRUCTOR order by color
rows BETWEEN UNBOUNDED PRECEDING AND
UNBOUNDED FOLLOWING ) as f,
last_Value(color) over (partition by CONSTRUCTOR order by color
rows BETWEEN UNBOUNDED PRECEDING AND
UNBOUNDED FOLLOWING ) as l,
ROW_NUMBER ( ) over (partition by CONSTRUCTOR order by color ) as n
from t
)
select CONSTRUCTOR,
case when f=l then f else 'multiple' end as color
from cte
where n = 1;