SQL查询:子查询上的自联接需要创建一个单独的(非临时)表吗?

时间:2009-09-29 16:15:43

标签: sql mysql

我正在研究什么对我来说是一个复杂的查询,我已经设法获得了我需要的信息,但似乎被迫创建一个表来完成它。我正在使用MySQL,所以我不能使用WITH,我不能使用视图,因为我的SELECTFROM子句中包含子查询,我无法使用临时表因为我需要自我加入。我错过了什么吗?

背景:

  • 一个reservation可以有一个或多个reservation_detailreservation_id上的外键密码
  • reservation_detail有一个quantity和一个ticket_typeticket_type上的外键关键字

这是我当前解决方案的第一部分:

CREATE TABLE 
    tmp
SELECT 
    t.reservation_id, 
    t.ticket_type, 
    COALESCE(rd.quantity,0) AS qty
FROM (
    SELECT *
    FROM 
        (ticket_type tt, reservation r)
    ) t
LEFT JOIN 
    reservation_detail rd 
    ON 
        t.reservation_id = rd.reservation_id 
    AND 
        t.ticket_type = rd.ticket_type;

这给了我一个如下所示的表格,对于reservation_idticket_type的每个组合,我有一个qty

+----------------+-------------+------+
| reservation_id | ticket_type | qty  |
+----------------+-------------+------+
|              1 | ADULT       |    2 | 
|              1 | CHILD       |    2 | 
|              1 | INFANT      |    0 | 
|              2 | ADULT       |    1 | 
|              2 | CHILD       |    0 | 
|              2 | INFANT      |    0 | 
|              3 | ADULT       |    1 | 
|              3 | CHILD       |    0 | 
|              3 | INFANT      |    0 | 
+----------------+-------------+------+

现在我可以自己加入这张桌子三次以获得我真正想要的东西......

SELECT 
    t1.reservation_id, 
    t1.qty AS num_adults, 
    t2.qty AS num_children, 
    t3.qty AS num_infants
FROM 
    tmp t1
LEFT JOIN 
    tmp t2 
    ON 
        t1.reservation_id = t2.reservation_id
LEFT JOIN 
    tmp t3 
    ON 
        t2.reservation_id = t3.reservation_id
WHERE 
    t1.ticket_type = 'ADULT'
AND 
    t2.ticket_type = 'CHILD'
AND 
    t3.ticket_type = 'INFANT';

...每个预订的一行显示三种故障单类型中的每一种的数量。

+----------------+------------+--------------+-------------+
| reservation_id | num_adults | num_children | num_infants |
+----------------+------------+--------------+-------------+
|              1 |          2 |            2 |           0 | 
|              2 |          1 |            0 |           0 | 
|              3 |          1 |            0 |           0 | 
+----------------+------------+--------------+-------------+

我希望这是足够的信息。如果不是,请发表评论。

4 个答案:

答案 0 :(得分:1)

如果你想坚持你的第一个查询,你可以将其分为第二个:

SELECT reservation_id,
       SUM(CASE WHEN ticket_type='ADULT' THEN qty ELSE 0 END) AS adults,
       SUM(CASE WHEN ticket_type='CHILD' THEN qty ELSE 0 END) AS children,
       SUM(CASE WHEN ticket_type='INFANT' THEN qty ELSE 0 END) AS infants,
FROM tmp
GROUP BY reservation_id;

但是,我想知道你的架构。您正在存储qty,即计算值。您是否考虑过为每个故障单实例添加一行。如果你这样做,那么就不需要tmp表,尽管你可以像上面那样进行数据透视。

答案 1 :(得分:1)

如果您的查询仅考虑以下3种类型:ADULT,CHILD,INFANT;您不必使用table ticket_type。

SELECT 
    r.reservation_id, 
    COALESCE(rd_adult.quantity,0) AS num_adults, 
    COALESCE(rd_child.quantity,0) AS num_children, 
    COALESCE(rd_infant.quantity,0) AS num_infants
FROM 
    reservation r
LEFT JOIN 
    reservation_detail rd_adult 
    ON r.reservation_id = rd_adult.reservation_id
       and rd_adult.ticket_type = 'ADULT'
LEFT JOIN 
    reservation_detail rd_child 
    ON r.reservation_id = rd_child.reservation_id
       and rd_child.ticket_type = 'CHILD'
LEFT JOIN 
    reservation_detail rd_infant
    ON r.reservation_id = rd_infant.reservation_id
       and rd_infant.ticket_type = 'INFANT'

答案 2 :(得分:1)

由于表reservation_detail包含您需要的所有字段,因此您无需连接其他表并创建临时表。

试试这个:

SELECT distinct
    t.reservation_id, 
    COALESCE(t1.qty,0) AS num_adults, 
    COALESCE(t2.qty,0) AS num_children, 
    COALESCE(t3.qty,0) AS num_infants
FROM reservation t
LEFT JOIN reservation_detail t1 ON t.reservation_id = t1.reservation_id AND t1.ticket_type = 'ADULT'
LEFT JOIN reservation_detail t2 ON t.reservation_id = t2.reservation_id AND t2.ticket_type = 'CHILD'
LEFT JOIN reservation_detail t3 ON t.reservation_id = t3.reservation_id AND t3.ticket_type = 'INFANT';

答案 3 :(得分:0)

一个简单的GROUP BY就可以了:

SELECT t.reservation_id,
       SUM(CASE
              WHEN ticket_type = 'ADULT' THEN
               COALESCE(rd.quantity, 0)
              ELSE
               0
           END) num_adults,
       SUM(CASE
              WHEN ticket_type = 'CHILD' THEN
               COALESCE(rd.quantity, 0)
              ELSE
               0
           END) num_children,
       SUM(CASE
              WHEN ticket_type = 'INFANT' THEN
               COALESCE(rd.quantity, 0)
              ELSE
               0
           END) num_infants
  FROM (SELECT * FROM (ticket_type tt, reservation r)) t
  LEFT JOIN reservation_detail rd ON t.reservation_id = rd.reservation_id
                                 AND t.ticket_type = rd.ticket_type
 GROUP BY t.reservation_id