我正在开发一个游戏库存管理系统,并希望在一张表中显示所有者的进货希望清单和每个游戏的客户购买预订计数。我写了一个我认为有效的查询,但后来我注意到它实际上省略了任何有预订的游戏,但最初都没有在补货愿望清单中。查询如下:
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;
查询结果: 游戏ID, 数量, gameName, payYes, payNo
1, 4, 适合所有季节的城堡, 0, 0
2, 2, 几英亩的雪, 0, 0
18, 4, 阿罕布拉, 0, 0
54, 2, Big Boggle, 2, 0
显然这个问题的解决方案是使用FULL OUTER JOIN而不是LEFT JOIN,但是MySQL并不支持该功能。我花了几个小时试图将它转换为UNION结构,但不能让它正常工作。这就像我得到的那样接近:
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,quantity,gameID,payYes,payNo
1,4,NULL,NULL,NULL
2,2,NULL,NULL,NULL
18,4,NULL,NULL,NULL
54,2,52,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:
游戏ID, 量
1, 4
2, 2
18, 4
54, 2
ReservationsBuy:
游戏ID, customerEmail, 顾客姓名, dateReserved, 购买日期, dateClaimed, 预付费
30, wonder@woman.com, 戴安娜, 2015-04-24 14:46:05, 空值, 空值, 是
54, boggie@marsh.com, 博吉, 2015-04-24 14:43:32, 空值, 空值, 是
54, manny@second.com, 曼尼, 2015-04-27 19:48:22, 空值, 空值, 是
43, old@mom.com, 奶奶, 2015-04-23 22:32:03, 空值, 空值, 否
预期产量: gameID,quantity,gameName,payYes,payNo
1,4,所有季节的城堡,0,0
2,2,几英亩雪,0,0
18,4,Alhambra,0,0
30,0,Arkham Horror,1,0
43,0,Bananagrams,0,1
54,2,Big Boggle,2,0
(游戏表对此查询不是特别重要。只有相关性是ReservationsBuy和RestockWishList都通过gameID连接到游戏)
答案 0 :(得分:1)
我想也许您想要这样的查询 - 不是完整的外部联接:
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
有demo here,但它的要点是,对于游戏桌中的每个游戏,它会给你预订总数,愿望清单中的数量,我们使用条件计数以提供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
的计数。实际上它只是在共享的gameid上加入两个小查询。
如果您希望这包括按日期等过滤,您可能需要更明确地说明您希望结果如何工作,或者显示
答案 1 :(得分:0)
您使用FULL OUTER JOIN
进入了正确的轨道,您只是执行不正确。
MySQL中的FULL OUTER JOIN
可以被认为是UNION
和LEFT JOIN
的{{1}}。在您的查询中,您试图通过将逻辑的RIGHT JOIN
部分视为两个表格的反RIGHT JOIN
来尝试近似,但您的第一部分不起作用,因为它&& #39;不是与您的第一个LEFT JOIN
具有相同GROUP BY
序列的子选择。
最简单的方法是将第一个LEFT JOIN
查询节简单地复制到第二节,然后将LEFT JOIN
替换为LEFT JOIN
,然后将结果链接到您的游戏表,像这样:
RIGHT JOIN
答案 2 :(得分:0)
确定。所以我们现在总是在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