2010-04-19 3 views
5

Учитывая эти данные по SQL Server 2005:Tricky SQL - Выбор несмежных номера

SectionID Name 
1   Dan 
2   Dan 
4   Dan 
5   Dan 
2   Tom 
7   Tom 
9   Tom 
10  Tom 

Как бы выбрать записи, где sectionID должна быть + -2 или более из другого раздела для того же имени.

Результат будет выглядеть так:

1 Dan 
4 Dan 
2 Tom 
7 Tom 
9 Tom 

Спасибо за чтение!

+2

Хм, вы говорите, что «1 Дан» находится в результатах, и поэтому «2 Дан» нет, но почему это не то, что «2 Дан» находится в результатах, и поэтому «1 Дан» нет? Я думаю, вы принимаете какой-то заказ здесь, чего SQL на самом деле не делает. Чего вы на самом деле хотите достичь? – wilth

+0

@wilth, SQL может распознавать реляционные операторы, такие как <и в реляционной алгебре нет ничего, что запретит использование свойств таких операций над атрибутами; это только если вы присваиваете значение произвольному порядку записей, которые вы совершаете кардинальной ошибкой. Однако вы поднимаете действительную точку зрения, что оператор не известен, но я бы сказал, что запись с меньшим идентификатором должна быть сохранена. – Unreason

+0

@ Даниэль, что бы вы вернули, если бы у вас также (3, Дэн) в стартовом столе? Будете ли вы возвращать записи (1, Дэн) и (3, Дэн) или только первые? Является ли единственным условием действительно, что разница между выбранными идентификаторами должна быть больше 1 (или есть дополнительные условия)? Если это единственное условие, что вы хотите сделать в случае последовательности, такой как: 5, 6, 7, 8, 10, 11, 12? (у него есть два решения, один из которых начинается с 5, имеет 4 элемента в ответе, но если вы начинаете с 6, вы можете выбрать 5 элементов); как отличить? – Unreason

ответ

3
SELECT * 
FROM mytable a 
WHERE NOT EXISTS 
    (SELECT * 
    FROM mytable b 
    WHERE a.Name = b.Name 
    AND a.SectionID = b.SectionID + 1) 
+0

+1 Прямое и правильное решение. Сложный индекс на '(SectionID, Name)' будет очень полезен для этого запроса. – Tomalak

+1

, так что если у вас были данные: '1 Tom 2 Tom 3 Tom 4 Tom' , вы получите нулевые записи назад. Я подозреваю, что это неверно. – ninesided

+0

@ninesided, не совсем - запрос возвращает все записи из таблицы a, где для раздела отсутствует запись в той же таблице с секцией, которая меньше на единицу (так что в примере вашего экземпляра 1 Tom будет возвращен). – Unreason

0

Вот LEFT JOIN вариант ответа Энтони (удаляет последовательные идентификаторы из результатов)

SELECT a.* 
FROM mytable a 
    LEFT JOIN mytable b ON a.Name = b.Name AND a.SectionID = b.SectionID + 1 
WHERE b.SectionID IS NULL 

EDIT: Так как есть еще одна интерпретация вопроса (просто получать результаты, где идентификаторы являются более 1 номер друг от друга) вот еще одна попытка ответа:

WITH alternate AS (
SELECT sectionid, 
     name, 
     EXISTS(SELECT a.sectionid 
       FROM mytable b 
       WHERE a.name = b.name AND 
        (a.sectionid = b.sectionid-1 or a.sectionid = b.sectionid+1)) as has_neighbour, 
     row_number() OVER (PARTITION by a.name ORDER BY a.name, a.sectionid) as row_no 
FROM mytable a 
) 
SELECT sectionid, name 
FROM alternate 
WHERE row_no % 2 = 1 OR NOT(has_neighbour) 
ORDER BY name, sectionid; 

дает:

sectionid | name 
-----------+------ 
     1 | Dan 
     4 | Dan 
     2 | Tom 
     7 | Tom 
     9 | Tom 

Логика: если запись имеет соседей с одинаковым именем и id +/- 1, то каждая нечетная строка берется, если у нее нет таких соседей, тогда она получает строку независимо от того, является она четной или нечетной.

Как указано в комментарии, условие неоднозначно - при запуске каждой новой последовательности вы можете начинать с нечетных или четных строк, и критерии по-прежнему будут удовлетворены разными результатами (даже с различным количеством результатов).

+0

По-разному, но все же имеет ту же проблему, о которой упоминалось @ninesided. – PaulG

+0

Плохая идея, так как SQL-сервер не сможет преобразовать это в antijoin. – erikkallen

+0

@PaulG, можете ли вы объяснить проблему; Я попросил более подробную информацию о ninesided комментариях в ответ Энтони, но никто не был предоставлен (насколько я могу видеть, что оба запроса возвращают запрошенные данные) @erikkallen, я согласен, что это не так, но производительность должна быть проверена, НЕ СУЩЕСТВУЕТ коррелированная производительность подзапроса явно не превосходит производительность LEFT JOIN даже при такой высокой избирательности. – Unreason

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