我有一张维护要求表和要执行的相关每月频率
维护
+----------+------+
| maint_id | freq |
+----------+------+
| 1 | 6 |
| 2 | 12 |
| 3 | 24 |
| 4 | 3 |
+----------+------+
我还有一张设备表,其中包含有关其制造商,型号,设备类型和构造的数据。
装备
+----------+--------+--------+--------+---------+
| equip_id | mfg_id | mod_id | dev_id | bldg_id |
+----------+--------+--------+--------+---------+
| 1 | 1 | 1 | 3 | 1 |
| 2 | 1 | 2 | 3 | 1 |
| 3 | 2 | 3 | 1 | 2 |
| 4 | 2 | 3 | 1 | 3 |
+----------+--------+--------+--------+---------+
我正在尝试使每个维护要求与其相关设备匹配。每个要求在其适用范围内都适用于特定的制造商,型号,设备,设施或它们的任意组合。 我创建了一个表来管理这些关系,如下所示:
maint_equip
+----------------+----------+--------+--------+--------+---------+
| maint_equip_id | maint_id | mfg_id | mod_id | dev_id | bldg_id |
+----------------+----------+--------+--------+--------+---------+
| 1 | 1 | NULL | NULL | 1 | NULL |
| 2 | 2 | 2 | NULL | NULL | 2 |
| 3 | 3 | NULL | NULL | NULL | 1 |
| 4 | 3 | NULL | NULL | NULL | 3 |
| 5 | 4 | 1 | NULL | 3 | 1 |
+----------------+----------+--------+--------+--------+---------+
根据上表,要求1仅适用于设备类型为“ 1”的任何设备。 要求2适用于制造商为“ 2”且建筑物为“ 2”的所有设备。 要求3将适用于所有建筑物为“ 1”或建筑物为“ 3”的设备 要求4适用于所有mfg_id为“ 1”且dev_id为“ 3”且建筑物为“ 1”的设备。
我正在尝试编写一个查询,以便根据maint_equip中定义的关系为我提供所有设备ID和所有相关频率要求的列表。我遇到的问题是处理多个联接。我已经尝试过:
SELECT equip.equip_id, maint.freq
FROM equip INNER JOIN
maint_equip ON equip.mfg_id = maint_equip.mfg_id
OR equip.mod_id = maint_equip.mod_id
OR equip.dev_id = maint_equip.dev_id
OR equip.bldg_id = maint_equip.bldg_id INNER JOIN
maint ON maint_equip.maint_id = maint.maint_id
但是使用OR分隔多个联接意味着它不考虑每一行的AND偶然性。例如,maint_id 2应该仅适用于equip_id 3,但同时返回ID 3和4。如果使用AND,则不会返回任何行,因为所有列都没有值。
是否可以通过这种方式联接表来完成此操作,或者是否有另一种结构化数据的方式?
答案 0 :(得分:1)
如果我没看错,当maint_equip
中与设备相关的ID为空时,这应该算作匹配项。仅当它不为null时,它才必须与equip
中的相应ID相匹配。也就是说,您要检查maint_equip
中的ID是否为空或等于equip
中的ID。
SELECT e.equip_id,
m.freq
FROM equip e
INNER JOIN maint_equip me
ON (me.mfg_id IS NULL
OR me.mfg_id = e.mfg_id)
AND (me.mod_id IS NULL
OR me.mod_id = e.mod_id)
AND (me.dev_id IS NULL
OR me.dev_id = e.dev_id)
AND (me.bldg_id IS NULL
OR me.bldg_id = e.bldg_id)
INNER JOIN maint m
ON m.maint_id = me.main_id;
答案 1 :(得分:0)
尝试一下:
( equip.mfg_id = maint_equip.mfg_id OR maint_equip.mfg_id is null )
AND( equip.mod_id = maint_equip.mod_id OR maint_equip.mod_id is null )
AND( equip.dev_id = maint_equip.dev_id OR maint_equip.dev_id is null )
AND( equip.bldg_id = maint_equip.bldg_id OR maint_equip.bldg_id is null )
答案 2 :(得分:0)
请注意,您的mod_id始终为null。否则,下面的查询将涉及您的所有情况。
SELECT maint_equip.maint_id, equip.equip_id, maint.freq
FROM equip INNER JOIN
maint_equip ON (
(equip.mfg_id = maint_equip.mfg_id AND
equip.dev_id = maint_equip.dev_id AND
equip.bldg_id = maint_equip.bldg_id
) OR
(equip.mfg_id = maint_equip.mfg_id AND
maint_equip.dev_id is NULL AND
equip.bldg_id = maint_equip.bldg_id
) OR
(maint_equip.mfg_id is NULL AND
equip.dev_id = maint_equip.dev_id AND
maint_equip.bldg_id is NULL
) OR
(maint_equip.mfg_id is NULL AND
maint_equip.dev_id is NULL AND
equip.bldg_id = maint_equip.bldg_id
) )
INNER JOIN
maint ON maint_equip.maint_id = maint.maint_id
;
答案 3 :(得分:0)
在我看来,您实际上要寻找的是具有最高匹配数量的维护时间表。您可以通过将SUM
与一系列CASE
表达式一起使用来获取匹配列的数量。
然后,您必须考虑多个具有相同次数的maint_id
值的关系。在下面的示例中,我选择使用维护频率作为决定性因素,与不那么频繁的维护相比,倾向于更频繁的维护。
具有数据设置的话机链接:https://rextester.com/VISR88105
ROW_NUMBER
子句中的ORDER BY
对结果进行排序以列匹配项的数目(螺母SUM/CASE
组合)降序排列,以首先获得最大的匹配项,然后是维护频率以升序排列以支持更频繁的维护。如果愿意,可以轻松地使用DESC
来解决。然后TOP (1) WITH TIES
将结果集限制为ROW_NUMBER
求值为1
的所有行。
代码:
SELECT TOP (1) WITH TIES
e.equip_id,
m.maint_id,
m.freq
FROM
#maint as m
JOIN
#maint_equip as me
ON
m.maint_id = me.maint_id
JOIN
#equip as e
ON
e.mfg_id = COALESCE(me.mfg_id, e.mfg_id)
AND
e.mod_id = COALESCE(me.mod_id, e.mod_id)
AND
e.dev_id = COALESCE(me.dev_id, e.dev_id)
AND
e.bldg_id = COALESCE(me.bldg_id, e.bldg_id)
GROUP BY
e.equip_id,
m.maint_id,
m.freq
ORDER BY
ROW_NUMBER() OVER (PARTITION BY e.equip_id ORDER BY (
SUM(
(CASE WHEN e.mfg_id = me.mfg_id THEN 1 ELSE 0 END) +
(CASE WHEN e.mod_id = me.mod_id THEN 1 ELSE 0 END) +
(CASE WHEN e.dev_id = me.dev_id THEN 1 ELSE 0 END) +
(CASE WHEN e.bldg_id = me.bldg_id THEN 1 ELSE 0 END)) ) DESC, m.freq )
结果:
+----------+----------+------+
| equip_id | maint_id | freq |
+----------+----------+------+
| 1 | 4 | 3 |
| 2 | 4 | 3 |
| 3 | 2 | 12 |
| 4 | 1 | 6 |
+----------+----------+------+