db2 SQL难题-为所有二进制特征插入缺失的行

qgelzfjb  于 2023-11-18  发布在  DB2
关注(0)|答案(1)|浏览(101)

我试图解决一个难题,但我无法理解它。解决方案最好是在DB2中,但其他SQL变体也可以接受。
假设我们有这个表列出所有者和他们的汽车(每个所有者可以有多辆汽车):
car_owners:
| 所有者|使|模型|地址|电话|
| --|--|--|--|--|
| 1 |丰田|花冠|第一街| 11111 |
| 1 |福特|野马|第一街| 11111 |
| 2 |丰田|花冠|二街| 22222 |
| 2 |奥迪|A7|二街| 22222 |
| 2 |保时捷| 911 |二街| 22222 |
| 3 |丰田|普锐斯|三街| 33333 |
然后我们有这个表与汽车功能和他们的代码:
car_features_codes:
| 代码|特征|
| --|--|
| 1 |轿车|
| 2 |不是轿车|
| 3 |ABS|
| 4 |无ABS|
| 5 |自动|
| 6 |不是自动|
| 7 |汽油|
| 8 |没有汽油|
请注意,该表有4个特征,每个特征都有一个“是”或“否”代码,因此共有8个代码,这些代码是连续的数字。
为了更好的可视化,上表可以这样呈现:
| 特征|是的|没有|
| --|--|--|
| 轿车| 1 | 2 |
| ABS| 3 | 4 |
| 自动| 5 | 6 |
| 汽油| 7 | 8 |
最后,我们有这个汽车功能表:
car_features:
| 所有者|使|模型|特征|
| --|--|--|--|
| 1 |福特|野马| 2 |
| 1 |福特|野马| 3 |
| 1 |福特|野马| 6 |
| 1 |福特|野马| 7 |
| 3 |丰田|普锐斯| 1 |
| 3 |丰田|普锐斯| 5 |
| 2 |保时捷| 911 | 2 |
| 2 |保时捷| 911 | 3 |
| 2 |保时捷| 911 | 5 |
| 2 |保时捷| 911 | 7 |
请注意,所有4个功能,野马和保时捷都有,普锐斯只有2个,其他汽车没有任何。
现在,挑战是用第一个表中所有汽车的所有特征填充最后一个表,使用第二个表中的“负”代码作为默认值。例如:如果一辆汽车没有代码7或8,则填写8(没有汽油)。如果缺少5或6,则填写6。如果缺少1或2,则填写2。等等。
最后的“car_features”表应该总共有X*4行(X是第一个表的汽车的数量,每个汽车都有所有4个特征),保留表中已经存在的行。
最后的表格应该是这样的:
| 所有者|使|模型|特征|
| --|--|--|--|
| 1 |福特|野马| 2 |
| 1 |福特|野马| 3 |
| 1 |福特|野马| 6 |
| 1 |福特|野马| 7 |
| 3 |丰田|普锐斯| 1 |
| 3 |丰田|普锐斯| 5 |
| 2 |保时捷| 911 | 2 |
| 2 |保时捷| 911 | 3 |
| 2 |保时捷| 911 | 5 |
| 2 |保时捷| 911 | 7 |
| 3 |丰田|普锐斯| 4 |
| 3 |丰田|普锐斯| 8 |
| 1 |丰田|花冠| 2 |
| 1 |丰田|花冠| 4 |
| 1 |丰田|花冠| 6 |
| 1 |丰田|花冠| 8 |
| 2 |丰田|花冠| 2 |
| 2 |丰田|花冠| 4 |
| 2 |丰田|花冠| 6 |
| 2 |丰田|花冠| 8 |
| 2 |奥迪|A7| 2 |
| 2 |奥迪|A7| 4 |
| 2 |奥迪|A7| 6 |
| 2 |奥迪|A7| 8 |
注意事项:前10行与之前相同。然后我完成了所有汽车缺少的其他功能,默认情况下每个都有“否定”选项,例如,如果没有ABS指示灯(没有“是”或“否”代码),那么我填充“无ABS”(“否”代码),并对所有其他功能重复。
我已经尝试了使用SQL语句的多个查询,但不知道如何做到这一点。

zzlelutf

zzlelutf1#

要生成不存在的行,可以使用2个集合的CROSS JOIN(笛卡尔积)。这里我们需要将现有车主交叉连接到负特征。这确保了所有车主和所有负代码都存在于结果中。
由于存在一个正特征和一个匹配的负特征,我们需要确保如果当前表中存在一对中的任何一个,我们不会否定现有的正特征,反之亦然。因此,我们将该结果与现有的车主信息连接起来,以识别任何缺失的行,但也要使用not exists检查数据是否已经存在:

INSERT INTO car_features (Owner, Make, Model, Feature)
WITH all_combinations AS (
    SELECT o.Owner, o.Make, o.Model, c.Code as Feature
    FROM car_owners o
    CROSS JOIN car_features_codes c
    WHERE c.Code IN (2,4,6,8)
),
existing_features AS (
    SELECT o.Owner, o.Make, o.Model, f.Feature, CASE WHEN f.Feature % 2 = 0 THEN f.Feature - 1 ELSE f.Feature + 1 END as OppositeFeature
    FROM car_owners o
    JOIN car_features f ON o.Owner = f.Owner AND o.Make = f.Make AND o.Model = f.Model
)
SELECT ac.Owner, ac.Make, ac.Model, ac.Feature
FROM all_combinations ac
WHERE NOT EXISTS (
    SELECT 1 
    FROM existing_features ef 
    WHERE ac.Owner = ef.Owner
    AND ac.Make = ef.Make 
    AND ac.Model = ef.Model
    AND (ac.Feature = ef.Feature OR ac.Feature = ef.OppositeFeature)
    )

字符串
插图后的行:

+-------+---------+---------+---------+
| OWNER |  MAKE   |  MODEL  | FEATURE |
+-------+---------+---------+---------+
|     1 | Ford    | Mustang |       2 |
|     1 | Ford    | Mustang |       3 |
|     1 | Ford    | Mustang |       6 |
|     1 | Ford    | Mustang |       7 |
|     1 | Toyota  | Corolla |       2 |
|     1 | Toyota  | Corolla |       4 |
|     1 | Toyota  | Corolla |       6 |
|     1 | Toyota  | Corolla |       8 |
|     2 | Audi    | A7      |       2 |
|     2 | Audi    | A7      |       4 |
|     2 | Audi    | A7      |       6 |
|     2 | Audi    | A7      |       8 |
|     2 | Porsche | 911     |       2 |
|     2 | Porsche | 911     |       3 |
|     2 | Porsche | 911     |       5 |
|     2 | Porsche | 911     |       7 |
|     2 | Toyota  | Corolla |       2 |
|     2 | Toyota  | Corolla |       4 |
|     2 | Toyota  | Corolla |       6 |
|     2 | Toyota  | Corolla |       8 |
|     3 | Toyota  | Prius   |       1 |
|     3 | Toyota  | Prius   |       4 |
|     3 | Toyota  | Prius   |       5 |
|     3 | Toyota  | Prius   |       8 |
+-------+---------+---------+---------+


参见DB2 fiddle

nb此解决方案假设8个代码是成对的,奇数是正数,“+1”是匹配的负数。如果不是这样,那么您可能需要提供每个基本特征的正负“Map表”。

相关问题