2013-08-13 5 views
5

У меня есть следующий фрагмент кода:Приоритет SQL заявления или

WHERE (Person.WorkGroupId = 2 or Person.RoleId = 2) 

То, что я хотел бы случиться, для этого, чтобы вернуть первое вхождение с WorkGroupId 2 на Person столе. Но, если нет человека с WorkgroupId из 2, выберите первое вхождение с RoldId из 2 в таблице Person.

Благодаря

+4

Вы хотите, чтобы всегда возвращалась одна строка? Что делать, если два человека соответствуют этим критериям, или один человек находится в WorkGroupId = 2, а другой человек находится в RoleId = 2? Можете ли вы показать образцы данных, желаемые результаты и остальную часть запроса? Возможно, вы заметили, что получаете кучу плохих ответов - это хотя бы частично, потому что ваши требования очень неясны. –

+0

Извините, мне просто нужен первый человек, у которого есть рабочая группа из 2 ... если нет никого, тогда я хочу первый с помощью роли 2 ... так что только один человек вернулся – Bobcat88

+0

Можете ли вы пояснить, что в вопросе, пожалуйста? –

ответ

12
SELECT TOP (1) * FROM 
(
    SELECT TOP (1) *, o = 1 
    FROM Person 
    WHERE WorkGroupId = 2 

    UNION ALL 

    SELECT TOP (1) *, o = 2 
    FROM Person 
    AND RoleId = 2 
) AS x ORDER BY o; 
+1

Это сканирование таблицы Person 3 раза! –

+0

Не обязательно .. Но можно сделать с 1 сканом :) –

+1

@NirKornfeld пылающие ответы с такими вещами, как это действительно не нужно. Пожалуйста, обратите внимание, что никто не раскачивал ваш ответ с потенциальной возможностью разбрасывания разновидностей * tempdb, который поставляется с вашим ответом. – swasheck

8

Вы бы получить больше, чем одну запись, если вы используете только что.

Я хотел бы сделать что-то вроде: (таблица в вопрос будет проверяться только один раз)

Select top 1 * 
From dbo.SomeTable 
where WorkGroupId=2 or RoleId=2 
Order by case 
    when WorkGroupId=2 then 1 
    when RoleId=2 then 2 
end 
+4

Извините, но пока этот запрос красивее, [Lamak's answer] (http://stackoverflow.com/a/18218741/61305) действительно работает лучше - не зная ничего больше о таблице пользователя, конечно, и против таблиц с количеством строк от 2000 до 1,26 млн. - как мы уже доказали в комментариях ниже. –

3
CREATE TABLE dbo.Person(
    PersonID INT IDENTITY(1,1) PRIMARY KEY, 
    FullName NVARCHAR(100) NOT NULL, 
    Col1 INT NOT NULL, 
    WorkGroupId TINYINT NOT NULL, 
    RoleId TINYINT NOT NULL, 
    [Priority] AS CONVERT(TINYINT,    
       CASE 
        WHEN WorkGroupId=2 THEN 1 -- Priority 1 
        WHEN RoleId=2 THEN 2  -- Priority 2 
        ELSE 3      -- Priority 3 
       END) 
); 
GO 
-- http://technet.microsoft.com/en-us/library/ms189292.aspx 
SET NUMERIC_ROUNDABORT OFF; 
SET ANSI_NULLS ON; 
SET ANSI_PADDING ON; 
SET ANSI_WARNINGS ON; 
SET ARITHABORT ON; 
SET CONCAT_NULL_YIELDS_NULL ON; 
SET QUOTED_IDENTIFIER ON; 
GO 
CREATE INDEX IX_Person_Col1_Priority 
ON dbo.Person (Col1,[Priority]) 
INCLUDE (FullName); 
GO 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'A' ,1,1,1); 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'BB' ,1,0,1); 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'CCC' ,1,2,1); -- <-- 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'DDDD',1,0,0); 
GO 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'X' ,2,1,1); 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'YY' ,2,1,2); -- <-- 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'ZZZ',2,1,3); 
GO 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'?' ,3,1,1); 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'!!' ,3,2,1); -- <-- 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'%%%' ,3,1,2); 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'&&&&',3,1,3); 
GO 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'-' ,4,1,1); -- No result 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'--' ,4,1,1); -- No result 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'---' ,4,1,1); -- No result 
INSERT dbo.Person (FullName,Col1,WorkGroupId,RoleId) VALUES (N'----',4,1,1); -- No result 
GO 

SELECT * 
FROM(
    SELECT p.PersonID,p.FullName, 
      -- If you have many persons with the same priority then you should use DENSE_RANK 
      ROW_NUMBER() OVER (ORDER BY p.[Priority]) AS Rnk 
    FROM dbo.Person p 
    WHERE p.Col1=1 
    AND  p.[Priority] IN (1,2) 
) x 
WHERE x.Rnk=1; 

SELECT * 
FROM(
    SELECT p.PersonID,p.FullName, 
      -- If you have many persons with the same priority then you should use DENSE_RANK 
      ROW_NUMBER() OVER (ORDER BY p.[Priority]) AS Rnk 
    FROM dbo.Person p 
    WHERE p.Col1=2 
    AND  p.[Priority] IN (1,2) 
) x 
WHERE x.Rnk=1; 

SELECT * 
FROM(
    SELECT p.PersonID,p.FullName, 
      -- If you have many persons with the same priority then you should use DENSE_RANK 
      ROW_NUMBER() OVER (ORDER BY p.[Priority]) AS Rnk 
    FROM dbo.Person p 
    WHERE p.Col1=3 
    AND  p.[Priority] IN (1,2) 
) x 
WHERE x.Rnk=1; 

SELECT * 
FROM(
    SELECT p.PersonID,p.FullName, 
      -- If you have many persons with the same priority then you should use DENSE_RANK 
      ROW_NUMBER() OVER (ORDER BY p.[Priority]) AS Rnk 
    FROM dbo.Person p 
    WHERE p.Col1=4 
    AND  p.[Priority] IN (1,2) 
) x 
WHERE x.Rnk=1; 

Результаты:

PersonID FullName Rnk 
-------- -------- --- 
3  CCC  1 


PersonID FullName Rnk 
-------- -------- --- 
6  YY  1 


PersonID FullName Rnk 
-------- -------- --- 
9  !!  1 


PersonID FullName Rnk 
-------- -------- --- 

И план выполнения последние четыре отчета: enter image description here

Примечание: Col1 представляет собой испытательный номер.

+2

Это работает нормально, если вы можете изменить таблицу и, вероятно, вам нужно будет сохранить и индексировать этот столбец. Если вы переместите выражение в вычисление ROW_NUMBER(), вы вводите такую ​​же дорогостоящую операцию сортировки, что и в ответе Нира. –