-1

我们有一种情况是在保存的 mysql 表范围之间获取唯一计数。可以说,我将数据保存在如下表中:

sr_no start_sr_no end_sr_number 总数
1 1 10 10
2 5 15 11
3 27 35 9
4 11 21 11

现在在上面的记录中看到,行 sr_no 2 与行 sr_no 1 和行 sr_no 4 重叠,因此所有 3 个范围的唯一 total_count 应该是:21 而不是 10+11+11 = 32 并且所有范围总计数应该是:30 10+11+9+11:41

4

1 回答 1

1

10.4.17-MariaDB – Rakesh Verma

WITH
cte1 AS ( SELECT start_sr_no value, 1 weight FROM test
          UNION ALL
          SELECT end_sr_number, -1 FROM test ),
cte2 AS ( SELECT *,
                 SUM(weight) OVER (ORDER BY value, weight DESC) cost
          FROM cte1 ),
cte3 AS ( SELECT value, 
                 SUM(cost = 0) OVER (ORDER BY value DESC) grp
          FROM cte2 )
SELECT MIN(value) start_sr_no, 
       MAX(value) end_sr_number, 
       MAX(value) - MIN(value) + 1 total_count
FROM cte3
GROUP BY grp
ORDER BY 1

仅用于总值

WITH
cte1 AS ( SELECT start_sr_no value, 1 weight FROM test
          UNION ALL
          SELECT end_sr_number, -1 FROM test ),
cte2 AS ( SELECT *,
                 SUM(weight) OVER (ORDER BY value, weight DESC) cost
          FROM cte1 ),
cte3 AS ( SELECT value, 
                 SUM(cost = 0) OVER (ORDER BY value DESC) grp
          FROM cte2 ),
cte4 AS ( SELECT MIN(value) start_sr_no, 
                 MAX(value) end_sr_number, 
                 MAX(value) - MIN(value) + 1 total_count
          FROM cte3
          GROUP BY grp )
SELECT SUM(total_count) total_count
FROM cte4

https://dbfiddle.uk/?rdbms=mariadb_10.4&fiddle=a627f3276bf2fd60d6bcfc986d4c19d9


对于较低版本的 mysql 也需要相同的查询,例如 MySQL5.5 – Rakesh Verma

SELECT MIN(start) start_sr_no,
       MAX(finish) end_sr_number,
       MAX(finish) - MIN(start) + 1 total_count
FROM ( SELECT CASE WHEN start_sr_no > @prev_finish
            THEN @group := @group + 1
                   ELSE @group
                   END grp,
              CASE WHEN start_sr_no BETWEEN @prev_start AND @prev_finish
                   THEN @prev_start
                   ELSE @prev_start := start_sr_no
                   END start, 
              CASE WHEN end_sr_number < @prev_finish
                   THEN @prev_finish
                   ELSE @prev_finish := end_sr_number
                   END finish
       FROM test
       CROSS JOIN ( SELECT @prev_start := -1,
                           @prev_finish := -1,
                           @group := 0 ) init_variables
       ORDER BY start_sr_no, end_sr_number ) enumerated
GROUP BY grp

SELECT SUM(total_count) total_count
FROM ( SELECT MIN(start) start_sr_no,
              MAX(finish) end_sr_number,
              MAX(finish) - MIN(start) + 1 total_count
       FROM ( SELECT CASE WHEN start_sr_no > @prev_finish
                   THEN @group := @group + 1
                          ELSE @group
                          END grp,
                     CASE WHEN start_sr_no BETWEEN @prev_start AND @prev_finish
                          THEN @prev_start
                          ELSE @prev_start := start_sr_no
                          END start, 
                     CASE WHEN end_sr_number < @prev_finish
                          THEN @prev_finish
                   ELSE @prev_finish := end_sr_number
                   END finish
                   FROM test
              CROSS JOIN ( SELECT @prev_start := -1,
                                  @prev_finish := -1,
                                  @group := 0 ) init_variables
              ORDER BY start_sr_no, end_sr_number ) enumerated
       GROUP BY grp ) total

https://dbfiddle.uk/?rdbms=mysql_5.5&fiddle=e2e3e6a6bd00aca2f8c53de50638788d

于 2021-06-08T07:49:14.577 回答