У меня есть две таблицы member
и team
со структурой, показанной ниже. Я пытаюсь достичь этих двух результатов:
Схема:
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. Любая помощь приветствуется.
Я также использовал левое соединение, но когда я использую COUNT, я получаю сообщение об ошибке.
Существует несколько причин получения сообщения об ошибке при (неправильном) использовании COUNT. То, что вы получите, зависит от того, что вы предоставляете в виде SQL. Мы не сможем отладить ваш код COUNT, если вы его не покажете, не так ли? Показанный вами запрос дает какой-то ответ, но я не совсем уверен, какой именно. Я думаю, что он генерирует NULL для столбца Handicap
для TeamA
, поскольку в TeamA
нет игроков. Если вам нужны нули, вы можете использовать COUNT(member.Handicap)
, но я бы автоматически использовал FROM Member AS m
и Team AS t
, чтобы сокращать ссылки.
Но каждому столбцу будет присвоено имя таблицы. Вы, вероятно, хотите t.TeamName
, а не m.MemberTeam
, поскольку вы получите NULL для TeamA
, что бесполезно, особенно если есть другие команды без участников.
Мне нравится использовать TDQD — Test-Driven Query Design — для решения сложных SQL-запросов. Это не особенно сложные запросы, но идея все же позволяет вам получить правильные результаты.
Запрос должен установить, в какую ночь каждый игрок посещает тренировку, а затем подсчитать количество игроков, посещающих данную ночь.
SELECT m.Member, t.TeamName, t.PracticeNight
FROM member AS m
JOIN team AS t ON m.MemberTeam = t.TeamName
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 для воскресенья, в зависимости от ваших предпочтений.
Обратите внимание, что этот запрос не возвращает ноль для дней, когда команды не тренируются, или для дней, когда в единственных командах, которые тренируются в этот день, нет участников. Исправить это значительно сложнее и требует где-то списка возможных дней недели, чтобы можно было убедиться, что все дни представлены в выходных данных.
Часть «общие сборы» — это просто подсчет количества игроков в каждой команде, умноженный на сбор игроков команды.
SELECT m.Member, t.TeamName
FROM member AS m
JOIN team AS t ON m.MemberTeam = t.TeamName
SELECT t.TeamName, COUNT(*) AS NumberOfPlayers
FROM team AS t
JOIN member AS m ON t.TeamName = m.MemberTeam
GROUP BY t.TeamName
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
Команды без участников не будут включены в выходные данные. Чтобы получить нули для таких команд, используйте 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!
Спасибо, что нашли время, чтобы помочь, это много значит. ты великолепен :-)
Для № 1 части 2, разве не должно быть COUNT (DISTINCT p.MemberID)
? Потому что игрок может быть членом нескольких команд с одним и тем же PracticeNight.
[…первые мысли…] Возможно, но маловероятно, чтобы лига позволяла игроку принадлежать более чем к одной команде одновременно. Я бы даже не рассматривал такую возможность — однако реальный мир иногда вторгается, и известны более странные вещи. Я не уверен, как игрок справится с принадлежностью к двум командам, которые тренируются в один и тот же вечер. Я знаю, что если бы я был менеджером любой из этих команд, я был бы недоволен игроком, который также принадлежит другой команде. […заменено мыслями ниже…]
Если подумать — нет. MemberID
— первичный ключ таблицы Members
; поэтому он уникален, и один MemberID
может принадлежать только одной команде. Есть отдельная проблема с тем, «что, если человеку будут выделены отдельные значения MemberID, чтобы он мог принадлежать к двум командам»; это административная неразбериха, наверное. Но MemberID уникален и идентифицирует (максимум) одну команду. Между Members.MemberTeam и Teams.TeamName не объявлено ограничение внешнего ключа, но это, вероятно, скорее недосмотр, чем что-либо еще.
Если вам нужен ответ для «количества X, которые делают Y», вам обычно нужна совокупность COUNT и предложение GROUP BY. Я не уверен, почему вы используете RIGHT JOIN; они редко нужны. Обычно лучше реорганизовать запрос, чтобы использовать ЛЕВОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ (также известное как ЛЕВОЕ СОЕДИНЕНИЕ).