относительное деление

Я должен написать запрос для этого оператора:

Перечислите имена покупателей и названия альбомов для случаев, когда покупатель купил весь альбом (т. е. все треки в альбоме).

Я знаю, что должен использовать разделение.

Вот мой ответ, но я получаю странные синтаксические ошибки, которые не могу решить.

SELECT 
     R1.FirstName
     ,R1.LastName
     ,R1.Title
FROM (Customer C, Invoice I, InvoiceLine IL, Track T, Album Al) AS R1
WHERE 
     C.CustomerId=I.CustomerId 
     AND I.InvoiceId=IL.InvoiceId
     AND T.TrackId=IL.TrackId 
     AND Al.AlbumId=T.AlbumId
     AND NOT EXISTS ( 
          SELECT 
               R2.Title
           FROM (Album Al, Track T) AS R2
           WHERE 
                T.AlbumId=Al.AlbumId
                AND R2.Title NOT IN (
                    SELECT R3.Title
                    FROM (Album Al, Track T) AS R3
                    WHERE 
                        COUNT(R1.TrackId)=COUNT(R3.TrackId)
                )
     );

ОШИБКА: misuse of aggregate function COUNT()

Схему базы данных можно найти здесь


person RedHood148    schedule 19.05.2016    source источник
comment
Вам не хватает закрывающей скобки в самом конце. (Два открытых подзапроса, одна закрывающая скобка)   -  person Aaron Dietz    schedule 19.05.2016
comment
( SELECT R2.Title FROM (Album Al, Track T) AS R2 кажется мне взволнованным. Вы собираетесь сделать кросс-соединение между альбомом и треком?   -  person xQbert    schedule 19.05.2016
comment
Я исправил скобки, но все равно получаю эту ошибку misuse of aggregate function COUNT() @Aaron D   -  person RedHood148    schedule 19.05.2016
comment
Да. В этой строке нет проблем. Я проверил это в других запросах. @xQbert   -  person RedHood148    schedule 19.05.2016
comment
Зачем использовать деление? Ваш подход кажется слишком сложным. Создайте два набора данных: 1 перечислите все треки в альбоме вместе с их количеством, другой перечислите количество треков, которые пользователь купил для каждого альбома, сравните два итоговых значения, если они совпадают, то они купили их все. Просто мои 2 цента   -  person xQbert    schedule 19.05.2016
comment
Я пытался использовать INTERSECT. Я получаю правильный ответ, но в этом запросе я не могу получить имена клиентов в результате. @xQbert   -  person RedHood148    schedule 19.05.2016
comment
stackoverflow.com/questions/648083/   -  person BoogaWooga    schedule 19.05.2016
comment
В вашей БД может ли человек купить один и тот же Трек более одного раза? Если да, то вам, возможно, придется переосмыслить свою методологию, потому что в этом случае количество (купленные мной треки) может равняться или даже превышать количество (треков в альбоме) без того, чтобы я покупал весь альбом.   -  person jdg    schedule 19.05.2016
comment
Нет, очевидно, они не могут, кроме одного и того же трека дважды. Это не имеет смысла. @jdg   -  person RedHood148    schedule 19.05.2016


Ответы (4)


Вы не можете использовать псевдоним списка таблиц, например (Album Al, Track T), который является устаревшим синтаксисом для (Album Al CROSS JOIN Track T). Вы можете использовать псевдоним таблицы, например. Album Al или подзапрос, например. (SELECT * FROM Album CROSS JOIN Track) AS R2.

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

Тогда вы не можете использовать WHERE COUNT(R1.TrackId) = COUNT(R3.TrackId). COUNT — это агрегатная функция, и агрегирование выполняется после WHERE.

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

Запрос для получения количества треков в альбоме:

select albumid, count(*)
from track
group by albumid;

Запрос, чтобы получить количество треков для каждого клиента и альбома:

select i.customerid, t.albumid, count(distinct t.trackid)
from track t
join invoiceline il on il.trackid = t.trackid
join invoice i on i.invoiceid = il.invoiceid
group by i.customerid, t.albumid;

Полный запрос:

select c.firstname, c.lastname, a.title
from
(
  select i.customerid, t.albumid, count(distinct t.trackid) as cnt
  from track t
  join invoiceline il on il.trackid = t.trackid
  join invoice i on i.invoiceid = il.invoiceid
  group by i.customerid, t.albumid
) bought
join
(
  select albumid, count(*) as cnt
  from track
  group by albumid
) complete on complete.albumid = bought.albumid and complete.cnt = bought.cnt
join customer c on c.customerid = bought.customerid
join album a on a.albumid = bought.albumid;
person Thorsten Kettner    schedule 19.05.2016
comment
Мне нравится, как вы подходите к проблеме. Я запускаю запрос, но получаю ambiguous column name: trackid: @thorsten-kettner - person RedHood148; 19.05.2016
comment
Я исправил это, добавив t.trackid. теперь я получаю no such column: c.firstname - person RedHood148; 19.05.2016
comment
Да, я забыл квалификатор для trackid. Но что касается c.firstname, я не в курсе. Мы присоединяемся к таблице customer, вызываем ее c и выбираем ее столбец firstname. Или такой колонки нет? Возможно, это уже опечатка в вашем запросе, а настоящее имя — first_name или подобное? Проверьте таблицу клиентов, если есть столбец с таким именем. - person Thorsten Kettner; 19.05.2016
comment
Есть лишний ; в complete.cnt = bought.cnt;, его надо убрать. После этого работает нормально. - person RedHood148; 19.05.2016
comment
Ах, извините за это. Я рад, что мой запрос теперь работает для вас. - person Thorsten Kettner; 19.05.2016

Кажется, вы используете count не в том месте

использовать для агрегатной функции

 SELECT R3.Title
    FROM (Album Al, Track T) AS R3
    HAVING  COUNT(R1.TrackId)=COUNT(R3.TrackId))

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

