5

我正在开发一个游戏库存管理系统,并希望在一个表中显示所有者的补货愿望清单和每个游戏的客户购买预订计数。我写了一个我认为有效的查询,但后来我注意到它实际上忽略了任何有预订但最初不在补货愿望清单中的游戏。查询如下:

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、数量、gameName、payYes、payNo

1, 4, 四季城堡, 0, 0

2, 2, 几英亩的雪, 0, 0

18, 4, 阿罕布拉, 0, 0

54, 2, 大博格, 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、数量、gameID、payYes、payNo

1、4、空、空、空

2、2、空、空、空

18、4、空、空、空

54, 2, 54, 2, 0

空, 空, 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

预订购买:

gameID, customerEmail, customerName, dateReserved, datePurchased, dateClaimed, prepaid

30,wonder@woman.com,戴安娜,2015-04-24 14:46:05,NULL,NULL,是的

54, boggie@marsh.com, boggie, 2015-04-24 14:43:32, NULL, NULL, 是

54, manny@second.com, manny, 2015-04-27 19:48:22, NULL, NULL, 是

43, old@mom.com, 奶奶, 2015-04-23 22:32:03, NULL, NULL, 没有

预期输出:gameID、数量、gameName、payYes、payNo

1, 4, 四季城堡, 0, 0

2, 2, 几英亩的雪, 0, 0

18, 4, 阿罕布拉, 0, 0

30, 0, 阿卡姆恐怖, 1, 0

43, 0, 香蕉图, 0, 1

54, 2, 大博格, 2, 0

(游戏表对于这个查询不是特别重要。唯一相关的是 ReservationsBuy 和 RestockWishList 都通过游戏 ID 连接到游戏)

4

3 回答 3

1

我想也许你想要这样的查询 - 而不是完整的外部连接:

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. 实际上,它只是将共享游戏 ID 上的两个小查询连接在一起。

如果您希望这包括按日期过滤等,您可能需要更明确地说明您希望结果如何工作或显示

于 2015-04-28T03:28:10.470 回答
0

您使用 a 走在正确的轨道上FULL OUTER JOIN,只是实现不正确。

MySQL 中的 AFULL OUTER JOIN可以被认为是UNIONaLEFT JOIN和 a 的RIGHT JOIN。在您的查询中,您试图通过将RIGHT JOIN逻辑的一部分视为两个表的逆来近似这一点LEFT JOIN,但您的第一部分不起作用,因为它不是与GROUP BY您的第一个具有相同序列的子选择LEFT JOIN

最简单的做法是获取您的第一个LEFT JOIN查询节,将其复制到第二个节,并替换LEFT JOINRIGHT 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

SQL 小提琴结果

于 2015-04-28T03:27:59.507 回答
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,同时删除条件并将其放入GamesLEFT JOINWHERELEFT JOIN

于 2015-04-28T03:51:26.877 回答