SQL: улучшите мой запрос select-where-subquery-return-one - PullRequest
2 голосов
/ 24 февраля 2012

У меня уже есть рабочее решение следующей проблемы, но я беспокоюсь, что это глупо или неэффективно.

Существует таблица Thing со столбцами (id, attributes...), а также таблица ThingVersion сстолбцы (id, thing_id, version_attributes...) Проблема состоит в том, чтобы выбрать из Thing, где существует ровно одна соответствующая строка ThingVersion.

В настоящий момент у меня есть что-то вроде

SELECT Thing.id AS id, Foo.whatever
FROM Thing JOIN Foo ON Thing.id=Foo.thing_id
WHERE Thing.id IN (
    SELECT thing_id FROM ThingVersion TV
    WHERE 1 = (
        SELECT COUNT(*)
        FROM ThingVersion TV2
        WHERE TV2.thing_id = TV.thing_id)
    )
ORDER BY Foo.whatever

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

Есть ли?

Ответы [ 3 ]

2 голосов
/ 24 февраля 2012

Вы можете использовать предложение HAVING в своем подзапросе:

SELECT Thing.id AS id, Foo.whatever
  FROM Thing JOIN Foo ON Thing.id=Foo.thing_id
 WHERE Thing.id IN
        ( SELECT thing_id
            FROM ThingVersion TV
           GROUP BY thing_id
          HAVING COUNT(*) = 1
        )
 ORDER BY Foo.whatever
;

Вы также можете исключить JOIN в основном запросе:

SELECT thing_id AS id, whatever
  FROM Foo
 WHERE thing_id IN
        ( SELECT thing_id
            FROM ThingVersion TV
           GROUP BY thing_id
          HAVING COUNT(*) = 1
        )
 ORDER BY whatever
;

(япри условии, что каждое значение, которое появляется как в Foo.thing_id, так и ThingVersion.thing_id, обязательно должно отображаться Thing.id.)

1 голос
/ 24 февраля 2012

Решение с использованием строго СОЕДИНЕНИЙ:

SELECT t.*
FROM Thing t
JOIN ThingVersion tv1
  ON tv1.thing_id = t.id
LEFT JOIN ThingVersion tv2
  ON tv2.thing_id = t.id
  AND tv2.id <> tv1.id
WHERE tv2.id IS NULL

Решение с использованием GROUP BY и COUNT:

SELECT t.* 
FROM Thing t
JOIN ThingVersion tv
  ON tv.thing_id = t.id
GROUP BY t.id
HAVING COUNT(t.id) = 1;

Попробуйте их обоих на производительность.

1 голос
/ 24 февраля 2012
SELECT Thing.id AS id, Foo.whatever
FROM Thing JOIN Foo ON Thing.id=Foo.thing_id
where Thing.idin (select thing_id from ThingVersion group by thing_id having COUNT(*)>1)
...