MySQL Lookup与更改查找列的最近或精确匹配值

时间:2018-03-14 00:51:22

标签: mysql sql sql-update

我有以下几组数据......

状态监测位置数据(CML表)

float('nan')

失败查找数据的可能性(POF表)

+--------+--------------------+--------------------+--------------+------------+--------------------+-------+-----+
| CML_ID |     POF_COLUMN     |      CML_TYPE      | SAMPLE_VALUE | COMPLIANCE | CORROSION_SEVERITY | LR_LD | POF |
+--------+--------------------+--------------------+--------------+------------+--------------------+-------+-----+
|      1 | SAMPLE_VALUE       | MIC_SAMPLING_POINT |            5 | NO         | MINOR              |     1 |     |
|      2 | SAMPLE_VALUE       | MIC_SAMPLING_POINT |          0.5 | NO         | MINOR              |     2 |     |
|      3 | SAMPLE_VALUE       | MIC_SAMPLING_POINT |           20 | NO         | MINOR              |     3 |     |
|      4 | COMPLIANCE         | VALVE_ROTATED      |            0 | YES        | MINOR              |     4 |     |
|      5 | LR_LD              | PIPING_THICKNESS   |            0 | YES        | MINOR              |   0.1 |     |
|      6 | CORROSION_SEVERITY | VESSEL_SHELL       |            0 | NO         | SEVERE             |     0 |     |
|      7 | CORROSION_SEVERITY | NOZZLE             |            0 | NO         | LOW                |     0 |     |
+--------+--------------------+--------------------+--------------+------------+--------------------+-------+-----+

我需要使用[POF_Column],[CML_Type]和每个CML记录的[SAMPLE_VALUE],[COMPLIANCE],[CORROSION_SEVERITY]或[LR_LD]字段返回POF表中的壁橱或完全匹配的记录在CML表中。然后更新将POF记录到CML表。

例如,如果我们查看CML_ID = 2。

按[POF_COLUMN] =' SAMPLE_VALUE',[CML_TYPE] =' MIC_SAMPLING_POINT'过滤POF表。并且[VALUE_RANGE] - [SAMPLE_VALUE]列中的值(在这种情况下为0.5)是最小值。

在这种情况下,它将匹配POF表中的第一条记录,并返回POF = 5的值。

如果我们看另一个案例。 CML_ID = 7。

按[POF_COLUMN] =' CORROSION_SEVERITY',[CML_TYPE] =' NOZZLE'过滤POF表。并且[VALUE_RANGE] = [CORROSION_SEVERITY]列中的值,在这种情况下' LOW'。

在这种情况下,它将匹配POF表中底部的第四行,并返回POF = 5的值。

总之,我需要更新CML表以显示以下结果......

+--------------------+--------------------+-------------+-----+
|     POF_COLUMN     |      CML_TYPE      | VALUE_RANGE | POF |
+--------------------+--------------------+-------------+-----+
| SAMPLE_VALUE       | MIC_SAMPLING_POINT | 1           |   5 |
| SAMPLE_VALUE       | MIC_SAMPLING_POINT | 5           |   4 |
| SAMPLE_VALUE       | MIC_SAMPLING_POINT | 10          |   3 |
| SAMPLE_VALUE       | MIC_SAMPLING_POINT | 15          |   2 |
| SAMPLE_VALUE       | MIC_SAMPLING_POINT | 100         |   1 |
| COMPLIANCE         | VALVE_ROTATED      | YES         |   5 |
| COMPLIANCE         | VALVE_ROTATED      | NO          |   1 |
| LR_LD              | PIPING_THICKNESS   | 2           |   5 |
| LR_LD              | PIPING_THICKNESS   | 1.5         |   4 |
| LR_LD              | PIPING_THICKNESS   | 1           |   3 |
| LR_LD              | PIPING_THICKNESS   | 0.8         |   2 |
| LR_LD              | PIPING_THICKNESS   | 0.5         |   1 |
| CORROSION_SEVERITY | VESSEL_SHELL       | NEGLIGIBLE  |   5 |
| CORROSION_SEVERITY | VESSEL_SHELL       | LOW         |   4 |
| CORROSION_SEVERITY | VESSEL_SHELL       | MEDIUM      |   3 |
| CORROSION_SEVERITY | VESSEL_SHELL       | HIGH        |   2 |
| CORROSION_SEVERITY | VESSEL_SHELL       | SEVERE      |   1 |
| CORROSION_SEVERITY | NOZZLE             | NEGLIGIBLE  |   5 |
| CORROSION_SEVERITY | NOZZLE             | LOW         |   5 |
| CORROSION_SEVERITY | NOZZLE             | MEDIUM      |   5 |
| CORROSION_SEVERITY | NOZZLE             | HIGH        |   3 |
| CORROSION_SEVERITY | NOZZLE             | SEVERE      |   2 |
+--------------------+--------------------+-------------+-----+

