我有一个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
或以更有效的方式使用它吗?
编写查询的最有效方法可能是:
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;
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
窗口函数来避免max:
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;