我在日常查询中越来越多地使用窗口函数,并且一直想知道自己是否正确执行了操作。
假设我们有一个数据库dbo.songs
,其中每首歌曲包含一个记录,并包含以下列:artist
,songName
和releaseDate
。
对于每个艺术家,我想选择他们的第一个songName
和releaseDate
,按releaseDate
升序排列。请注意,对artist
进行分组的决定是任意的-明天,我可能需要按不同的列(BPM,专辑,长度)进行分组。
为此,我们有一些选择:
最近,我一直在使用“一系列范围相同的窗口函数”策略,该策略看起来像这样:
SELECT DISTINCT
s.artist
, FIRST_VALUE(s.songName) OVER (PARTITION BY s.artist ORDER BY s.releaseDate ASC) AS songName
, FIRST_VALUE(s.releaseDate) OVER (PARTITION BY s.artist ORDER BY s.releaseDate ASC) AS releaseDate
FROM dbo.songs s
这似乎有点草率,不是吗?它完全依靠DISTINCT
来避免一百万重复的行,并且,如果您想选择其他字段(BPM,专辑,长度),则需要更多的窗口函数,我认为这将算作RBAR。>
选项二是“先确定键,然后加入自我”,如下所示:
WITH earliestArtistRelease AS (
SELECT
s.artist
, MIN(s.releaseDate) AS releaseDate
FROM dbo.songs s
GROUP BY s.artist
)
SELECT
e.artist
, e.releaseDate
, s.songName
FROM dbo.songs s
INNER JOIN earliestArtistRelease e
ON s.releaseDate = e.releaseDate
AND s.artist = e.artist
这可以完成工作,但是效率似乎并不高-特别是如果我们在releaseDate
和artist
上没有索引。如果一位艺术家每天发行两首歌曲,我们也会遇到问题。
此外,如果我们要进行一些时髦的优先级排序(可能的话,请选择2018年1月1日发行的歌曲,否则请选择最早发行的歌曲),我们几乎无法像使用窗口函数那样轻松地做到这一点:{{ 1}},这有点古怪,但简洁。
我们还有其他选择:使用OVER (PARTITION BY s.artist ORDER BY IIF(s.releaseDate = '20180101', '19000101', s,releaseDate))
的self-CROSS APPLY
,但据我所知,它们的效率或简明程度都比“绑定相同范围的窗口函数”上面概述的策略。
所以,我的问题是:最佳实践是什么?您将如何处理这个问题,既节省处理器周期,又避免代码库长度加倍?一个选项在CTE内部是否更好,而另一个选项在插入临时表中更好?
任何与现有标准,论文或资源的链接都将受到赞赏。
答案 0 :(得分:4)
1)您应该首先获得与众不同的艺术家。如果您已有艺术家表,则从中选择。如果您不这样做,则创建一个歌手表,并用一个外键使歌曲表与之相关。
2)完成此操作后,CROSS APPLY
将是检索相关歌曲数据的合适运算符。
SELECT a.artist, t.songName, t.releaseDate
FROM artists a
CROSS APPLY (
SELECT TOP 1 s.songName, s.releaseDate
FROM songs s
WHERE s.artistId = a.artistId
-- any other "funky" prioritization.
ORDER BY s.releaseDate ASC
) topSongs t
答案 1 :(得分:0)
您可以使用pip3 install keras
或分析函数:
subquery