Php Mysql选择具有最小和最大数据的行中的间隙
我有一个带有最小值和最大值列的表,其中可能有重叠的数据 范例Php Mysql选择具有最小和最大数据的行中的间隙,php,mysql,Php,Mysql,我有一个带有最小值和最大值列的表,其中可能有重叠的数据 范例 +--------+--------+ | Minval | Maxval | +--------+--------+ | 0000 | 1000 | | 1500 | 8999 | | 0100 | 0200 | | 5000 | 6999 | +--------+--------+ 最小值和最大值的可能范围为0000-9999 我正在寻找一种方法来找出数据中的漏洞。根据上述数据,差距将为1001-
+--------+--------+
| Minval | Maxval |
+--------+--------+
| 0000 | 1000 |
| 1500 | 8999 |
| 0100 | 0200 |
| 5000 | 6999 |
+--------+--------+
最小值和最大值的可能范围为0000-9999
我正在寻找一种方法来找出数据中的漏洞。根据上述数据,差距将为1001-1499和9000-9999
我正在使用php和mysql。您当然需要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中存储最小值和最大值。您当然需要一个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中存储最小值和最大值,而不需要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
)
您不需要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
)
结果可以通过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
编辑
我刚刚注意到OP注释中的数据类型是CHAR(4),我假设它是整数类型,很可能是INT(4)ZEROFILL
。上面的查询也可以处理字符类型,但我们需要确保字符转换为整数,最简单的方法是向列引用中添加“+0”,并进行调整和测试
CREATE TABLE `example1` (minval CHAR(4), maxval CHAR(4));
INSERT INTO `example1` VALUES ('0055','1000')
,('1500','8999'),('0100','0200'),('5000','6999');
结果可以通过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
编辑
我刚刚注意到OP注释中的数据类型是CHAR(4),我假设它是整数类型,很可能是INT(4)ZEROFILL
。上面的查询也可以处理字符类型,但我们需要确保字符转换为整数,最简单的方法是向列引用中添加“+0”,并进行调整和测试
CREATE TABLE `example1` (minval CHAR(4), maxval CHAR(4));
INSERT INTO `example1` VALUES ('0055','1000')
,('1500','8999'),('0100','0200'),('5000','6999');
最小和最大varchar的数据类型是什么?为什么不是int?为什么有前导零?为什么在字符列中存储整数值?最小和最大varchar的数据类型是什么?为什么不是int?为什么会有前导零?为什么要在字符列中存储整数值?这真的是临时表的最有效方法吗…?将值列表转换回某个范围的最佳方法是什么,例如
'1001-1499'
,而不是将间隙报告为'1001-1001'
,'1002-1002'
,'1003-1003'
,等。@James-我不认为这是最有效的,但它解决了这个问题fully@spencer7593PHP循环,该循环运行并检查其旁边是否有值,如果没有,则将其报告为间隙开始并继续,直到出现新的连续值,虽然被接受的答案也可以很好地调整,但这是处理这个真正临时表的最有效方法…?将值列表转换回某个范围的最佳方法是什么,例如'1001-1499'
,而不是将间隙报告为'1001-1001'
,'1002-1002'
,'1003-1003'
,等。@James-我不认为这是最有效的,但它解决了这个问题fully@spencer7593PHP循环,它运行并检查它旁边是否有值,如果没有,则报告它作为间隔开始并继续,直到新的连续值,而接受的答案也可以微调,这是一个赢家。谢谢你。我同意resultset可以只使用MySQL返回。但有一个边缘情况,我认为这无法处理:从0000开始的间隙。(例如,如果该(00001000)
行更改为(00551000)
)。我也采取了类似的方法。我生成了所有可能间隙的集合(我们知道任何间隙都将在0000、9999、minval-1或maxval+1开始和结束。很容易得到所有“可能间隙”的整个集合(忽略minval>maxval的交叉连接,我必须在0000和9999中并集)。在我的查询中不起作用的是消除所有非实际间隙的行。@Chinaski…请注意,如果您想处理这两种边缘情况,可以使用union all
语句,与最小的minval和最大的maxval进行比较。这是一个赢家。谢谢。+1。我同意返回结果集时只需MySQL。但是有一个边缘情况,我不认为这可以处理:一个从0000
开始的间隙(例如,如果(00001000)
行被更改为(00551000)
),我采用了类似的方法。我生成了所有可能的间隙集(我们知道任何间隙都将在0000、9999、minval-1或maxval+1处开始和结束。很容易得到所有“可能间隙”的整个集合(忽略minval>maxval的交叉连接,我必须在0000和9999处并集)。在我的查询中不起作用的是消除所有非实际间隙的行。@Chinaski…请注意,如果您想处理这两种边缘情况,可以使用union all
语句,与最小的minval和最大的maxval进行比较。这更完整。也感谢您的解释。我仍在尝试分析怎么样。@Chinaski:诀窍在于查询r
(您可以单独运行)来生成每个可能的范围。rl
获取每个可能的间隙的“min”,而rh
获取每个可能的间隙的“max”。我们进行连接,并获取每个可能的间隙。(只有当hi小于lo时,lo和hi的组合才不会成为间隙。下一个技巧是“反连接”…找出所有这些可能的间隙中哪些不是真正的间隙,因为它们