MySQL внешняя замена соединения
Я работаю над системой управления запасами игр и хотел бы отобразить список пожеланий владельца пополнения запасов и количество заказов на покупку клиентов для каждой игры в одном столе. Я написал запрос, который, как мне казалось, работал, но затем я заметил, что он на самом деле опускает любые игры, для которых есть оговорки, но которые изначально не находятся в списке пожеланий пополнения. Запрос приведен ниже:
SELECT rwl.*, g.gameName, coalesce(payYes, 0) payYes, coalesce(payNo, 0) payNo FROM RestockWishList AS rwl, Games AS g
LEFT JOIN
(SELECT gameID, COUNT(if(prepaid='Yes', 1, NULL)) payYes, COUNT(if(prepaid='No', 1, NULL)) payNo FROM ReservationsBuy GROUP BY gameID) AS res
ON res.gameID = g.gameID
WHERE rwl.gameID = g.gameID;
Результаты запроса: gameID, количество, название игры, плати!, пайно
1, Четыре, Замок для все времена года, Ноль, 0
2, Два, Несколько акров снега, Ноль, 0
18, Четыре, Алхамбра, Ноль, 0
[3]}54, Два, Большое Ошеломление, Два, 0 По-видимому, решение этой проблемы заключается в использовании полного внешнего соединения вместо левого соединения, но MySQL не поддерживает эту функцию. Я потратил много часов, пытаясь перевести его в структуру профсоюза, но не могу заставить его работать правильно. Это самое близкое, что у меня есть:SELECT rwl.*, res.gameID, res.payYes, res.payNo FROM RestockWishList rwl
LEFT JOIN
(SELECT gameID, COUNT(if(prepaid='Yes', 1, NULL)) payYes, COUNT(if(prepaid='No', 1, NULL)) payNo FROM ReservationsBuy GROUP BY gameID) AS res
ON res.gameID = rwl.gameID
UNION
SELECT rwl.*, res.gameID, COUNT(if(prepaid='Yes', 1, NULL)) payYes, COUNT(if(prepaid='No', 1, NULL)) payNo FROM ReservationsBuy res
LEFT JOIN RestockWishList rwl ON rwl.gameID = res.gameID;
Результаты запроса: gameID, количество, gameID, payYes, payNo
1, 4, NULL, NULL, NULL
2, 2, NULL, NULL, NULL
18, 4, NULL, NULL, NULL
54, 2, 54, 2, 0
NULL, NULL, 30, 3, 1
(Извините, я не знаю, как красиво форматировать результаты таблицы запросов в StackOverflow.)
Я хочу, чтобы запрос отображался так, как я его изначально написал, только с пропущенными значениями из ReservationsBuy. Конкретная помощь, пожалуйста?
Таблицы:
CREATE TABLE IF NOT EXISTS RestockWishList (
gameID INT(6),
quantity INT(3) NOT NULL,
PRIMARY KEY (gameID),
FOREIGN KEY (gameID) REFERENCES Games(gameID) ON UPDATE CASCADE ON DELETE CASCADE);
CREATE TABLE IF NOT EXISTS ReservationsBuy (
gameID INT(6),
customerEmail VARCHAR(25) NOT NULL,
customerName VARCHAR(25) NOT NULL,
dateReserved DATETIME NOT NULL, #date customer files game reservation
datePurchased DATETIME, #date Board and Brew restocks game
dateClaimed DATETIME, #date customer physically claims game
prepaid ENUM('Yes', 'No') NOT NULL,
PRIMARY KEY (gameID, customerEmail),
FOREIGN KEY (gameID) REFERENCES Games (gameID) ON UPDATE CASCADE ON DELETE CASCADE);
Образец данные: RestockWishList:
GameID, количество
1, 4
2, 2
18, 4
[3]}54, 2ReservationsBuy:
GameID, customerEmail, customerName, dateReserved, дата покупки, dateClaimed, prepaid
30, wonder@woman.com, Диана, 2015-04-24 14: 46: 05, НУЛЕВОЙ, НУЛЕВОЙ, Да
[3]}54, boggie@marsh.com, багги, 2015-04-24 14: 43: 32, НУЛЕВОЙ, НУЛЕВОЙ, Да [3]}54, manny@second.com, Мэнни, 2015-04-27 19: 48: 22, НУЛЕВОЙ, НУЛЕВОЙ, Да43, old@mom.com, бабуля, 2015-04-23 22: 32: 03, НУЛЕВОЙ, НУЛЕВОЙ, Нет
Ожидаемый результат: gameID, количество, gameName, payYes, payNo
1, 4, Замок на все времена года, 0, 0
2, 2, несколько акров снега, 0, 0
18, 4, Альгамбра, 0, 0
30, 0, Arkham Horror, 1, 0
43, 0, Бананаграммы, 0, 1
54, 2, Big Boggle, 2, 0
(Таблица игр не особенно важна для этого запроса. Только релевантность в том, что и то и другое ReservationsBuy и RestockWishList связаны с играми по gameID)
3 ответа:
Вы на правильном пути с использованием
FULL OUTER JOIN
, у вас просто неправильная реализация.A
FULL OUTER JOIN
в MySQL можно рассматривать какUNION
aLEFT JOIN
и ARIGHT JOIN
. В своем запросе вы пытаетесь приблизить это, рассматриваяRIGHT JOIN
часть логики как обратнуюLEFT JOIN
из двух таблиц, но ваша первая часть не работает, потому что это не подвыборка с той же последовательностьюGROUP BY
, что и ваша перваяLEFT JOIN
.Самое простое, что нужно сделать, это просто взять ваш первый запрос
LEFT JOIN
строфа, скопируйте ее во вторую строфу и заменитеLEFT JOIN
наRIGHT JOIN
, затем свяжите результаты с таблицей игр, например:SELECT g.gameID, IFNULL(q.quantity, 0) AS quantity, g.gameName, IFNULL(q.payYes, 0) AS payYes, IFNULL(q.payNo, 0) AS payNo FROM games g INNER JOIN ( SELECT IFNULL(rwl.gameID, res.gameID) AS gameID, rwl.quantity, res.payYes, res.payNo FROM RestockWishList rwl LEFT JOIN ( SELECT gameID, COUNT(if(prepaid='Yes', 1, NULL)) payYes, COUNT(if(prepaid='No', 1, NULL)) payNo FROM ReservationsBuy GROUP BY gameID ) AS res ON res.gameID = rwl.gameID UNION SELECT IFNULL(rwl.gameID, res.gameID) AS gameID, rwl.quantity, res.payYes, res.payNo FROM RestockWishList rwl RIGHT JOIN ( SELECT gameID, COUNT(IF(prepaid='Yes', 1, NULL)) payYes, COUNT(IF(prepaid='No', 1, NULL)) payNo FROM ReservationsBuy GROUP BY gameId ) AS res ON res.gameID = rwl.gameID ) AS q ON g.gameID = q.gameID
Я думаю, может быть, вам нужен такой запрос - не полное внешнее соединение:
select q.id, q.name, q.reservations, ifnull(q2.wishcount, 0) wishcount, q.payYes, q.payNo from ( select g.*, count(rb.gameid) reservations, count(case when prepaid = 'Yes' then 1 end) payYes, count(case when prepaid = 'No' then 1 end) payNo from games g left join reservationsbuy rb on g.id = rb.gameid group by g.id ) q left join ( select g.id, sum(quantity) wishcount from games g left join restockwishlist rwl on g.id = rwl.gameid group by g.id ) q2 on q.id = q2.id;
Здесь есть демонстрационная версия, но суть ее в том, что для каждой игры в игровом столе она даст вам общее количество оговорок, количество из списка пожеланий, и мы используем условный счетчик, чтобы обеспечить количество
prepaid = yes
, илиprepaid = no
. По сути, это просто объединение двух небольших запросов к общему gameid.Если вы хотите, чтобы это включало фильтрацию по дате и т. д., Вам может потребоваться быть немного более ясно о том, как вы хотите, чтобы результаты работали или отображались
Хорошо. Итак, мы теперь, что всегда существует запись в
game
таблице, верно?Затем начните свой
FROM
с этой таблицы, тогда вам просто нужно сделатьLEFT JOIN
для каждой таблицы следующим образом:Как вы можете сказать, единственными изменениями были: начнитеSELECT rwl.* , g.gameName , coalesce(payYes, 0) payYes , coalesce(payNo, 0) payNo FROM Games AS g LEFT JOIN RestockWishList AS rwl ON rwl.gameID = g.gameID LEFT JOIN ( SELECT gameID , COUNT(if(prepaid='Yes', 1, NULL)) payYes , COUNT(if(prepaid='No', 1, NULL)) payNo FROM ReservationsBuy GROUP BY gameID) AS res ON res.gameID = g.gameID ;
FROM
сGames
таблицы и используйтеLEFT JOIN
, также удалите условие изWHERE
и поместите его вLEFT JOIN