我正在使用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
答案 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 by
与union
以不同的方式进行交互。
就像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不会在结果中检查重复项(在此查询中不会出现)。