MYSQL 从三个表中获取数据

MYSQL getting data from three tables

我正在尝试查找 2020 年 2 月所有饮酒者的饮酒者和在饮料上花费的总金额。我还需要包括在此期间未点酒的饮酒者。

这是三个表格:

CREATE TABLE DRINKERS ( /* All drinkers */
DRINKER VARCHAR(30) NOT NULL,
    CONSTRAINT DRINKERS_PKEY PRIMARY KEY (DRINKER)); 

CREATE TABLE SERVES(    /* Pubs serve drinks */
PUB         VARCHAR(30) NOT NULL,   /* Pub name */
DRINK       VARCHAR(30) NOT NULL,   /* Drink name   */
PRICE       DECIMAL(5,2)    NOT NULL,   /* Drink price  */
    CONSTRAINT SERVES_PKEY PRIMARY KEY(PUB, DRINK),
        CONSTRAINT SERVES_FKEY1 FOREIGN KEY(PUB) 
        REFERENCES LOCATED(PUB),
    CONSTRAINT SERVES_FKEY2 FOREIGN KEY(DRINK)
        REFERENCES ALLDRINKS(DRINK)  );

CREATE TABLE ORDERS(    /* Drinkers visit pubs and consumes drinks */
DRINKER     VARCHAR(30) NOT NULL,   /* Drinker name */
PUB         VARCHAR(30) NOT NULL,   /* Pub name */
ODATE       DATE        NOT NULL,   /* Order date   */
DRINK       VARCHAR(30) NOT NULL,   /* Drink name   */
DRINK_NO    DECIMAL(2)  NOT NULL,   /* A sequence number of a drink */
    CONSTRAINT ORDERS_PKEY PRIMARY KEY(DRINKER, PUB, ODATE, DRINK, DRINK_NO),
    CONSTRAINT ORDERS_FKEY1 FOREIGN KEY(PUB, DRINK) REFERENCES SERVES(PUB, DRINK),
    CONSTRAINT ORDERS_FKEY2 FOREIGN KEY(DRINKER) REFERENCES DRINKERS(DRINKER)   );

到目前为止,这是我的声明:

SELECT ORDERS.DRINKER, SUM(SERVES.PRICE)
FROM ORDERS
LEFT JOIN SERVES ON ORDERS.DRINKER = SERVES.PRICE
GROUP BY ORDERS.DRINKER;

我是SQL的新手,我知道有很多错误。任何帮助将不胜感激!

您可以使用联接作为

SELECT D.DRINKER , SUM(ifnull(S.PRICE,0))
FROM DRINKERS D
LEFT JOIN ORDERS O ON D.DRINKER  = O.DRINKER    
INNER JOIN  SERVES S ON O.PDB = S.PUB
    AND S.DRINK = O.DRINK
GROUP BY D.DRINKER;

如果你只需要 2 月

SELECT D.DRINKER , SUM(ifnull(S.PRICE,0))
FROM DRINKERS D
LEFT JOIN ORDERS O ON D.DRINKER  = O.DRINKER    
    AND year(O.ODATE) = 2020 AND month(O.ODATE) = 2
INNER JOIN  SERVES S ON O.PDB = S.PUB
    AND S.DRINK = O.DRINK

GROUP BY D.DRINKER;

您需要使用简单的 inner joinleft join 以及 month()year() 函数。无论他们是否点了酒,您都会得到所有饮酒者的结果。因此,您将在 2 月份获得非饮酒者的结果。

select a.drinker,sum(c.price)
from drinkers a left join orders b on a.drinker = b.drinker
join serves c on b.pub = c.pub and b.drink = c.drink
where month(b.odate) = 'February' and year(b.odate) = 2020
group by a.drinker;

由于您想要全部 DRINKERS,无论他们是否订购,您都希望从 table 开始。然后LEFT JOINORDERStable,去拿那些有订单的人。

这是一个猜测,但从 DRINK_NO 列看来,每份饮品在 ORDERS 中有一行。由于您只需要此查询的总饮料,我建议使用 table 的子查询,而不是加入完整的 table。由于此 table 包含 ODATE 数据,您可以在此处的子查询中过滤结果。您也可以在外部查询中使用 WHERE 子句进行过滤,但在此处执行此操作会更有效率。

SELECT
  DRINKER,
  PUB,
  DRINK,
  COUNT(DRINK_NO) AS QUANTITY 
FROM ORDERS
GROUP BY
  DRINKER,
  PUB,
  DRINK
WHERE
  MONTH(ODATE) = 2 AND YEAR(ODATE) = 2020

最后,INNER JOIN 您对 SERVES 的子查询以获得定价信息。

完整构造的查询应该接近于此:

SELECT
  d.DRINKER,
  SUM(o.PRICE * o.QUANTITY) AS TotalSpent
FROM
  DRINKERS AS d
  LEFT JOIN
    (
      SELECT
        DRINKER,
        PUB,
        DRINK,
        COUNT(DRINK_NO) AS QUANTITY
      FROM ORDERS
      GROUP BY
        DRINKER,
        PUB,
        DRINK
      WHERE
        MONTH(ODATE) = 2 AND YEAR(ODATE) = 2020
    ) AS o
    ON o.DRINKER = d.DRINKER
  INNER JOIN SERVES AS s
    ON o.PUB = s.PUB
    AND o.DRINK = s.DRINK
GROUP BY
  d.DRINKER;

有多种查询模式可以return 满足规范的结果。这是一个例子:

SELECT d.drinker               AS drinker
     , IFNULL(SUM(s.price),0)  AS tot_feb_prices
  FROM `DRINKERS` d
    -- 
  LEFT
  JOIN `ORDERS` o
    ON o.drinker  = p.drinker
   AND o.odate   >= '2020-02-01' 
   AND o.odate    < '2020-02-01' + INTERVAL 1 MONTH
    --
  LEFT
  JOIN `SERVES` s
    ON s.pub   = o.pub
   AND s.drink = o.drink
    --
 GROUP
    BY d.drinker
 ORDER
    BY d.drinker

另一种方法是在 select 列表中使用相关子查询(子查询必须 return 标量...只有一列,最多一行。)

SELECT d.drinker
    --
     , ( SELECT IFNULL(SUM(s.price),0)
           FROM `ORDERS` o
           JOIN `SERVES` s
             ON s.pub   = o.pub
            AND s.drink = o.drink
          WHERE o.drinker  = p.drinker
            AND o.odate   >= '2020-02-01' 
            AND o.odate    < '2020-02-01' + INTERVAL 1 MONTH
       ) AS tot_feb_prices
    --
  FROM `DRINKERS` d
 ORDER BY d.drinker