Подтвердить что ты не робот

Использование групповой и имеющей оговорки

Используя следующую схему:

Supplier (sid, name, status, city)
Part (pid, name, color, weight, city)
Project (jid, name, city)
Supplies (sid, pid, jid**, quantity)
  • Получить номера и имена поставщиков для поставщиков комплектующих, поставляемых по меньшей мере в двух разных проектах.

  • Получить номера поставщиков и имена поставщиков одной и той же части по меньшей мере в двух разных проектах.

Это были мои ответы:

1.

SELECT s.sid, s.name
FROM Supplier s, Supplies su, Project pr
WHERE s.sid = su.sid AND su.jid = pr.jid
GROUP BY s.sid, s.name
HAVING COUNT (DISTINCT pr.jid) >= 2 

2.

SELECT s.sid, s.name
FROM Suppliers s, Supplies su, Project pr, Part p
WHERE s.sid = su.sid AND su.pid = p.pid AND su.jid = pr.jid
GROUP BY s.sid, s.name
HAVING COUNT (DISTINCT pr.jid)>=2

Может ли кто-нибудь подтвердить, правильно ли я это написал? Я немного смущен относительно того, как работает функция Group By and Have

4b9b3361

Ответ 1

Семантика наличия

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

A группа - это запрос, который берет таблицу и суммирует ее в другой таблице. Вы суммируете исходную таблицу, группируя исходную таблицу в подмножества (на основе атрибутов, которые вы указали в группе). Каждая из этих групп даст один кортеж.

Имея, просто эквивалентно предложению WHERE после, группа выполнила и до того, как вычисляется часть запроса select.

Допустим, что ваш запрос:

select a, b, count(*) 
from Table 
where c > 100 
group by a, b 
having count(*) > 10;

Оценить этот запрос можно следующим образом:

  • Выполните WHERE, исключив строки, которые не удовлетворяют этому.
  • Группировать таблицу в подмножества, основанные на значениях a и b (каждый кортеж в каждом подмножестве имеет те же значения a и b).
  • Устранить подмножества, не удовлетворяющие условию HAVING
  • Обработка каждого подмножества, выводящего значения, как указано в части SELECT запроса. Это создает один выходной набор на подмножество, оставшееся после шага 3.

Вы можете расширить это на любой сложный запрос. Таблица может представлять собой любой сложный запрос, возвращающий таблицу (кросс-продукт, соединение, UNION и т.д.).

Фактически имеет синтаксический сахар и не увеличивает возможности SQL. Любой заданный запрос:

SELECT list 
FROM table
GROUP BY attrList
HAVING condition;

можно переписать как:

SELECT list from (
   SELECT listatt 
   FROM table 
   GROUP BY attrList) as Name
WHERE condition;

Listatt - это список, который включает атрибуты GROUP BY и выражения, используемые в списке и состоянии. Может потребоваться назвать некоторые выражения в этом списке (с AS). Например, приведенный выше пример запроса можно переписать как:

select a, b, count 
from (select a, b, count(*) as count
      from Table 
      where c > 100
      group by a, b) as someName
where count > 10;

Требуемое решение

Ваше решение кажется правильным:

SELECT s.sid, s.name
FROM Supplier s, Supplies su, Project pr
WHERE s.sid = su.sid AND su.jid = pr.jid
GROUP BY s.sid, s.name
HAVING COUNT (DISTINCT pr.jid) >= 2 

Вы присоединяетесь к трем таблицам, а затем используете sid в качестве атрибута группировки (sname функционально зависит от него, поэтому он не влияет на количество групп, но вы должны включать его, в противном случае он не может быть частью выбранной части заявления). Затем вы удаляете те, которые не удовлетворяют вашему условию: удовлетворяют pr.jid is >= 2, которые вы хотели первоначально.

Лучшее решение вашей проблемы

Я лично предпочитаю более простое решение для очистки:

  • Вам нужно группировать только товары (sid, pid, jid **, количество), чтобы найти сид из тех, которые поставляют по меньшей мере два проекта.
  • Затем присоедините его к таблице поставщиков, чтобы получить тот же поставщик.

 SELECT sid, sname from
    (SELECT sid from supplies 
    GROUP BY sid, pid 
    HAVING count(DISTINCT jid) >= 2
    ) AS T1
NATURAL JOIN 
Supliers;

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

- DMG

Ответ 2

Поскольку мы не можем использовать предложение Where с совокупными функциями, например count(), min(), sum() и т.д., так что возникла оговорка, чтобы преодолеть это проблема в sql. см. пример для предложения, перейдите по этой ссылке

http://www.sqlfundamental.com/having-clause.php

Ответ 3

Прежде всего, вы должны использовать синтаксис JOIN, а не FROM table1, table2, и вы должны всегда ограничивать группировку как можно меньше полей.

Скорее всего, я не тестировал, ваш первый запрос кажется мне хорошим, но может быть переписан как:

SELECT s.sid, s.name
FROM 
    Supplier s
    INNER JOIN (
       SELECT su.sid
       FROM Supplies su
       GROUP BY su.sid
       HAVING COUNT(DISTINCT su.jid) > 1
    ) g
        ON g.sid = s.sid

Или упрощено как:

SELECT sid, name
FROM Supplier s
WHERE (
    SELECT COUNT(DISTINCT su.jid)
    FROM Supplies su
    WHERE su.sid = s.sid
) > 1

Однако второй запрос кажется мне неправильным, потому что вы также должны GROUP BY pid.

 SELECT s.sid, s.name
    FROM 
        Supplier s
        INNER JOIN (
            SELECT su.sid
            FROM Supplies su
            GROUP BY su.sid, su.pid
            HAVING COUNT(DISTINCT su.jid) > 1
        ) g
            ON g.sid = s.sid

Как вы могли заметить в вышеприведенном запросе, я использовал синтаксис INNER JOIN для выполнения фильтрации, однако его можно также записать как:

SELECT s.sid, s.name
FROM Supplier s
WHERE (
     SELECT COUNT(DISTINCT su.jid)
     FROM Supplies su
     WHERE su.sid = s.sid
     GROUP BY su.sid, su.pid
) > 1

Ответ 4

Какой тип базы данных sql использует (MSSQL, Oracle и т.д.)? Я верю, что вы написали правильно.

Вы также можете написать первый запрос следующим образом:

SELECT s.sid, s.name
FROM Supplier s
WHERE (SELECT COUNT(DISTINCT pr.jid)
       FROM Supplies su, Projects pr
       WHERE su.sid = s.sid 
           AND pr.jid = su.jid) >= 2

Это немного более читаемо и меньше ума, чем попытка сделать это с помощью GROUP BY. Производительность может отличаться.

Ответ 5

1.Введите номера и имена поставщиков для поставщиков комплектующих, поставляемых по меньшей мере в два разных проекта.

 SELECT S.SID, S.NAME
 FROM SUPPLIES SP
 JOIN SUPPLIER S
 ON SP.SID = S.SID
 WHERE PID IN
 (SELECT PID FROM SUPPPLIES GROUP BY PID, JID HAVING COUNT(*) >= 2)

Я не догадываюсь о вашем втором вопросе