2011-11-26 72 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