Проблема с соединениями — кто-нибудь объяснит мне, что я делаю неправильно?

У меня есть две таблицы member и team со структурой, показанной ниже. Я пытаюсь достичь этих двух результатов:

  1. Количество игроков в каждой команде плюс общая сумма сборов, собранных для каждой команды (т.е. PlayerFee, умноженное на количество игроков).

Схема:

CREATE TABLE member 
(
     MemberID int NOT NULL,
     LastName varchar(20) NOT NULL,
     FirstName varchar(20) NOT NULL,
     MemberType varchar(10) NOT NULL DEFAULT 'Social',
     Phone varchar(20) DEFAULT NULL,
     Handicap int DEFAULT NULL,
     JoinDate date NOT NULL,
     MemberTeam varchar(10) DEFAULT NULL,
     Gender char(1) NOT NULL,
     LifeMember bit(1) NOT NULL DEFAULT b'0',
     PRIMARY KEY (MemberID)
);

INSERT INTO member 
VALUES (118, 'James', 'Melissa', 'Junior', '027-075-0712', 30, '2004-05-08', 'TeamB', 'F', '0');

CREATE TABLE team 
(
     TeamName varchar(10) NOT NULL,
     PracticeNight varchar(10) NOT NULL,
     PlayerFee decimal(10,2) NOT NULL,
     PRIMARY KEY (TeamName)
);

INSERT INTO team 
VALUES ('TeamA', 'Monday', 25.75),
       ('TeamB', 'Tuesday', 16.75); 

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

SELECT
    MemberTeam, Handicap, PracticeNight 
FROM
    member 
RIGHT JOIN 
    team ON member.MemberTeam = team.TeamName 
ORDER BY
    PracticeNight;

Вопрос номер 1 решен, но не знаете, как использовать функцию COUNT с помощью JOIN. Любая помощь приветствуется.

Если вам нужен ответ для «количества X, которые делают Y», вам обычно нужна совокупность COUNT и предложение GROUP BY. Я не уверен, почему вы используете RIGHT JOIN; они редко нужны. Обычно лучше реорганизовать запрос, чтобы использовать ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ (также известное как ЛЕВОЕ СОЕДИНЕНИЕ).

Jonathan Leffler 13.12.2020 05:35

Я также использовал левое соединение, но когда я использую COUNT, я получаю сообщение об ошибке.

Ezy 13.12.2020 05:40

Существует несколько причин получения сообщения об ошибке при (неправильном) использовании COUNT. То, что вы получите, зависит от того, что вы предоставляете в виде SQL. Мы не сможем отладить ваш код COUNT, если вы его не покажете, не так ли? Показанный вами запрос дает какой-то ответ, но я не совсем уверен, какой именно. Я думаю, что он генерирует NULL для столбца Handicap для TeamA, поскольку в TeamA нет игроков. Если вам нужны нули, вы можете использовать COUNT(member.Handicap), но я бы автоматически использовал FROM Member AS m и Team AS t, чтобы сокращать ссылки.

Jonathan Leffler 13.12.2020 05:46

Но каждому столбцу будет присвоено имя таблицы. Вы, вероятно, хотите t.TeamName, а не m.MemberTeam, поскольку вы получите NULL для TeamA, что бесполезно, особенно если есть другие команды без участников.

Jonathan Leffler 13.12.2020 05:47
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
3
4
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Мне нравится использовать TDQD — Test-Driven Query Design — для решения сложных SQL-запросов. Это не особенно сложные запросы, но идея все же позволяет вам получить правильные результаты.

Запрос 1 — количество участников, которые посещают тренировки в каждый день недели.

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

Шаг 1 — В какой вечер участники посещают тренировки?

SELECT m.Member, t.TeamName, t.PracticeNight
  FROM member AS m
  JOIN team AS t ON m.MemberTeam = t.TeamName

Шаг 2 — Сколько игроков посещают тренировки в каждый день недели?

