考虑像
这样的表格tbl_ranks
--------------------------------
family_id | item_id | view_count
--------------------------------
1 10 101
1 11 112
1 13 109
2 21 101
2 22 112
2 23 109
3 30 101
3 31 112
3 33 109
4 40 101
4 51 112
4 63 109
5 80 101
5 81 112
5 88 109
我需要为查看计数排序的族id(例如1,2,3和4)的子集生成前两(2)行的结果集。 我想做一些像
这样的事情select top 2 * from tbl_ranks where family_id = 1 order by view_count
union all
select top 2 * from tbl_ranks where family_id = 2 order by view_count
union all
select top 2 * from tbl_ranks where family_id = 3 order by view_count
union all
select top 2 * from tbl_ranks where family_id = 4 order by view_count
但是,当然,以为单位>以这种方式在 union all 上下文中无效。有什么建议?我知道我可以运行一组4个查询,将结果存储到临时表中并选择该临时表的内容作为最终结果,但是如果可能的话我宁愿避免使用临时表。
注意:在真实应用中,每个系列ID的记录数量是不确定的,并且view_counts也没有像上面示例中显示的那样修复。
答案 0 :(得分:1)
使用:
SELECT *
FROM (select *,
ROW_NUMBER() OVER (PARTITION BY family_id ORDER BY view_count DESC) 'rank'
from tbl_ranks) x
WHERE x.rank <= 2
ORDER BY ...
理由是指定排名,然后根据它进行过滤。
答案 1 :(得分:1)
SELECT tro.*
FROM family
CROSS APPLY
(
SELECT TOP 2 *
FROM tbl_ranks tr
WHERE tr.family_id = family.id
ORDER BY
view_count DESC
) tro
WHERE family.id IN (1, 2, 3, 4)
如果您没有实际的family
表,可以使用一组联合或递归CTE构建它:
WITH family AS
(
SELECT 1 AS id
UNION ALL
SELECT 2 AS id
UNION ALL
SELECT 3 AS id
UNION ALL
SELECT 4 AS id
)
SELECT tro.*
FROM family
CROSS APPLY
(
SELECT TOP 2 *
FROM tbl_ranks tr
WHERE tr.family_id = family.id
ORDER BY
view_count DESC
) tro
WHERE family.id IN (1, 2, 3, 4)
确保您在tbl_ranks (family_id, viewcount)
上有索引。
如果每个家庭有很多排名,这将会很有效,因为ROW_NUMBER
等分析函数如果与TOP
一起使用,则不会使用PARTITION BY
方法。
答案 2 :(得分:1)
如果您使用的是SQL Server 2005或更高版本,则可以利用分析功能:
SELECT * FROM (
SELECT rank() OVER (PARTITION BY family_id ORDER BY view_count) AS RNK, * FROM ...
)
WHERE RNK <= 2
ORDER BY ...
答案 3 :(得分:1)
您可以尝试这样的事情
DECLARE @tbl_ranks TABLE(
family_id INT,
item_id INT,
view_count INT
)
INSERT INTO @tbl_ranks SELECT 1,10,101
INSERT INTO @tbl_ranks SELECT 1,11,112
INSERT INTO @tbl_ranks SELECT 1,13,109
INSERT INTO @tbl_ranks SELECT 2,21,101
INSERT INTO @tbl_ranks SELECT 2,22,112
INSERT INTO @tbl_ranks SELECT 2,23,109
INSERT INTO @tbl_ranks SELECT 3,30,101
INSERT INTO @tbl_ranks SELECT 3,31,112
INSERT INTO @tbl_ranks SELECT 3,33,109
INSERT INTO @tbl_ranks SELECT 4,40,101
INSERT INTO @tbl_ranks SELECT 4,51,112
INSERT INTO @tbl_ranks SELECT 4,63,109
INSERT INTO @tbl_ranks SELECT 5,80,101
INSERT INTO @tbl_ranks SELECT 5,81,112
INSERT INTO @tbl_ranks SELECT 5,88,109
SELECT *
FROm (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY family_id ORDER BY view_count DESC) MyOrder
FROM @tbl_ranks
) MyOrders
WHERE MyOrder <= 2
答案 4 :(得分:1)
您只需稍微调整建议的SQL命令,使其按您的需要运行。要绑定TOP和ORDER BY,您可以将语句放在您选择的paranthesis中并给出一个名称(此处不使用但需要)。
使用Adriaan Stander's answer中的DECLARE和INSERT语句以下
SELECT * FROM (SELECT TOP 2 * FROM @tbl_ranks WHERE family_id = 1 ORDER BY view_count) AS dummy1 UNION ALL
SELECT * FROM (SELECT TOP 2 * FROM @tbl_ranks WHERE family_id = 2 ORDER BY view_count) AS dummy2 UNION ALL
SELECT * FROM (SELECT TOP 2 * FROM @tbl_ranks WHERE family_id = 3 ORDER BY view_count) AS dummy3 UNION ALL
SELECT * FROM (SELECT TOP 2 * FROM @tbl_ranks WHERE family_id = 4 ORDER BY view_count) AS dummy4
给出
family_id item_id view_count
1 10 101
1 13 109
2 21 101
2 23 109
3 30 101
3 33 109
4 40 101
4 63 109