使用联合

时间:2018-11-28 23:04:39

标签: mysql sql ruby-on-rails

在mysql中,我在尝试获取正确的数据时遇到问题。我想我必须使用union来从两个表中获取所有结果,但不确定如何执行。

表的说明:

  • 订单包含订单号
  • 员工持有员工
  • 区域保存区域名称
  • 实际时间具有区域ID,订单ID和交付所需的小时数
  • 交付详细信息包含员工ID,员工交付的区域以及交付所需的时间

订购

| id | number |
|----|--------|
| 1  |  0001  |

员工

| id | name |
|----|------|
| 1  | Jon  |

区域

| id | name  |
|----|-------|
| 1  | ZoneA |
| 2  | ZoneB |

actual_times

| id | zone_id | eta_hours | order_id |
|----|---------|-----------|----------|
| 1  |    1    |     5     |     1    |
| 2  |    2    |     4     |     1    |

deliver_details

| id | order_id | employee_id | zone_id | hours |
|----|----------|-------------|---------|-------|
| 1  |     1    |      1      |    1    |   3   |
| 2  |     1    |      1      |    1    |   1   |

我希望得到的是区域名称,交付时间和员工交付时间的总和。如果员工没有到达该区域,则显示0

预期产量

| zone_name | hours | eta_hours | employee_name |
|-----------|-------|-----------|---------------|
|   ZoneA   |   4   |     5     |      Jon      |
|   ZoneB   |   0   |     4     |      Jon      |

我尝试在实际时间全部建立一个工会,但我做得不好。

这是我尝试过的方法(请注意,这只是为了获得带有交付时间和实际时间的正确区域)。

SELECT deliver_details.zone_id, actual_times.zone_id, zones.zone_name FROM actual_times
RIGHT JOIN deliver_details ON actual_times.order_id = deliver_details.order_id
INNER JOIN zones ON zones.id = deliver_details.zone_id
WHERE deliver_details.order_id = 1
GROUP BY deliver_details.zone_id
UNION ALL
SELECT deliver_details.zone_id, actual_times.zone_id, zones.zone_name FROM actual_times
LEFT JOIN deliver_details ON actual_times.order_id = deliver_details.order_id
INNER JOIN zones ON zones.id = actual_times.zone_id 
WHERE actual_times.order_id = 1
group by actual_times.zone_id

我几乎正在尝试通过一个查询来获取所有这些信息。有办法吗?

请注意,这是我遇到的更复杂问题的简化。如果您需要更多说明或没有任何意义,请告诉我。

3 个答案:

答案 0 :(得分:1)

无需使用UNION

从表employees开始,然后与zonesactual_times交叉加入以获得简单的笛卡尔积。然后在deliver_details中搜索每个员工在每个区域执行的交货;为此使用LEFT JOIN。如果临时人员没有在给定区域上投放,请使用COALESCE返回0而不是NULL

查询:

select
    z.name,
    coalesce(sum(dd.hours), 0),
    at.eta_hours,
    e.name
from 
    employees e
    cross join zones z
    inner join actual_times at on at.zone_id = z.id
    left join deliver_details dd on dd.employee_id = e.id and dd.id = at.zone_id
group by 
    z.name, at.eta_hours, e.name

答案 1 :(得分:1)

我想出了一个针对GMB的类似解决方案,但是使用UNION来获取0小时的行...:

SELECT z.name, sum(dd.hours), at.eta_hours, e.name 
FROM zones z JOIN deliver_details dd ON z.id = dd.zone_id
JOIN actual_times at ON z.id = at.zone_id
JOIN employees e ON dd.employee_id = e.id
GROUP BY z.name, at.eta_hours, e.name

UNION

SELECT z.name, 0, at.eta_hours, e.name
FROM zones z JOIN actual_times at ON z.id = at.zone_id,
employees e
WHERE e.id NOT IN (SELECT employee_id FROM deliver_details WHERE zone_id = z.id)

答案 2 :(得分:0)

如果每个区域只有一名员工,则以下查询将为您工作:

SELECT   Z.name  AS zone_name
        ,DT.hours_total
        ,ACT.eta_hours_total
        ,E.name AS employee_name
FROM zones Z
INNER JOIN (SELECT  zone_id
                    , SUM(eta_hours) eta_hours_total 
            FROM actual_times 
            GROUP BY zone_id) ACT ON Z.zone_id = ACT.zone_id
INNER JOIN (SELECT  zone_id
                    , employee_id
                    , SUM(hours) hours_total 
            FROM deliver_details 
            GROUP BY zone_id, employee_id) DT ON Z.zone_id = DT.zone_id
INNER JOIN employees E ON DT.employee_id = E.employee_id