person scaisEdge    schedule 19.05.2016
comment
Хорошо подмечено, но это все равно не сработает. Поскольку идентификаторы дорожек, конечно, не равны нулю, HAVING COUNT(R1.TrackId) = COUNT(R3.TrackId) равно HAVING COUNT(*) = COUNT(*), что, в свою очередь, равносильно отсутствию предложения HAVING вообще. - person Thorsten Kettner; 19.05.2016

Вы должны упростить свой запрос. Взгляните на это:

SELECT FirstName
    , LastName
    , Title
FROM (
    SELECT C.FirstName
         , C.LastName
         , A.AlbumID
         , A.Title
         , COUNT(DISTINCT TrackID) as TracksInvoiced
    FROM Customer C
    INNER JOIN Invoice I
    ON I.CustomerId = C.CustomerId
    INNER JOIN InvoiceLine IL
    ON I.InvoiceId = IL.InvoiceId
    INNER JOIN Track T 
    ON T.TrackID = I
    INNER JOIN Album A 
    ON A.AlbumID = T.AlbumID
    GROUP BY C.FirstName, C.LastName, A.AlbumID, A.Title
) C
INNER JOIN (
    SELECT AlbumID
        , COUNT(TrackID) as TotalTracks
    FROM Track
    GROUP BY AlbumID
) A
ON C.AlbumID = A.AlbumID
AND TracksInvoiced = TotalTracks

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

person Raul Sebastian    schedule 19.05.2016

Этот кажется немного менее сложным:

SELECT r.FirstName, r.LastName, r.Title FROM
(
    SELECT C.FirstName as FirstName,
           C.LastName as LastName,
           A.Title as Title,
           A.AlbumId as AlbumId,
           COUNT(*) as count
    FROM Customer C, Invoice I, InvoiceLine IL, Track T, Album A
    WHERE C.CustomerId=I.CustomerId
      AND I.InvoiceId = IL.InvoiceId
      AND T.TrackId   = IL.TrackId
      AND A.AlbumId   = T.AlbumId
    GROUP BY C.CustomerId, A.AlbumId
) AS r
WHERE r.count IS IN
(
    SELECT COUNT(*) FROM Track T
    WHERE T.AlbumId = r.AlbumId
)

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

person Aconcagua    schedule 19.05.2016
comment
Ваш запрос неверен. Вам не хватает A.AlbumId в предложении GROUP BY. И вы не должны использовать коррелированные предложения IN. Используйте коррелированный EXISTS или некоррелированный IN, чтобы не запутать читателя. Между прочим, присоединение к альбому в предложении IN лишнее. - person Thorsten Kettner; 19.05.2016
comment
Спасибо за подсказки - не удалось попробовать запрос, он был задуман как подсказка, чтобы найти решение, пока не существовало лучших ответов... - person Aconcagua; 19.05.2016