Mysql选择具有最小和最大数据的行中的间隙

时间:2013-08-15 18:34:30

标签: php mysql

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

实施例

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

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

我正在寻找一种在数据中找到间隙(孔)的方法。根据上述数据,差距将为1001-1499和9000-9999。

我正在使用php和mysql。

3 个答案:

答案 0 :(得分:3)

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

差距将从一个以上的最大值开始,并以小于一个小时的一个结束。然后,您只需要查看特定记录是否参与了差距。

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
                 )

答案 1 :(得分: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的差距。)

设置测试用例(我将OP 0000值调整为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

修改

我刚注意到OP注释数据类型为CHAR(4),我认为它是整数类型,可能是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');

答案 2 :(得分: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中的min和max