我有一个表,有两个重要的列DocEntry,WebId
示例数据类似于
DocEntry WebId
1 S001
2 S002
3 S003
4 S005
现在我们可以注意到,在WebId列中,缺少S004。我们如何通过查询找到这些丢失的数字。
进一步解释:
如果缺少任何数字,则网络ID应按递增顺序,如S001,S002,S003,S004,S005,而不是丢失的数字。我没有任何单独的表可用条目,因为这是不切实际的。我要逐月找到丢失的数字,将每个月的起始值和结束值作为边界,而不是找到丢失的数字(如果有的话)。
答案 0 :(得分:5)
一种非常简单的方法:)
mysql> select * from test;
+----------+-------+
| DocEntry | WebId |
+----------+-------+
| 1 | S001 |
| 2 | S002 |
| 3 | S003 |
| 4 | S005 |
| 5 | S006 |
| 6 | S007 |
| 7 | S008 |
| 8 | S010 |
+----------+-------+
8 rows in set (0,00 sec)
mysql> SELECT right(t1.webid,3) +1 as missing_WebId FROM test t1 left join test t2 on right(t1.webid,3)+1 = right(t2.webid,3) where t2.webid is null;
+---------------+
| missing_WebId |
+---------------+
| 4 |
| 9 |
| 11 |
+---------------+
3 rows in set (0,01 sec)
祝你好运,
莫里斯
答案 1 :(得分:1)
有一个生成整数的标准技巧,需要你创建一个10行实用程序表,即:
create table Pivot (i int)
insert into Pivot values (0)
insert into Pivot values (1)
insert into Pivot values (2)
/* ... down to */
insert into Pivot values (9)
一旦你完成了这个,那么,例如
select u.i + 10*t.i + 100*h.i from Pivot u, Pivot t, Pivot h
会得到0到999的所有数字。
添加一个where子句来限制你在一个范围之间,一些字符串函数会让你进入上面Robs回答中的PossibleEntries表。
答案 2 :(得分:1)
(旁白:为什么一般人(Rahul不是唯一一个,在任何想象中)从问题中省略了他们的表名?)
以关系方式进行操作非常困难,因为它本身依赖于数据的排序和关系代数在(无序)集合上的工作。我认为我们应该假设DocID列没有任何意义,它不能用于帮助解决问题。
在该示例中,您有S003和S005并且缺少S004。我们如何判断缺失值?据推测,因为有一个比较操作告诉我们'小于','相等','大于',还因为有一个差异函数告诉我们S003和S005之间的差距是2.让我们假设' >”和朋友进行比较(在这里用于字符串),并且你可以生成一个存储过程webid_diff(),它接受两个WebID值并返回差异。
然后,您可以编写一个查询,例如:
SELECT a.webid, MIN(b.webid) AS min_next
FROM AnonymousTable AS a, AnonymousTable AS b
WHERE a.webid < b.webid
GROUP BY a.webid;
这使用表和它自身之间的非等值连接来查找每个项目的最小后继WebID值。
以此为核心,我们可以过滤结果,只选择WebID和Min_Next之间的差距大于1的那些行。所以,我认为我们得到了(第一次尝试):
SELECT x.webid, y.min_next, webid_diff(x.webid, y.min_next) AS gap
FROM AnonymousTable AS x,
(SELECT a.webid, MIN(b.webid) AS min_next
FROM AnonymousTable AS a, AnonymousTable AS b
WHERE a.webid < b.webid
GROUP BY a.webid
) AS y
WHERE x.webid = y.webid
AND webid_diff(x.webid, y.min_next) > 1;
外层的联接实际上是否对我们有用?我不这么认为,所以我们可以删除它,导致(第二次尝试):
SELECT y.webid, y.min_next, webid_diff(y.webid, y.min_next) AS gap
FROM (SELECT a.webid, MIN(b.webid) AS min_next
FROM AnonymousTable AS a, AnonymousTable AS b
WHERE a.webid < b.webid
GROUP BY a.webid
) AS y
WHERE webid_diff(y.webid, y.min_next) > 1;
这确实有效。试图将webid_diff()函数放入内部查询会给我带来问题 - 至少GAP表达式必须包含在GROUP BY子句中,但那样会给出错误的答案。
HAVING子句用于将过滤条件应用于聚合,因此看起来好像查询可以简化为:
SELECT a.webid, MIN(b.webid) AS min_next, webid_diff(a.webid, b.webid) AS gap
FROM AnonymousTable AS a, AnonymousTable AS b
WHERE a.webid < b.webid
GROUP BY a.webid
HAVING webid_diff(a.webid, b.webid) > 1;
然而,这不起作用(对我来说,使用我的DBMS - IBM Informix Dynamic Server),因为webid_diff()不是聚合。
这是我用于webid_diff()函数的代码(你必须调整以适应你的DBMS的语法)和辅助webid_num()函数:
CREATE FUNCTION webid_num(a CHAR(4)) RETURNING INTEGER;
DEFINE i INTEGER;
LET i = substr(a, 2, 3);
RETURN i;
END FUNCTION;
CREATE FUNCTION webid_diff(a CHAR(4), b CHAR(4)) RETURNING INTEGER;
DEFINE i, j INTEGER;
LET i = webid_num(a);
LET j = webid_num(b);
RETURN (j - i);
END FUNCTION;
答案 3 :(得分:0)
你需要通过“缺失”来定义你的意思。您不能指望您的数据库服务器能够理解这个抽象概念。也许存储过程是最好的方法,因为那时你可以更精确地定义你的逻辑。
答案 4 :(得分:0)
除非你已经定义了一个特定的数字布局(它看起来像你),否则要有一个包含所有可能性的表格(虽然效率不是很高),你可以这样做:
获取一个包含名称PossibleEntries的所有可能性的表,然后执行以下操作:
SELECT pe.WebID from PossibleEntries pe
WHERE pe.WebID Not In (Select WebID from SampleData)
我认为这应该有效,但我不知道效率如何。 我同意上述内容,如果数字不是连续的,你将无法做到这一点。
答案 5 :(得分:0)
就个人而言,我会用PHP或者你用SQL编写的任何编程语言来做这件事。如果你不能拥有一个包含所有可能值的单独表(顺便说一句,为什么不呢?)那么我采取的方法是直接查询以获取表中的值:
select WebID from table order by WebID;
然后使用一个简单的循环来查找哪些缺失。例如,在php中:
$values = Array();
$query = "select WebID from table order by WebID;";
$dataset = mysql_query ($query) or die (mysql_error());
while ($data = mysql_fetch_assoc($dataset))
{
$values[$data['WebID'] = 1;
}
$last_line = $data['WebID'];
$matches = Array();
ereg("S([0-9]+)", $last_line, $matches))
$max_value = $matches[0];
$missing = Array();
for ($count = 0; $count < $max_value; $count ++)
{
if (!isset($values[$count])
{
echo "value $count is missing\n";
$missing[$count] = true;
}
}
我还没有对它进行过测试,但是如果您确实使用了PHP,那么这可能就是您想要的。
本
答案 6 :(得分:0)
我的猜测是你的数据库有一个严重的设计缺陷,因为看起来你的WebID实际上至少有两列你已经组合在一起。数字部分显然具有某种意义,因为你希望它是顺序的,但如果是这样,那么“S”是什么意思?由于这种设计缺陷,您的问题的解决方案将变得比它需要的更复杂。此外,您声明存储对数据库很重要的数据并不“实际”是一个很大的危险信号。
除此之外,以下查询应该为您提供任何缺失值:
SELECT
(
SELECT
SUBSTRING(MAX(T4.WebID), 1, 1) +
RIGHT('000' + CAST(CAST(SUBSTRING(MAX(T4.WebID), 2, 3) AS INT) + 1 AS VARCHAR), 3)
FROM My_Table T4
WHERE T4.WebID < T1.WebID
) AS min_range,
SUBSTRING(T1.WebID, 1, 1) + RIGHT('000' + CAST(CAST(SUBSTRING(T1.WebID, 2, 3) AS INT) - 1 AS VARCHAR), 3) AS max_range
FROM
My_Table T1
LEFT OUTER JOIN My_Table T2 ON
T2.WebID = SUBSTRING(T1.WebID, 1, 1) +
RIGHT('000' + CAST(CAST(SUBSTRING(T1.WebID, 2, 3) AS INT) - 1 AS VARCHAR), 3)
WHERE
T2.WebID IS NULL AND
T1.WebID <> (SELECT MIN(WebID) FROM My_Table)
它为每个缺失值范围提供了一个开始和结束,而不是每个缺失值的明确列表。为了得到这个,你需要一张cindi和Rob所涵盖的数字表。