Выберите запрос выберите на основе приоритета - PullRequest
2 голосов
/ 21 августа 2010

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

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

Table (id, value, value_type, data)

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

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

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

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

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

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

В настоящее время я делаю это с рядом временных таблиц.Существует ли один оператор выбора (подзапросы в порядке), который может выполнить эту работу?

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

Дополнительные сведения:

SQL Server2005

Ответы [ 7 ]

5 голосов
/ 21 августа 2010

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

Версия без CTE:

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
4 голосов
/ 21 августа 2010
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)
2 голосов
/ 21 августа 2010

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

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% больше), но имеет в 3 раза больше операций чтения. Продолжительность этого запроса часто в 2/3 раза превышает время всех остальных. Я считаю это хорошим соперником.

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

1 голос
/ 21 августа 2010
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 голосов
/ 21 августа 2010

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

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"))
0 голосов
/ 21 августа 2010

Попробуйте это (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 голосов
/ 21 августа 2010

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

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...