0

我有一个包含最小值和最大值列的表,其中可能有重叠的数据。

例子

+--------+--------+
| Minval | Maxval |
+--------+--------+
|   0000 |   1000 |
|   1500 |   8999 |
|   0100 |   0200 |
|   5000 |   6999 |
+--------+--------+

最小值和最大值的可能范围是 0000-9999。

我正在寻找一种方法来找到数据中的差距(漏洞)。根据上述数据,差距将是 1001-1499 和 9000-9999。

我正在使用 php 和 mysql。

4

3 回答 3

3

你不需要php代码。您可以在 SQL 中执行此操作。

间隙将从 maxval 多 1 开始,以比 minval 小 1 结束。然后,您只需要查看特定记录是否参与间隙。

select t.*,
       t.maxval+1 as gapStart,
       (select min(t2.minval) - 1
        from t t2
        where t2.minval > t.maxval
       ) as gapEnd
from t
where not exists (select 1
                  from t t2
                  where t.maxval + 1 between t2.minval and t2.maxval
                 )
于 2013-08-15T19:58:06.467 回答
1

结果可以由 MySQL 查询返回,无需脚本。

SELECT CONCAT(LPAD(r.lo,4,'0'),'-',LPAD(r.hi,4,'0')) AS gap
     , r.lo
     , r.hi
--   , d.minval IS NULL AS gap
--   , d.*
  FROM ( SELECT rl.lo, rh.hi
           FROM (SELECT 0000 AS lo UNION 
                 SELECT rlo.maxval+1
                   FROM example1 rlo
                  WHERE rlo.maxval < 9999
                 ) rl
            JOIN (SELECT 9999 AS hi UNION
                  SELECT rhi.minval-1
                    FROM example1 rhi
                   WHERE rhi.minval > 0000
                 ) rh
              ON rh.hi >= rl.lo
           GROUP BY rl.lo, rh.hi
       ) r
  LEFT
  JOIN example1 d
    ON r.lo BETWEEN d.minval+0 AND d.maxval+0
    OR r.hi BETWEEN d.minval+0 AND d.maxval+0
    OR d.minval+0 BETWEEN r.lo AND r.hi
    OR d.maxval+0 BETWEEN r.lo AND r.hi
 WHERE d.minval IS NULL
 ORDER
    BY r.lo, r.hi
--   , d.minval, d.maxval

我使用的方法是从一组所有可能的差距开始。我们知道,每一个潜在的差距都会:

  • 开始于0000或任何maxval+1
  • 结束于9999或任何minval-1

因此,我们可以生成所有可能的“间隙开始”的列表和所有可能的“间隙结束”的列表。(当我编写查询时,我将这些视为“范围”。我为内联视图、r“范围”、范围rh的“高端”和范围rl的“低”端使用了别名。

分配了别名 " " 的内联视图r返回所有可能存在间隙的行。(这几乎是一个交叉连接,但我们消除了 r.hi 小于 r.lo 的行。我认为用于此的实际术语是“不等式连接”。)

回到原始范围表的反连接模式消除了不是真正间隙的行,因为与表中的一个范围有一些重叠。(反连接模式是一个 LEFT JOIN,然后是 WHERE 子句中的谓词来消除行,如果 LEFT JOIN 操作找到匹配项,所以我们留下没有匹配的行。作为替代方案,相同可以使用一种NOT EXISTS (correlated subquery)方法来完成消除。)

(此查询还将返回0000-9999范围表中没有行的间隙。)

设置测试用例(我调整了 OP0000值以0055证明这将识别一个以 . 开头的间隙0000。)

CREATE TABLE `example1` (minval INT(4), maxval INT(4));
INSERT INTO `example1` VALUES (0055,1000),(1500,8999),(0100,0200),(5000,6999);


gap           lo     hi
---------  -----  -----
0000-0054      0     54
1001-1499   1001   1499
9000-9999   9000   9999

编辑

我刚刚注意到数据类型是 CHAR(4) 的 OP 注释,我假设它是整数类型,可能INT(4) ZEROFILL。上面的查询也适用于 CHAR 类型,但我们需要确保将 CHAR 转换为整数,最简单的方法是在列引用中添加“+0”,进行调整并进行测试。

CREATE TABLE `example1` (minval CHAR(4), maxval CHAR(4));
INSERT INTO `example1` VALUES ('0055','1000')
  ,('1500','8999'),('0100','0200'),('5000','6999');
于 2013-08-15T21:36:07.077 回答
0

你当然需要一个 PHP 代码

CREATE TABLE TEMP_TABLE (NUMBER_VALUE INT);

INSERT INTO TEMP_TABLE VALUES (1,2,3,....9999); 

您可以使用 php 循环执行此操作,或者创建一次常量查询并重用它

然后对主表中的每一行做一个

DELETE FROM TEMP_TABLE WHERE NUMBER_VALUE BETWEEN MINVAL AND MAXVAL;

删除后,您将留下空白但所有数字。然后你可以遍历这些以在 PHP 中存储最小值和最大值

于 2013-08-15T18:57:34.323 回答