2010-08-20 2 views
1

Кто-то, пожалуйста, измените мой заголовок, чтобы лучше отразить то, что я пытаюсь задать.Выбрать выбор запроса на основе приоритета

У меня есть таблица, как

Table (id, value, value_type, data) 

ID не является уникальным. Не существует уникального ключа.

value_type имеет два возможных значения, скажем А и Б.

типа B лучше, чем А, но часто не доступны.

Для каждого идентификатора, если какая-либо запись с value_type B существует, я хочу, чтобы все записи с этим идентификатором и value_type B.

Если записи для этого идентификатора с VALUE_TYPE B не существует, я хочу, чтобы все записи с этим идентификатором и value_type А.

Обратите внимание, что если B существует для этого идентификатора я не хочу записей типа A.

в настоящее время я сделать это с помощью серии временных таблиц. Есть ли один оператор select (sub queries OK), который может выполнять эту работу?

Большое спасибо!

Дополнительная информация:

SQL Server 2005

+0

какая версия SQL Server? –

+0

SQL 2005 так «partiton by» доступен мне. Я попытался использовать его, но имел проблему с тем, когда было несколько записей с типом B. – kralco626

ответ

4

RANK, а не ROW_NUMBER, потому что вы хотите связи (те, с тем же значением B), чтобы иметь такое же значение ранга:

WITH summary AS (
    SELECT t.*, 
     RANK() OVER (PARTITION BY t.id 
          ORDER BY t.value_type DESC) AS rank 
    FROM TABLE t 
    WHERE t.value_type IN ('A', 'B')) 
SELECT s.id, 
     s.value, 
     s.value_type, 
     s.data 
    FROM summary s 
WHERE s.rank = 1 

Non КТР версия:

SELECT s.id, 
     s.value, 
     s.value_type, 
     s.data 
    FROM (SELECT t.*, 
       RANK() OVER (PARTITION BY t.id 
           ORDER BY t.value_type DESC) AS rank 
      FROM TABLE t 
     WHERE t.value_type IN ('A', 'B')) s 
WHERE s.rank = 1 

WITH test AS (
    SELECT 1 AS id, 'B' AS value_type 
    UNION ALL 
    SELECT 1, 'B' 
    UNION ALL 
    SELECT 1, 'A' 
    UNION ALL 
    SELECT 2, 'A' 
    UNION ALL 
    SELECT 2, 'A'), 
    summary AS (
    SELECT t.*, 
      RANK() OVER (PARTITION BY t.id 
          ORDER BY t.value_type DESC) AS rank 
    FROM test t) 
SELECT * 
    FROM summary 
WHERE rank = 1 

я получаю:

id value_type rank 
---------------------- 
1 B   1 
1 B   1 
2 A   1 
2 A   1 
+0

+1 Ударьте меня на 12 секунд! –

+1

@ Мартин Смит: Значит, ты признаешь это - ты * украл мой ответ! =) –

+0

ха-ха! ya, я делал почти то же самое с ROW_NUMBER. Просто, когда я подумал, что я получаю возможность использовать эти «оконные» функции. Спасибо! я проверю и дам вам знать. – kralco626

0

Это использует союз, объединяющий в себе все записи значений B со всеми записями, которые имеют только значения:

SELECT * 
FROM mainTable 
WHERE value_type = B 
GROUP BY value_type UNION SELECT * 
          FROM mainTable 
          WHERE value_type = A 
           AND id NOT IN(SELECT * 
              FROM mainTable 
              WHERE value_type = B); 
+0

Это дубликат ответа Бет, который был первым. – ErikE

0

Попробуйте это (MSSQL).

Select id, value_typeB, null 
from myTable 
where value_typeB is not null 
Union All 
Select id, null, value_typeA 
from myTable 
where value_typeB is null and value_typeA is not null 
+0

value_typeB и value_typeA не являются столбцами. value_type - это столбец, и он может иметь значение A или B – kralco626

3
SELECT * 
    FROM table 
WHERE value_type = B 
UNION ALL 
SELECT * 
    FROM table 
WHERE ID not in (SELECT distinct id 
        FROM table 
        WHERE value_type = B) 
+0

Я думаю, что этот запрос пропустит идентификатор записи, который связан только с значениями типа A. – dvanaria

+0

@dvanaria: перечитайте вторую половину заявления UNION –

+0

@Beth: +1: не нужно ли DISTINCT, для 'IN' –

1
declare @test as table(
id int , value [nvarchar](255),value_type [nvarchar](255),data int) 

INSERT INTO @test 
SELECT 1, 'X', 'A',1 UNION 
SELECT 1, 'X', 'A',2 UNION 
SELECT 1, 'X', 'A',3 UNION 
SELECT 1, 'X', 'A',4 UNION 
SELECT 2, 'X', 'A',5 UNION 
SELECT 2, 'X', 'B',6 UNION 
SELECT 2, 'X', 'B',7 UNION 
SELECT 2, 'X', 'A',8 UNION 
SELECT 2, 'X', 'A',9 


SELECT * FROM @test x 
INNER JOIN 
(SELECT id, MAX(value_type) as value_type FROM 
@test GROUP BY id) as y 
ON x.id = y.id AND x.value_type = y.value_type 
+0

. Ваш запрос выполняет почти лучшее из всех представленных запросов (часто лучше всего), поэтому заслуживает признания. – ErikE

+0

@ Emtucifor - я верю, однако, что если вы заменили @test для подзапроса или неиндексированного представления, это займет больше времени, потому что ему придется называть его дважды. Это было бы моей ошибкой, но не Крисом, потому что я не сказал, что в моем вопросе – kralco626

+0

@ kralco626 - Количество упоминаний таблицы в запросе не коррелирует с производительностью. Сосредоточив внимание на уменьшении количества упоминаний названия таблицы, не глядя на фактическую производительность запроса (CPU и чтения), определенно приведет вас к неправильному пути. – ErikE

0

Возможно, что-то вроде этого:

select * from mytable 
where id in (select distinct id where value_type = "B") 
union 
select * from mytable 
where id in (select distinct id where value_type = "A" 
and id not in (select distinct id where value_type = "B")) 
2

Самый короткий запрос, чтобы сделать работу я могу думать:

SELECT TOP 1 WITH TIES * 
FROM #test 
ORDER BY Rank() OVER (PARTITION BY id ORDER BY value_type DESC) 

Это примерно На 50% хуже, чем процессоры OMG Ponies и Christoperous 5000, но такое же количество просмотров , Это лишний сорт, который заставляет процессор больше.

Наиболее выполняя оригинальный запрос я придумал до сих пор:

SELECT * 
FROM #test 
WHERE value_type = 'B' 
UNION ALL 
SELECT * 
FROM #test T1 
WHERE NOT EXISTS (
    SELECT * 
    FROM #test T2 
    WHERE 
     T1.id = T2.id 
     AND T2.value_type = 'B' 
) 

Это последовательно бьет все остальные представленные на CPU примерно 1/3 (остальные около 50% больше) но имеет 3x количество чтений. Продолжительность этого запроса часто составляет 2/3rds - время всех остальных. Я считаю это хорошим соперником.

Индексы и типы данных могут изменять все.

+0

Спасибо, что сделали анализ, славную работу. Однако мне нужно решение, которое использует таблицу только один раз. – kralco626

+0

также я думаю, что ваши решения вернут только одну запись. Что делать, если имеется более одной записи с наивысшим приоритетом? – kralco626

+0

Попробуйте запрос: – ErikE

Смежные вопросы