Добавление некоторой логики в SQL-запрос - PullRequest
3 голосов
/ 22 октября 2009

Во-первых, я действительно не настолько хорош в sql, с учетом сказанного, далее к вопросу:

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

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

Можно ли написать такой запрос, который в итоге будет возвращать только те строки, которые соответствуют моему приведенному выше утверждению? Я мог бы добавить, что таблица и ее содержимое вымышленные, поэтому странность: P

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

Спасибо

Ответы [ 5 ]

5 голосов
/ 22 октября 2009
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 для одного и того же экземпляра Способностей, но это не сработало - вам явно нужно тестировать отдельные экземпляры Способностей, откуда возникает необходимость в этом множественном «я». -join!

3 голосов
/ 22 октября 2009

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

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
1 голос
/ 20 июля 2015
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 голос
/ 22 октября 2009

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

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, а не IN, но они не дадут ожидаемых результатов - то есть людей, которые летают, едут, поют и не борются со скейтбордом

0 голосов
/ 22 октября 2009

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