2008-12-31 88 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已經覆蓋的數字表。