交叉联接,总价值最高

时间:2019-06-12 02:34:43

标签: mysql cross-join

我有下表,我们将其称为Segments

-------------------------------------
| SegmentStart | SegmentEnd | Value |
-------------------------------------
| 1            | 4          | 20    |
| 4            | 8          | 60    |
| 8            | 10         | 20    |
| 10           | 1000000    | 0     |
-------------------------------------

我正在尝试将此表与其自身连接,以获得以下结果集:

-------------------------------------
| SegmentStart | SegmentEnd | Value |
-------------------------------------
| 1            | 4          | 20    |
| 1            | 8          | 60    |
| 1            | 10         | 60    |
| 1            | 1000000    | 60    |
| 4            | 8          | 60    |
| 4            | 10         | 60    |
| 4            | 1000000    | 60    |
| 8            | 10         | 20    |
| 8            | 1000000    | 20    |
| 10           | 1000000    | 0     |
-------------------------------------

基本上,我需要将每一行与其后的每一行都连接起来,然后获取先前连接的每一行之间的值的MAX()示例:如果我要将第1行与第3行连接在一起,则需要所有这3行中的MAX(Value)

我已经做的是以下查询:

SELECT s1.SegmentStart, s2.SegmentEnd, GREATEST(s1.Value, s2.Value) as Value FROM Segments s1 CROSS JOIN Segments s2 ON s1.SegmentStart < s2.SegmentEnd

此查询将创建一个与所需表相似的表,但是值字段按以下方式混合(我已在!!的不同行之间进行了标记):

-------------------------------------
| SegmentStart | SegmentEnd | Value |
-------------------------------------
| 1            | 4          | 20    |
| 1            | 8          | 60    |
| 1            | 10         | !20!  |
| 1            | 1000000    | !20!  |
| 4            | 8          | 60    |
| 4            | 10         | 60    |
| 4            | 1000000    | 60    |
| 8            | 10         | 20    |
| 8            | 1000000    | 20    |
| 10           | 1000000    | 0     |
-------------------------------------

问题出在GREATEST()函数上,因为它只比较正在联接的两行(起始端1-4、8-10),而不是整个间隔(在这种情况下,它比较将是3行,起始行为1-4、4-8、8-10)

如何修改此查询,或应使用哪种查询来获得所需的结果?

其他信息可能会有所帮助:原始表中的行始终基于SegmentStart进行排序,并且不能有重复或缺失的值。 xy之间的每个间隔在表格中只会出现一次,没有重叠,也没有间隙。

我正在使用Maria DB 10.3.13

1 个答案:

答案 0 :(得分:1)

像这样吗?

SELECT
      s1.SegmentStart
    , s2.SegmentEnd
    , MAX(s.Value) as Value 
FROM
    Segments s1
    INNER JOIN Segments s2 ON (
        s2.SegmentEnd > s1.SegmentStart
    )
    INNER JOIN Segments s ON (
            s.SegmentStart >= s1.SegmentStart
        AND s.SegmentEnd <= s2.SegmentEnd
    )
GROUP BY
      s1.SegmentStart
    , s2.SegmentEnd