如何从params中选择顶部x?

时间:2010-07-18 10:41:46

标签: sql sql-server

我正在使用Sql-Server 2005

我有User表和userID和性别。我想通过userID desc选择前1000名男性(0名)和前1000名女性(1名)。

如果我创建联合,则只有一个结果集由userID desc排序。还有什么方法可以做到这一点?

SELECT top 1000 *
FROM Users
where gender=0
union
SELECT top 1000 *
FROM Users
where gender=1
order by userID desc

4 个答案:

答案 0 :(得分:3)

Martin Smith的解决方案比以下更好。

SELECT UserID, Gender
FROM 
  (SELECT TOP 1000 UserId, Gender 
   FROM Users 
   WHERE gender = 0
   ORDER BY UserId DESC) m
UNION ALL
SELECT UserID, Gender
FROM 
 (SELECT TOP 1000 UserId, Gender
  FROM Users
  WHERE gender = 1
  ORDER BY UserId DESC) f
ORDER BY Gender, UserID DESC

这可以满足您的需求,只需更改顺序,如果您最先拥有最新用户,那么它将为您提供前1000名。

答案 1 :(得分:3)

另一种方法

WITH TopUsers AS
(
SELECT UserId, 
       Gender,
       ROW_NUMBER() OVER (PARTITION BY Gender ORDER BY UserId DESC) AS RN
  FROM Users
  WHERE Gender IN (0,1) /*I guess this line might well not be needed*/
) 

SELECT UserId, Gender 
FROM TopUsers  
WHERE RN <= 1000
ORDER BY UserId DESC

答案 2 :(得分:1)

做了一些测试,结果很奇怪。如果在联合的两个部分中指定order by,则SQL Server会出现语法错误:

select top 2 * from @users where gender = 0 order by id
union all
select top 2 * from @users where gender = 1 order by id 

这是有道理的,因为顺序应该只在联盟的末尾。但是如果你在子查询中使用相同的构造,它会编译!并按预期工作:

select * from (
    select top 2 * from @users where gender = 0 order by id
    union all
    select top 2 * from @users where gender = 1 order by id
) sub

当您为子查询联合只指定一个order by时,会发生最奇怪的事情:

select * from (
    select top 2 * from @users where gender = 0
    union all
    select top 2 * from @users where gender = 1 order by id
) sub

现在它随机命令联盟的前半部分,但下半部分是id。这是非常意外的。上半场的order by也发生了同样的事情:

select * from (
    select top 2 * from @users where gender = 0 order by id desc
    union all
    select top 2 * from @users where gender = 1
) sub

我希望这会给出一个语法错误,但它会命令联盟的前半部分。因此,当union是子查询的一部分时,order byunion以不同的方式进行交互。

就像Chris Diver最初发布的那样,摆脱困惑的一个好方法是不依赖于联盟中的order by,并明确指定所有内容:

select  *
from    (
        select  *
        from    (
                select  top 2 *
                from    @users
                where   gender = 0
                order by 
                        id desc
                ) males
        union all
        select  *
        from    (
                select  top 2 *
                from    @users
                where   gender = 1
                order by 
                        id desc
                ) females
        ) males_and_females
order by 
        id

示例数据:

declare @users table (id int identity, name varchar(50), gender bit)

insert into @users (name, gender)
          select 'Joe', 0
union all select 'Alex', 0
union all select 'Fred', 0
union all select 'Catherine', 1
union all select 'Diana', 1
union all select 'Esther', 1

答案 3 :(得分:0)

您需要确保为联合创建子选择,然后在组合结果之外进行排序。

这样的事情应该有效:

SELECT u.*
  FROM (SELECT u1a.* FROM (SELECT TOP 1000 u1.*
                             FROM USERS u1
                            WHERE u1.gender = 0
                            ORDER BY u1.userid DESC) u1a
        UNION ALL
        SELECT u2a.* FROM (SELECT TOP 1000 u2.*
                             FROM USERS u2
                            WHERE u2.gender = 1
                            ORDER BY u2.userid DESC) u2a
       ) u
ORDER BY u.userid DESC

此外,使用UNION ALL会提供更好的性能,因为db不会在结果中检查重复项(在此查询中不会出现)。