2010-07-18 3 views
3

Я использую Sql-Server 2005Как выбрать верхний х из с параметрами?

У меня есть таблица пользователей с идентификатором пользователя и пол. Я хочу выбрать топ 1000 мужчин (0) и топ 1000 женщин (1) по адресу userID desc.

Если я создаю объединение, то только один результирующий набор упорядочивается по userID desc. Какой еще способ сделать это?

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

Вы можете разместить SQL вашего запроса? В частности, мне интересно о таких вещах, как круглые скобки и местоположение, или в разделе «порядок». – sje397

+0

@ sje397, сделано для ya – eugeneK

+0

По какому критерию вы намерены выбрать первую 1000? В настоящий момент запрос над союзом выбирает эффективно наугад. –

ответ

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 
+0

Более элегантное решение, чем мое. Выступает лучше. Я это запомню. Благодарю. –

+0

Что я буду делать без тебя, Мартин Смит? Я получаю 90% ответов от вас! – eugeneK

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 даст лучшую производительность, поскольку дБ не будет беспокоить проверки дубликатов (который не будет в этом запросе) в Результаты.

+0

Возможно, я ошибаюсь, но он будет выбирать лучших мужчин и женщин на основе какого фактора, я думаю, нет фактора? – eugeneK

+0

Закрыть, но это не сработает, он выберет любое 1000 пользователей, которые являются мужчинами и любыми 1000, которые являются женщинами, он хочет последние 1000 –

+0

Спасибо, ошибка с помощью быстрой печати - теперь исправлена. – Tom

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 Дайвер первоначально размещен, хороший способ, чтобы выйти из путаницы не полагаться на 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 
+0

Ошибка: Tom –

+0

Зачем вам нужен двойной запрос, не работает ли мой запрос? –

+0

@Chris Diver: ваш запрос действительно работает. Я пишу еще более четко, что последний «порядок от» относится к – Andomar

3

Решение Мартина Смита лучше, чем следующее.

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 каждому из них.

+0

+1. Вы правы, я сосредоточился на заказе и пропустил то, что он хотел 1000 лучших за пол. – Andomar

+0

Закрыть, но если вы заказываете по Пол в в конце вы снова разделите мужчин и женщин. – Tom

+0

@ Chris Diver, да, вы поняли это правильно. Просто, возможно, есть более быстрое решение ... – eugeneK