2008-12-31 87 views
2

我有一个表,有2分重要的列DocEntry,WebId查找遗漏值

的样本数据是像

DocEntry WebId 
1   S001 
2   S002 
3   S003 
4   S005 

现在,我们可以看到这里,列WebId,S004缺少。我们如何找到这样的缺失数字,并附上查询。

进一步解释:

的网络ID应该是递增的顺序一样,S001,S002,S003,S004,S005,如果任何号码之间的缺失,比的是缺号。我没有可能的条目单独的表格,因为这是不实际的。我必须以月份为基础找出缺失的数字,以每月的起始和结束值作为边界,并找到丢失的数字(如果有的话)。

回答

4

一个非常简单的方法:)

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) 

好运, 莫里斯

0

您需要定义“失踪”的含义。你不能指望你的数据库服务器理解这个抽象概念。也许存储过程是最好的方法,因为那样你可以更精确地定义你的逻辑。

+0

您的评论是有效的。这个问题已被澄清。我建议取消这个答案,以避免反对票。 – 2008-12-31 17:51:25

1

除非你已经定义了一个特定的号码布局(它看起来像你的),有一个表的所有可能性(不是很长的时间效率,虽然),你可以做这样的事情:

获取一个表名PossibleEntries的所有possiblities然后做到这一点:

SELECT pe.WebID从PossibleEntries PE WHERE pe.WebID不在(从sampleData在选择WebID)

我认为应该工作,但我不不知道它有多高效。 我同意以上所述。如果这些数字不是连续的,你将无法做到这一点。

1

就我个人而言,我会用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,那么这可能会做你想做的。

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 cla用来限制你在一个范围内,一些字符串函数会让你进入上面的Robs答案中的PossibleEntries表。

+0

这是适度的努力工作。 – 2009-01-01 09:29:09

1

旁白:为什么一般人(拉胡尔是不是唯一的一个,由任何想象的延伸),从问题中省略了表的名称?)

这是很难做到的以关系的方式,因为它本质上依赖于(无序)集上的数据和关系代数作品的排序。我认为我们应该假定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; 

是联接在外部水平实际上得到了我们什么有用吗?我不这么认为,所以我们可以将其删除,从而导致(第2次尝试)

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; 
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已经覆盖的数字表。