SELECT p.PracticeNight, COUNT(*) AS NumberOfPlayers
  FROM (SELECT m.Member, t.TeamName, t.PracticeNight
          FROM member AS m
          JOIN team AS t ON m.MemberTeam = t.TeamName
       ) AS p
 GROUP BY p.PracticeNight

Обратите внимание, что это не гарантирует никакого порядка вывода. Добавление ORDER BY p.PracticeNight даст данные в последовательности Friday, Monday, Saturday, Sunday, Thursday, Tuesday, Wednesday, потому что это будет алфавитный порядок. Вам нужно будет ввести DayOfWeekNumber для каждого дня недели, например, от 0 для воскресенья до 6 для субботы или 1 для понедельника и 7 для воскресенья, в зависимости от ваших предпочтений.

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

Запрос 2 — количество игроков в каждой команде и общая сумма сборов с каждой команды.

Часть «общие сборы» — это просто подсчет количества игроков в каждой команде, умноженный на сбор игроков команды.

Шаг 1 — Какие игроки есть в каждой команде?

SELECT m.Member, t.TeamName
  FROM member AS m
  JOIN team AS t ON m.MemberTeam = t.TeamName

Шаг 2 — Сколько игроков в каждой команде?

SELECT t.TeamName, COUNT(*) AS NumberOfPlayers
  FROM team AS t
  JOIN member AS m ON t.TeamName = m.MemberTeam
 GROUP BY t.TeamName

Шаг 3 — И общая сумма сборов?

SELECT t.TeamName, COUNT(*) AS NumberOfPlayers, COUNT(*) * t.PlayerFee AS TotalFees
  FROM team AS t
  JOIN member AS m ON t.TeamName = m.MemberTeam
 GROUP BY t.TeamName

Шаг 4 — А команды без игроков?

Команды без участников не будут включены в выходные данные. Чтобы получить нули для таких команд, используйте LEFT OUTER JOIN (которое можно сократить до LEFT JOIN):

SELECT t.TeamName,
       COUNT(m.MemberID) AS NumberOfPlayers,
       COUNT(m.MemberID) * t.PlayerFee AS TotalFees
  FROM team AS t
  LEFT JOIN member AS m ON t.TeamName = m.MemberTeam
 GROUP BY t.TeamName

Агрегат COUNT не подсчитывает значения NULL, когда вы указываете имя столбца. Когда в команде нет члена (TeamA страдает от этого унижения в данных выборки), LOJ генерирует NULL для m.MemberID, поэтому COUNT(m.MemberID) генерирует 0.

Warning: None of the SQL above has been tested; there could be bugs!

Спасибо, что нашли время, чтобы помочь, это много значит. ты великолепен :-)

Ezy 13.12.2020 07:25

Для № 1 части 2, разве не должно быть COUNT (DISTINCT p.MemberID)? Потому что игрок может быть членом нескольких команд с одним и тем же PracticeNight.

ATOMP 13.12.2020 08:50

[…первые мысли…] Возможно, но маловероятно, чтобы лига позволяла игроку принадлежать более чем к одной команде одновременно. Я бы даже не рассматривал такую ​​​​возможность — однако реальный мир иногда вторгается, и известны более странные вещи. Я не уверен, как игрок справится с принадлежностью к двум командам, которые тренируются в один и тот же вечер. Я знаю, что если бы я был менеджером любой из этих команд, я был бы недоволен игроком, который также принадлежит другой команде. […заменено мыслями ниже…]

Jonathan Leffler 13.12.2020 09:11

Если подумать — нет. MemberID — первичный ключ таблицы Members; поэтому он уникален, и один MemberID может принадлежать только одной команде. Есть отдельная проблема с тем, «что, если человеку будут выделены отдельные значения MemberID, чтобы он мог принадлежать к двум командам»; это административная неразбериха, наверное. Но MemberID уникален и идентифицирует (максимум) одну команду. Между Members.MemberTeam и Teams.TeamName не объявлено ограничение внешнего ключа, но это, вероятно, скорее недосмотр, чем что-либо еще.

Jonathan Leffler 13.12.2020 09:11

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