Максимальное значение SQL на значение атрибута - PullRequest
0 голосов
/ 24 февраля 2019

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

Я получаю исключение SQL, которое направляет меня на проверку руководства для моей версии SQL (с использованием MySQL).

Отношения

  • Пользователь (UID,UName, State)
  • Песня (SID, AID, SName, ReleaseDate)
  • Исполнитель (AID, AName, Описание)
  • Запись (SID, UID, Дата)

Я пытаюсь SELECT идентификатор пользователя и наиболее часто воспроизводимая песня (по имени) 2018 года. Моя попытка приведена ниже.

Мое обоснование состояло в том, чтобы получить отношение, сгруппированное по идентификатору пользователя (UID) и каждой песне по идентификатору песни (SID) и количеству для каждой песни, а затем объединить названия песен и фильтр для MAX значение, но я здесь упускаю что-то важное, и сравнение моего ответа с другими сообщениями SO о чем-то похожем не очень помогло

SELECT UID, SName
FROM 
(SELECT UID, SName, COUNT(listenDate) AS listen_date_count
    FROM record
    LEFT JOIN song ON song.SID = record.SID
    WHERE YEAR(Date) = 2018
    GROUP BY UID, SName) AS records_2018
GROUP BY UID, SName
HAVING MAX(listen_date_count);

Ответы [ 2 ]

0 голосов
/ 24 февраля 2019

Сначала вы можете LIMIT только для песен.

Затем для этой первой песни, LIMIT для главного пользователя.

SELECT usermost.UID, song.SName
FROM
(
   SELECT songmost.SID, rec.UID
   FROM
   (
      SELECT SID
      FROM record 
      WHERE YEAR(`Date`) = 2018
      GROUP BY SID
      ORDER BY COUNT(*) DESC, COUNT(DISTINCT UID) DESC
      LIMIT 1
  ) songmost
  JOIN record rec 
    ON rec.SID = songmost.SID AND YEAR(rec.`Date`) = 2018
  GROUP BY rec.SID, rec.UID
  ORDER BY COUNT(*) DESC
  LIMIT 1
) usermost
LEFT JOIN song ON song.SID = usermost.SID

Пример:

CREATE TABLE user (
  UID int primary key not null auto_increment, 
  UName varchar(30) not null, 
  State int not null default 0
);
CREATE TABLE artist (
  AID int primary key not null auto_increment, 
  AName varchar(30) not null, 
  Description  varchar(300)
);
create table song (
  SID int primary key not null auto_increment, 
  AID int not null,
  SName varchar(30) not null, 
  ReleaseDate date not null,
  constraint fk_song_aid foreign key (AID) references artist(AID)
);
create table record (
  SID int not null, 
  UID int not null, 
  `Date` date not null,
  constraint fk_record_sid foreign key (SID) references song(SID)
);
insert into user (UName, State) values 
('John Doe', 0), 
('Jane Sheppard', 1);
insert into artist (AName, Description) values 
('Imagine Dragons', 'American pop rock band'),
('Yuki Kajiura', 'Japanese musician, composer and record producer');
insert into song (AID, SName, ReleaseDate) values
(1, 'Whatever it takes', '2017-10-06'),
(2, 'I talk to the rain', '2005-07-05');
insert into  record (SID, UID, `Date`) values 
(1,1,'2018-01-01'),(1,1,'2018-02-01'),(1,2,'2018-03-01'),
(2,1,'2018-04-01'),(2,2,'2018-01-01');
select rec.SID, song.SName, user.UName, artist.AName, COUNT(*) As Total
from record rec
left join song on song.SID = rec.SID
left join user on user.UID = rec.UID
left join artist on artist.AID = song.AID
group by rec.SID, rec.UID
SID | SName              | UName         | AName           | Total
--: | :----------------- | :------------ | :-------------- | ----:
  1 | Whatever it takes  | John Doe      | Imagine Dragons |     2
  1 | Whatever it takes  | Jane Sheppard | Imagine Dragons |     1
  2 | I talk to the rain | John Doe      | Yuki Kajiura    |     1
  2 | I talk to the rain | Jane Sheppard | Yuki Kajiura    |     1
SELECT usermost.UID, song.SName
FROM
(
   SELECT songmost.SID, rec.UID
   FROM
   (
      SELECT SID
      FROM record 
      WHERE YEAR(`Date`) = 2018
      GROUP BY SID
      ORDER BY COUNT(*) DESC, COUNT(DISTINCT UID) DESC
      LIMIT 1
  ) songmost
  JOIN record rec 
    ON rec.SID = songmost.SID AND YEAR(rec.`Date`) = 2018
  GROUP BY rec.SID, rec.UID
  ORDER BY COUNT(*) DESC
  LIMIT 1
) usermost
LEFT JOIN song ON song.SID = usermost.SID
UID | SName            
--: | :----------------
  1 | Whatever it takes

db <> скрипка здесь

0 голосов
/ 24 февраля 2019

Это хорошее начало для агрегирования по кортежу пользователя / песни в подзапросе.Я бы просто добавил условие NOT EXISTS, обеспечивающее отсутствие других кортежей с наибольшим числом просмотров.

Следующий запрос должен дать вам песню с наибольшим количеством просмотров для каждого пользователя в 2018 году:

SELECT *
FROM (
    SELECT r.UID, r.SID, s.SName, COUNT(*) AS listen_date_count
    FROM record r
    INNER JOIN song s ON s.SID = r.SID
    WHERE YEAR(r.Date) = 2018
    GROUP BY r.UID, r.SID, s.SName
) x WHERE NOT EXISTS (
    SELECT 1
    FROM record r1
    WHERE YEAR(r1.Date) = 2018 AND r1.UID = x.UID AND r1.SID != x.SID
    GROUP BY r1.UID, r1.SID
    HAVING COUNT(*) > x.listen_date_count
)

PS:

  • вам нужно SID в группе по пунктам;группирование по SName вместо этого небезопасно, поскольку две разные песни с одинаковым именем в итоге будут неправильно сгруппированы вместе

  • при использовании объединений или коррелированных подзапросов, вы хотите добавить к имени столбца префикссоответствующий префикс таблицы.Это позволяет избежать столкновений и, как правило, облегчает понимание и поддержку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...