2011-11-26 81 views
1

讓想我的數據庫的數據結構就是這樣尋找失蹤數據庫序列號

ShopId Transaction 

001  1.000  
001  2.000 
001  3.000 
002  1.000 
002  2.000 
002  3.000 

現在是威力可能是一些交易缺少讓想

002  4.000 
002  6.000 

在上面的表格5.000交易的表丟失。

我想編寫一個查詢,在我的數據庫中查找像上面那樣丟失的序列號。

所以我的查詢將返回結果

shopid  transaction 
    002  5.000 

回答

2

要得到缺少交易的每ShopId數量:

SELECT ShopId 
     , count(*) 
      - max([Transaction]) 
      + min([Transaction]) 
      - 1 as MissingTranCount 
    FROM yourtable 
GROUP BY ShopId 

要獲取丟失的事務:

1. Generate table #numbers

2.Gener吃#shops:

SELECT ShopId as id 
    into #shops 
    FROM yourtable 
GROUP BY ShopId 
    HAVING count(*) 
      - max([Transaction]) 
      + min([Transaction]) 
      - 1 > 0 

3.Get缺少的交易:

SELECT id 
     , number 
    FROM #numbers 
    cross join #shops shops 
    WHERE exists (SELECT 1 
        FROM yourtable 
        WHERE ShopId = id 
        and number < [Transaction] 
       ) 
    and exists (SELECT 1 
        FROM yourtable 
        WHERE ShopId = id 
        and number > [Transaction] 
       ) 
    and not exists (SELECT 1 
         FROM yourtable 
         WHERE ShopId = id 
         and number = [Transaction] 
       )   
1

1)生成缺少的TX我需要一個符合表,每個店(的TX的最大數量前。 1000分的TX):

CREATE TABLE Number 
(
    Id INT IDENTITY(1,1) PRIMARY KEY 
); 
GO 

INSERT Number 
DEFAULT VALUES; 
--It executes 1000 times this batch 
GO 1000 

SELECT * 
FROM Number; 
GO 

2)該溶液是基於下的假定:

-For每ShopId第一TX是1.000。

- 對於每個ShopId,交易清單表示算術級數:上一筆交易+ 1。

DECLARE @Test TABLE 
(
    ShopId  CHAR(3) NOT NULL 
    ,Tx   NUMERIC(6,3) NOT NULL 
    ,PRIMARY KEY(ShopId, Tx) 
); 

INSERT @Test(ShopId, Tx) 
SELECT '001',1.000 UNION ALL  
SELECT '001',2.000 UNION ALL 
SELECT '001',3.000 UNION ALL 
SELECT '002',1.000 UNION ALL 
SELECT '002',2.000 UNION ALL 
SELECT '002',3.000 UNION ALL 
SELECT '002',5.000 UNION ALL 
SELECT '002',6.000 UNION ALL 
SELECT '002',9.000 UNION ALL 
SELECT '003',1.000 UNION ALL 
SELECT '004',1.000 UNION ALL  
SELECT '004',4.000 UNION ALL  
SELECT '005',3.000; 

WITH Base 
AS 
(
    SELECT *, ROW_NUMBER() OVER(PARTITION BY a.ShopId ORDER BY a.Tx) RowNumber 
    FROM @Test a 
), TxStatus 
AS 
(
    SELECT crt.ShopId 
      ,crt.Tx AS TxCurrent 
      ,ISNULL(prev.Tx,0) AS TxPrevious 
      ,CASE 
       WHEN crt.RowNumber = 1 AND crt.Tx = 1.000 THEN 1 --It checks if the first Tx is 1.000 
       WHEN crt.RowNumber > 1 AND crt.Tx = prev.Tx + 1.000 THEN 1 
       ELSE 0 
      END IsOk 
    FROM Base crt /*Current*/ 
    LEFT JOIN Base prev /*Previous*/ ON crt.ShopId = prev.ShopId 
    AND  crt.RowNumber = prev.RowNumber + 1 
) 
SELECT x.ShopId 
     ,x.TxPrevious+1 AS MissingFrom 
     ,x.TxCurrent-1 AS MissingTo 
     ,n.Id AS MissingTx 
FROM TxStatus x 
INNER JOIN Number n ON n.Id BETWEEN x.TxPrevious+1 AND x.TxCurrent-1 
WHERE x.IsOk = 0; 

結果:

ShopId MissingFrom MissingTo MissingTx 
------ ----------- --------- --------- 
002 4.000  4.000  4 
002 7.000  8.000  7 
002 7.000  8.000  8 
004 2.000  3.000  2 
004 2.000  3.000  3 
005 1.000  2.000  1 
005 1.000  2.000  2