【发布时间】:2019-01-27 16:37:01
【问题描述】:
背景
Oracle 数据库版本:
SELECT * FROM v$version
WHERE banner LIKE 'Oracle%';
-- OUTPUT
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
目标
我正在尝试将 三个表 与 两个条件 进行外部连接,以便缺失值仅显示为 NULL。请参阅下面的详细信息。
表格
以下表格是抽象的,所以请不要试图改进数据模型本身。
测量
主键 = ID
| ID | MEAS_NAME |
|------|-----------------|
| 1000 | "Measurement 1" |
MEASUREMENT_AREA
主键 = (ID, NAME)
外键ID = MEASUREMENT.ID
| ID | NAME | AREA |
|------|-----------|------|
| 1000 | "Point 1" | 10 |
| 1000 | "Point 2" | 20 |
MEASUREMENT_VOLUME
主键 = (ID, NAME)
外键ID = MEASUREMENT.ID
| ID | NAME | VOLUME |
|------|-----------|--------|
| 1000 | "Point 1" | 100 |
| 1000 | "Point 3" | 200 |
预期结果
我想要的是以下输出:
| ID | MEAS_NAME | NAME | AREA | VOLUME |
|------|-----------------|-----------|------|--------|
| 1000 | "Measurement 1" | "Point 1" | 10 | 100 |
| 1000 | "Measurement 1" | "Point 2" | 20 | NULL |
| 1000 | "Measurement 1" | "Point 3" | NULL | 200 |
这意味着,如果对于特定的 MEASUREMENT.ID 和特定的 NAME 在 AREA 和 VOLUME 中都有数据,则将它们放在同一行中。否则,只需将 AREA 或 VOLUME 字段留空即可。
查询 1
我想出了以下 SQL 语句,它不起作用,它丢弃了来自 MEASUREMENT_VOLUME 的结果:
SELECT meas.ID AS "ID",
meas.MEAS_NAME AS "MEAS_NAME",
COALESCE (area.NAME, vol.NAME) as "NAME",
area.AREA, vol.VOLUME
FROM MEASUREMENT meas
LEFT JOIN MEASUREMENT_AREA area
ON meas.ID = area.ID
FULL JOIN MEASUREMENT_VOLUME vol
ON meas.ID = vol.ID AND area.NAME = vol.NAME
WHERE meas.ID = 1000;
查询 2
如果我把MEASUREMENT放在最后,它可以工作,但查询非常慢:
SELECT meas.ID AS "ID",
meas.MEAS_NAME AS "MEAS_NAME",
COALESCE (area.NAME, vol.NAME) as "NAME",
area.AREA, vol.VOLUME
FROM MEASUREMENT_AREA area
FULL JOIN MEASUREMENT_VOLUME vol
ON area.ID = vol.ID AND area.NAME = vol.NAME
JOIN MEASUREMENT meas
ON meas.ID = vol.ID OR meas.ID = area.ID
WHERE meas.ID = 1000;
问题
- 为什么查询 1 不起作用?
- 为什么查询 2 有效?
- 实现输出的最有效方法是什么?
非常感谢您的帮助,我不是 SQL 专家。
其他信息
-
MEASUREMENT中的一行仅包含一次测量的元数据 - 一次测量可以包含数百个测量点,这些点由它们的 `NAME 来区分。
-
MEASUREMENT_AREA和MEASUREMENT_VOLUME比MEASUREMENT大得多,每个都包含超过 1000 万行
【问题讨论】:
-
你能试试这个查询吗?
SELECT meas.ID, meas.MEAS_NAME, area.NAME, area.AREA, vol.VOLUME FROM MEASUREMENT meas LEFT JOIN MEASUREMENT_AREA area ON meas.ID = area.ID LEFT JOIN MEASUREMENT_VOLUME vol ON meas.ID = vol.ID AND area.NAME = vol.NAME WHERE meas.ID = 1000;您能否解释一下为什么您的第一个查询不起作用?输出是什么?一些建议: - 如果列已经以相同的方式命名,则无需命名列 - 您应该将键和索引放在用于在表之间查找数据的列上以优化搜索。 -
LEFT JOIN是我尝试的第一件事,但它保证不起作用。它遗漏了任何具有NAME的值,该值仅存在于MEASURMENT_VOLUME中。在我的“预期结果”中,第三行将丢失,MEASURMENT_VOLUME中没有Point 3。不幸的是,查询 1 也会发生这种情况。我不知道为什么,我希望FULL JOIN也会接受与条件ON meas.ID = vol.ID OR meas.ID = area.ID不匹配的值。