Есть ли способ удалить вложенный запрос в этом типе SQL SELECT? - PullRequest
1 голос
/ 30 марта 2011

Учитывая эту структуру таблицы и пример данных (t3 не должен использоваться в запросе, он только здесь показывает связь между t1 и t2):

      t1                 t2                         t3
--------------   -----------------   --------------------------------
| id | value |   | t1key | t3key |   | id | value                   |
|  1 |  2008 |   |     3 |     1 |   |  1 | "New intel cpu in 2010" |
|  2 |  2009 |   |     4 |     1 |   |  2 | "New amd cpu in 2008"   |
|  3 |  2010 |   |     6 |     1 |   |    |                     ... |
|  4 | intel |   |     1 |     2 |   --------------------------------
|  5 |   amd |   |     5 |     2 |
|  6 |   cpu |   |     6 |     2 |
|    |   ... |   |       |   ... |
--------------   -----------------

Как бы вы построили SQL-запрос, который бы удовлетворял следующему:

Given the input for t1.id is the set {6} returns t1.id set {3,4,6,1,5}
Given the input for t1.id is the set {6,4} returns t1.id set {3,4,6}
Given the input for t1.id is the set {5,4} returns t1.id set {}

и не снижает производительность, когда таблицы больше ...?

Ответы [ 5 ]

2 голосов
/ 30 марта 2011

Вот мой блестящий вклад (по крайней мере, давайте пока предположим, что он блестящий):

SELECT DISTINCT a2.t1key, COUNT( * ) AS cnt
FROM t2 AS a1
    LEFT JOIN t2 AS a2 ON a2.t3key = a1.t3key
WHERE a1.t1key IN ( 6, 4 ) 
GROUP BY a2.t3key, a2.t1key
HAVING cnt >=2

Часть IN (6,4) действительно говорит сама за себя. В cnt >=2 2 указывается число id -ов в предложении IN. Например: вы используете IN (6), тогда вы должны использовать cnt >=1.

Я не уверен, что > нужен вообще, но я ленив, даже не для того, чтобы создать больший набор данных для тестирования:)

1 голос
/ 30 марта 2011
select distinct t2b.t1key
from 
  t2 t2a
  inner join t2 t2b on t2a.t3key = t2b.t3key
where t2a.t1key in (6, 5) /* or whatever */

Начиная с t1 (ключевое слово), вы получаете все t3 (выражения), которые содержат «cpu» (или что-то еще). Вам не нужно присоединяться к t3 напрямую, вам не нужны никакие данные оттуда. Присоединившись к t2 во второй раз, вы получите все остальные ключевые слова, которые содержатся в найденных выражениях. Вам нужно только вернуть один из них.


Исправление : если вы не хотите подзапросов, вы можете создать объединение для каждого ключевого слова для поиска:

select distinct t2b.t1key
from 
  t2 t2a
  inner join t2 t2b on t2a.t3key = t2b.t3key and t2a.t1key = 6
  inner join t2 t2c on t2a.t3key = t2c.t3key and t2a.t1key = 5
1 голос
/ 30 марта 2011

Не очень понятно, что вы хотите.

Я буду называть таблицу t1 word, вызывать таблицу t3 phrase и вызывать таблицу t2 word is in phrase.

Тогда, я думаю, вы хотите найти все word.ids, которые находятся в одной фразе с определенным набором word.ids.Это правильно?

SELECT DISTINCT t1.id
FROM t1 
  JOIN t2
    ON t1.id = t2.t1key
  JOIN t2 copyt2
    ON copyt2.t3key = t2.t3key 
WHERE copyt2.t1key IN
  (6,4)       --what you want to check here

ИСПРАВЛЕНИЕ

Читая комментарий Джо и перечитывая детали вопроса, я думаю, вы хотите найти все слова, которые появляютсяв той же фразе со ВСЕМИ словами в указанном вами списке.

Это похоже на проблему реляционного деления:

SELECT DISTINCT t2a.t1key
FROM t2 AS t2a
WHERE NOT EXISTS
  ( SELECT *
    FROM t2 AS t2b
    WHERE t2b.t1key IN (6,4)
      AND NOT EXISTS
      ( SELECT *
        FROM t2 AS t2c
        WHERE t2a.t3key = t2c.t3key
          AND t2c.t1key = t2b.t1key
      )
  )

2-е решение:

SELECT a.t1key
FROM t2 AS a
  JOIN t2 as b
    ON  a.t3key = b.t3key
WHERE b.t1key IN (6,4)       --list you want to check
GROUP BY a.t1key, a.t3key
HAVING COUNT(*) = 2          --size of list
;

3-е решение:

SELECT DISTINCT t1key
FROM t2
WHERE t3key IN
  ( SELECT t3key
    FROM t2
    WHERE t1key IN (6,4)
    GROUP BY t3key
    HAVING COUNT(*) = 2
  )
;

Примечание: Первое (с NON EXISTS) решение сильно отличается от двух других:

Если вы попробуете его со списком, его членыне появляются в таблице t2, скажем, (2) или (2,7), это покажет ВСЕ ключи t1 от t2.

2-е и 3-е решения вообще не будут показывать никаких ключей.

1 голос
/ 30 марта 2011
select distinct t1key
from t2
where t3key in
(
    select t3key from t2 where t1key = 6
    intersect
    select t3key from t2 where t1key = 4
)

==> 3, 4, 6

Вам нужно будет добавить больше «пересекающихся» предложений в зависимости от того, сколько элементов содержится в вашем входном наборе.

Протестировано на SQL Server.

0 голосов
/ 30 марта 2011

Он там, Вы уверены, что выбрали правильную структуру стола?Кажется, он не нормализован - хотя я не знаю точно, какой объект может представлять каждая таблица.

Важно сохранить дизайн базы данных, по крайней мере, в третьей нормальной форме (см. статья в Википедии).

Ваши запросы будут гораздо более естественными и легко формулируемыми

...