Вопрос

У меня есть запрос, подобный этому:

SELECT t1.id,
    (SELECT COUNT(t2.id)
     FROM t2
     WHERE t2.id = t1.id
          ) as num_things
FROM t1
WHERE num_things = 5;

Цель состоит в том, чтобы получить идентификатор всех элементов, которые появляются 5 раз в другой таблице.Однако я получаю эту ошибку:

ERROR: column "num_things" does not exist
SQL state: 42703

Вероятно, я делаю здесь что-то глупое, поскольку я несколько новичок в базах данных.Есть ли способ исправить этот запрос, чтобы я мог получить доступ num_things?Или, если нет, есть ли какой-либо другой способ достижения этого результата?

Это было полезно?

Решение

Я думаю, вы могли бы просто переписать свой запрос следующим образом:

SELECT t1.id
FROM t1
WHERE (SELECT COUNT(t2.id)
     FROM t2
     WHERE t2.id = t1.id
          ) = 5;

Другие советы

Несколько важных моментов об использовании SQL:

  • Вы не можете использовать псевдонимы столбцов в предложении WHERE, но вы можете использовать их в предложении HAVING.Это причина ошибки, которую вы получили.
  • Вы можете лучше подсчитать, используя JOIN и GROUP BY, чем используя коррелированные подзапросы.Так будет намного быстрее.
  • Используйте предложение HAVING для фильтрации групп.

Вот как я бы написал этот запрос:

SELECT t1.id, COUNT(t2.id) AS num_things
FROM t1 JOIN t2 USING (id)
GROUP BY t1.id
HAVING num_things = 5;

Я понимаю, что этот запрос может пропустить JOIN с t1, как в решении Чарльза Бретаны.Но я предполагаю, что вы можете захотеть, чтобы запрос включал некоторые другие столбцы из t1.


Ре:вопрос в комментарии:

Разница в том, что WHERE предложение вычисляется в строках, перед GROUP BY уменьшает количество групп до одной строки для каждой группы.Тот Самый HAVING предложение оценивается после формирования групп.Таким образом, вы не можете, например, изменить COUNT() группы с помощью HAVING;вы можете исключить только саму группу.

SELECT t1.id, COUNT(t2.id) as num
FROM t1 JOIN t2 USING (id)
WHERE t2.attribute = <value>
GROUP BY t1.id
HAVING num > 5;

В приведенном выше запросе, WHERE фильтрует строки, соответствующие условию, и HAVING фильтры для групп, количество которых не менее пяти.

Момент, который приводит большинство людей в замешательство, заключается в том, что у них нет GROUP BY оговорка, так что это кажется Нравится HAVING и WHERE являются взаимозаменяемыми.

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

SELECT <expensive expressions>
FROM t1
HAVING primaryKey = 1234;

Если вы используете запрос, подобный приведенному выше, выражения в списке выбора вычисляются для каждая строка, только для того , чтобы отбросить большую часть результатов из - за HAVING состояние.Однако приведенный ниже запрос вычисляет выражение только для одиночный ряд соответствующий WHERE состояние.

SELECT <expensive expressions>
FROM t1
WHERE primaryKey = 1234;

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

  1. Сгенерировать набор строк из таблицы (таблиц), включая любые строки, созданные JOIN.
  2. Оценивать WHERE условия для набора строк, отфильтровывая строки, которые не совпадают.
  3. Вычислите выражения в списке выбора для каждого из набора строк.
  4. Примените псевдонимы столбцов (обратите внимание, что это отдельный шаг, который означает, что вы не можете использовать псевдонимы в выражениях в списке выбора).
  5. Сведите группы к одной строке для каждой группы в соответствии с GROUP BY оговорка.
  6. Оценивать HAVING условия для групп, отфильтровывающие группы, которые не совпадают.
  7. Отсортируйте результат в соответствии с ORDER BY оговорка.

Все остальные предложения сработают, но для ответа на ваш основной вопрос достаточно написать

  SELECT id  From T2
  Group By Id
  Having Count(*) = 5

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

т. е.

ВЫБЕРИТЕ usr_id В КАЧЕСТВЕ my_id У пользователя, ИМЕЮЩЕГО my_id = 1

Не сработает.

Еще один пример, который не сработает:

ВЫБЕРИТЕ su.usr_id КАК my_id, ПОСЧИТАЙТЕ (*) КАК val ИЗ sys_user КАК ГРУППУ su ПО su.usr_id, ИМЕЮЩЕМУ значение >= 1

Возникнет та же ошибка:значение столбца неизвестно.

Я подчеркиваю это, потому что Билл Карвин написал что-то не совсем верное для Postgres:

"Вы не можете использовать псевдонимы столбцов в предложении WHERE, но вы можете в предложении HAVING.Это причина ошибки, которую вы получили ".

попробуйте это

SELECT t1.id,
    (SELECT COUNT(t2.id) as myCount
     FROM t2
     WHERE t2.id = t1.id and myCount=5
          ) as num_things
FROM t1
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top