У меня есть простая (я полагаю) проблема, которая сбивает меня с толку (я не эксперт по SQL, как вы скоро увидите ... :-).

У меня есть таблица person с полями id и name и таблица comment с полями id, id_person и text :

---------------
 table: person
---------------
 id | name
---------------

---------------------------
 table: comment
---------------------------
 id | id_person | text
---------------------------

Комментарии связаны с людьми на person.id => comment.id_person.
У каждого человека может быть много комментариев.
Я бы предпочел не сохранять количество комментариев в любой таблице.

Возникает вопрос: Как выбрать всех людей, у которых есть не менее N комментариев?

Это то, что я сейчас пытаюсь, но это конечно неправильно ...:

SELECT * FROM person WHERE (SELECT COUNT(*) FROM comment WHERE id_person = 2) >= N

P.S .: Сейчас я работаю с sqlite, но стандартный ответ SQL подойдет ...

2
MarcoS 11 Мар 2015 в 23:07

3 ответа

Лучший ответ

Я не уверен, что понимаю, что не так с тем, что вы пробовали. Вы жестко кодируете идентификатор, но если вы просто замените его, все будет в порядке.

SELECT *
FROM person
WHERE (SELECT COUNT(*)
       FROM comment
       WHERE id_person = person.id) >= N

Другое решение, лучше или нет, трудно определить (вы должны попробовать каждое, если производительность вызывает беспокойство, или, по крайней мере, проверить планы запросов), - это использовать предложение GROUP BY:

SELECT *
FROM person
WHERE id IN (SELECT id_person
             FROM comment
             GROUP BY id_person
             HAVING COUNT(*) >= N)

Мне нравится использовать здесь предложение IN по сравнению с INNER JOIN, потому что оно позволяет вам делать SELECT *, как в вашем примере. Конечно, это может иногда не быть идеальным, но похоже, что это подходит для вашего случая.

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

4
Community 23 Май 2017 в 12:12
DECLARE @N  INT--Here I declared variable N, but you could simply hardcode the value instead.
SELECT @N = 2

select  person.id,
        person.name 
from person 
INNER JOIN comment ON person.id = comment.id_person
GROUP BY person.id,
         person.name 
HAVING COUNT(comment.id) >= @N
0
AXMIM 11 Мар 2015 в 20:18

Проще всего было бы использовать такие предложения group by и having

select p.name 
from   person p
       inner join comment c on c.id_person = p.id
group by
       p.name
having count(*) = 2

В качестве примечания: я бы переименовал ваши столбцы в

---------------------------
table: person
---------------
 id_person | name
---------------

---------------------------
 table: comment
---------------------------
 id_comment | id_person | text
---------------------------

Чтобы было понятно, какие столбцы связаны друг с другом. Когда-нибудь вы столкнетесь с новой для вас схемой базы данных, в которой имена не совпадают, и вам придется прибегать к поиску отношений внешних ключей, чтобы решить эту проблему. Поверьте, это не весело.

3
Lieven Keersmaekers 11 Мар 2015 в 20:15