2009-10-22 2 views
3

Прежде всего, я на самом деле не так уж велик в SQL, с тем, что, начиная с вопросом:Добавление некоторой логики в SQL запрос

Допустит, у меня есть таблица под названием Способностей. В этом примере У Способностей есть ID, PersonID, Текст.

Скажем, я выполняю поиск, в котором я указываю, что хочу отдельный список каждого человека, который имеет возможность «летать», «диск», «поет», но не имеет возможности «сражаться», «скейтборд» '

Есть ли вообще-нибудь написать такой запрос, который в конце концов вернет строки, соответствующие моему заявлению выше? Стол и его содержание чисто вымышленные, я мог бы добавить, следовательно, wierdness: P

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

Благодаря

+0

вы хотите, чтобы все способности (включены или исключены) или любой из списка и включить любого из списка исключений делать? Делает небольшую разницу с тем, что требуется и что будет работать. – Murph

ответ

5
SELECT a.PersonId 
FROM Abilities a 
JOIN Abilities b ON (a.PersonId = b.PersonId AND b.text = 'Drive') 
JOIN Abilities c ON (a.PersonId = c.PersonId AND c.text = 'Sing') 
LEFT JOIN Abilities d ON (a.PersonId = d.PersonId AND d.text = 'Flight') 
LEFT JOIN Abilities e ON (a.PersonId = e.PersonId AND e.text = 'Skateboard') 
WHERE a.text = 'Fly' AND d.Id IS NULL and e.Id IS NULL 

Я вижу, что у вас есть несколько ответов, пытающихся выполнить как IN, так и NOT IN тесты одного и того же экземпляра способностей, но это не сработает - вам, очевидно, нужно протестировать отдельные экземпляры способностей, откуда требуется эта множественная самость -присоединиться!

+0

+1 ... Рад, что я не пытался это сделать, хороший ответ, как всегда –

+0

Большое спасибо, очень полезно –

0

Вы не указали сервер базы данных, но я знаю, что это работает в SQL Server

SELECT a1.ID, a1.PersonID, a1.Text 
FROM Abilities a1 
WHERE a1.Text IN ('Fly', 'Drive', 'Sing') 
AND NOT EXISTS (SELECT ID 
       FROM Abilities a2 
       WHERE a2.ID = a1.ID 
       AND a2.Text IN ('Fight', 'Skateboard')) 
1

Есть несколько способов решить эту проблему. Я выбрал тот, который должен быть читабельным, но не обязательно поддерживаемым для многих изменений.

WITH Fliers AS (
    SELECT PersonID 
    FROM Abilities 
    WHERE Text = 'Fly' 
), 
Drivers AS (
    SELECT PersonID 
    FROM Abilities 
    WHERE Text = 'Drive' 
), 
Singers AS (
    SELECT PersonID 
    FROM Abilities 
    WHERE Text = 'Sing' 
), 
Fighters AS (
    SELECT PersonID 
    FROM Abilities 
    WHERE Text = 'Fight' 
), 
Skateboarders AS (
    SELECT PersonID 
    FROM Abilities 
    WHERE Text = 'Skateboard' 
) 
SELECT * 
FROM People 
INNER JOIN Fliers 
    ON Fliers.PersonID = People.PersonID 
INNER JOIN Drivers 
    ON Drivers.PersonID = People.PersonID 
INNER JOIN Singers 
    ON Singers.PersonID = People.PersonID 
LEFT JOIN Fighters 
    ON Fighters.PersonID = People.PersonID 
LEFT JOIN Skateboarders 
    ON Skateboarders.PersonID = People.PersonID 
WHERE Fighters.PersonID IS NULL 
    AND Skateboarders.PersonID IS NULL 

Но есть много способов кожи этого кота.

Большинство решений здесь использовать простой IN, NOT IN, но они не собираются, чтобы дать результаты, я думаю, вы ожидаете, - то есть люди, которые имеют ширинку и диск и петь и ни Fight NOR Скейтборд

3

В зависимости от фактических данных и параметров запроса, подход без самостоятельных подключений может быть более эффективным. Я ожидал бы, что это сделает одно полное сканирование таблицы, тогда как метод join, вероятно, сделает много индексов.

SELECT personID FROM 
(
SELECT personID, 
     SUM(CASE WHEN text IN ('Fly','Drive','Sing') THEN 1 ELSE 0 END) good_stuff, 
     SUM(CASE WHEN text IN ('Fight','Skateboard') THEN 1 ELSE 0 END) bad_stuff 
    FROM abilities 
    GROUP BY personID 
) 
WHERE good_stuff = 3 and bad_stuff = 0 
+0

Вместо вложенного запроса тоже будет работать предложение having, но ему придется повторять «СУММ» вместо этого возможности использования псевдонимов. – Thorsten

1
SELECT * FROM (SELECT PERSONID, COUNT(SKILLS) FROM DUMMY WHERE SKILLS IN ('FLY','DRIVE','SING') GROUP BY PERSONID HAVING COUNT(*)=3) A 

WHERE PERSONID NOT IN 

(SELECT DISTINCT PERSONID FROM DUMMY WHERE SKILLS IN ('FIGHT','SKATEBOARD') ) 
+1

Добро пожаловать в переполнение стека! Пожалуйста, [отформатируйте свой код] (http://meta.stackexchange.com/a/22189), чтобы улучшить читаемость. – AHiggins

+1

Кроме того, нам нравится [избегать ответов только на код] (http://meta.stackexchange.com/a/148274), когда это возможно. Действительно хороший ответ часто включает в себя объяснения и описания того, что вы делаете и почему! Включение таких деталей помогает сделать сайт лучше и сделать ваши собственные ответы более полезными. – AHiggins

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