SQL拼图 - UNION ALL没有UNION ALL

时间:2015-11-12 23:31:18

标签: sql intersystems-cache

这是挑战你的SQL拼图:

编写一个查询,选择三个不同类别中的前5个记录。

这样的事情:

select top 5 name, age from table1 where category = 22 order by age desc
union all
select top 5 name, age from table1 where category = 27 order by age desc
union all
select top 5 name, age from table1 where category = 53 order by age desc

但是没有使用UNION或UNION ALL

如果您使用某些特定于供应商的SQL扩展,请指定您正在使用的数据库。

4 个答案:

答案 0 :(得分:3)

经典top-n-per-group,不是吗?

使用SQL Server语法。 ROW_NUMBER()应该在2015年的所有体面的数据库中。

WITH
CTE
AS
(
    select 
        name
        ,age
        ,ROW_NUMBER() OVER (PARTITION BY category ORDER BY age desc) AS rn
    from table1
    where category IN (22, 27, 53)
)
SELECT
    name
    ,age
FROM CTE
WHERE rn <= 5
;

UNION在某种意义上与OR相同。

如果您的表有主键ID,您可以像这样重写查询:

SELECT name, age
FROM table1
WHERE
    ID IN (select top 5 ID from table1 where category = 22 order by age desc)
    OR
    ID IN (select top 5 ID from table1 where category = 27 order by age desc)
    OR
    ID IN (select top 5 ID from table1 where category = 53 order by age desc)

通常情况下,UNION ALL会比这更有效率。

答案 1 :(得分:3)

如果你真的想要前5名,那么你可能需要打破平局。每nameage是唯一的吗?

select t.name, t.age from T t
where t.category in (22, 27, 53) and 5 >= (
    select count(*) from T t2
    where t2.category = t.category
        and (t2.age >= t.age or t2.age = t.age and t2.name >= t.name)
)

答案 2 :(得分:2)

  

如果您使用某些特定于供应商的SQL扩展,请指定   你正在使用的数据库。

SQL Server 中,您可以使用排名功能ROW_NUMBER()PARTITION BY category来为每个类别组生成排名,并且过滤您正在寻找的三个类别。然后,您可以过滤以仅获得排名数小于5的行,这将为您获得每个类别的最早的5个名称:

SELECT name, age
FROM
(
    SELECT 
      name, age, 
      ROW_NUMBER() OVER(PARTITION BY category ORDER BY age DESC)AS RN
    FRO< table1 
    WHERE category IN(22,27, 53)
) AS t
WHERE RN <= 5;

答案 3 :(得分:1)

使用自联接可以昂贵地模拟排名。对于具有执行自连接的子选择的解决方案,这是伪SQL(即,可能需要一些语法调整)。这是你的意思吗?

select name, age from ( 
  select a.name,a.age, count(*) as rank from 
    table1 a join table1 b on a.category=b.category 
  where a.category in (22,27,53) and 
        ((b.age+hash(b.name,b.age) >=a.age+hash(a.name,a.age))
) c
group by c.name, c.age  
where rank <= 5