有谁知道我怎么能做到这一点?我在下面列出了一些我尝试的示例代码。这适用于查找完全匹配的值但不是最接近的匹配值。

+--------+---+-----+
| CML_ID | … | POF |
+--------+---+-----+
|      1 | … |   4 |
|      2 | … |   5 |
|      3 | … |   2 |
|      4 | … |   5 |
|      5 | … |   1 |
|      6 | … |   1 |
|      7 | … |   5 |
+--------+---+-----+

2 个答案:

答案 0 :(得分:1)

很好的措辞,有足够的细节。

你在这里遇到挑战。

A)POF中的值是字符串或浮点数。如果是字符串,则需要进行精确比较。如果它是一个浮点数,你想找到最接近的值。

这会在应用服务器中尖叫业务代码,但我们假设您希望在MySQL中执行此操作。

答案是一个案例陈述,由CML_TYPE确定如何计算POF。对于“字符串”类型比较,这将是一个等于。对于“浮点”类型比较,您可以编写比较以获得最接近提供值的记录。无论哪种方式,每个规则都略有不同。

您需要做的是为每个CML_TYPE创建一个CASE语句,然后创建一个自定义匹配器来查找您想要的POF。

以下代码确实有效,但无法保证性能。

UPDATE CML c
  JOIN 
(select CML_ID, 
  CASE CML_TYPE 
     WHEN 'VALVE_ROTATED' THEN
       (select POF from POF where POF.CML_TYPE = CML.CML_TYPE and VALUE_RANGE = CML.COMPLIANCE)
     WHEN 'VESSEL_SHELL' THEN
       (select POF from POF where POF.CML_TYPE = CML.CML_TYPE and VALUE_RANGE = CML.CORROSION_SEVERITY)
     WHEN 'NOZZLE' THEN
       (select POF from POF where POF.CML_TYPE = CML.CML_TYPE and VALUE_RANGE = CML.CORROSION_SEVERITY)
     WHEN 'MIC_SAMPLING_POINT' THEN
       (select POF from POF where POF.CML_TYPE = CML.CML_TYPE ORDER BY ABS(CML.SAMPLE_VALUE - cast(VALUE_RANGE AS DECIMAL(10,2))) LIMIT 1)
     WHEN 'PIPING_THICKNESS' THEN
       (select POF from POF where POF.CML_TYPE = CML.CML_TYPE ORDER BY ABS(CML.SAMPLE_VALUE - cast(VALUE_RANGE AS DECIMAL(10,2))) LIMIT 1)
     ELSE 'BLAH'       
  END as CALC_POF
from CML) as updater on c.CML_ID = updater.CML_ID
set c.POF = updater.CALC_POF;

Link TO SQL Fiddle

答案 1 :(得分:1)

使用样本数据和预期结果上传非常详细的帖子。 问题在于sample_value和lr_ld,因为它可能不是POF表中的确切值。但是,您会注意到值等于或小于值范围。

因此,如果我们得到POF值的最大值,其中sample_value或lr_ld小于或等于值范围,那么我们只需要得到最大的POF值。

此查询仅在sample_value或lr_ld增加时POF值增加时才有效。

UPDATE CML c
  JOIN 
(
    select c.CML_ID, max(p.POF) POF 
    from CML c
    LEFT JOIN POF p
    ON c.POF_COLUMN = p.POF_COLUMN
       AND c.CML_TYPE = p.CML_TYPE
       AND ( (c.POF_COLUMN = 'COMPLIANCE' AND c.COMPLIANCE = p.VALUE_RANGE) OR
             (c.POF_COLUMN = 'SAMPLE_VALUE' AND  c.SAMPLE_VALUE<=p.VALUE_RANGE) OR
             (c.POF_COLUMN = 'LR_LD' AND c.LR_LD  <= p.VALUE_RANGE) OR
             (c.POF_COLUMN = 'CORROSION_SEVERITY' AND c.CORROSION_SEVERITY = p.VALUE_RANGE)
           )
     group by c.CML_ID 
   ) t
 on c.CML_ID = t.CML_ID
set c.POF = t.POF;