2011-02-17 37 views
0

我有以下查询:SQL是否打破数字模式,标记记录?

SELECT AccountNumber, RptPeriod 
FROM dbo.Report 
ORDER BY AccountNumber, RptPeriod. 

我得到如下结果:

123 200801 
123 200802 
123 200803 
234 200801 
344 200801 
344 200803 

我需要标记在rptperiod犯规同时流动帐户的纪录。例如,344 200803会在它旁边有一个X,因为它从200801到200803.

这是约19321行,我希望它在公司的基础上,所以不同公司之间我不在乎数字是什么,我只是想让同一家公司展示数字模式中的哪些地方出现中断。

任何想法?

谢谢!

+0

每个`AccountNumber`,`RptPeriod`最多有一个匹配吗?组合(无重复) – 2011-02-17 15:09:33

+0

是的,只有一个报告期间可以对公司相同。 – user380432 2011-02-17 15:25:59

回答

2

OK,这是一种丑陋的(双加盟+反连接),但它可以完成的工作,和是纯粹的便携式SQL:

SELECT * 
FROM dbo.Report R1 
    , dbo.Report R2 
WHERE R1.AccountNumber = R2.AccountNumber 
AND R2.RptPeriod - R1.RptPeriod > 1 
-- subsequent NOT EXISTS ensures that R1,R2 rows found are "next to each other", 
-- e.g. no row exists between them in the ordering above 
AND NOT EXISTS 
     (SELECT 1 FROM dbo.Report R3 
     WHERE R1.AccountNumber = R3.AccountNumber 
     AND R2.AccountNumber = R3.AccountNumber 
     AND R1.RptPeriod < R3.RptPeriod 
     AND R3.RptPeriod < R2.RptPeriod 
     ) 
0

像这样的东西应该这样做:

-- cte lists all items by AccountNumber and RptPeriod, assigning an ascending integer 
-- to each RptPeriod and restarting at 1 for each new AccountNumber 
;WITH cte (AccountNumber, RptPeriod, Ranking) 
as (select 
     AccountNumber 
     ,RptPeriod 
     ,row_number() over (partition by AccountNumber order by AccountNumber, RptPeriod) Ranking 
     from dbo.Report) 
-- and then we join each row with each preceding row based on that "Ranking" number 
select 
    This.AccountNumber 
    ,This.RptPeriod 
    ,case 
     when Prior.RptPeriod is null then '' -- Catches the first row in a set 
     when Prior.RptPeriod = This.RptPeriod - 1 then '' -- Preceding row's RptPeriod is one less that This row's RptPeriod 
     else 'x' -- -- Preceding row's RptPeriod is not less that This row's RptPeriod 
    end UhOh 
    from cte This 
    left outer join cte Prior 
    on Prior.AccountNumber = This.AccountNumber 
    and Prior.Ranking = This.Ranking - 1 

(编辑补充评论)

0
WITH T 
    AS (SELECT *, 
       /*Each island of contiguous data will have 
        a unique AccountNumber,Grp combination*/ 
       RptPeriod - ROW_NUMBER() OVER (PARTITION BY AccountNumber 
               ORDER BY RptPeriod) Grp, 
       /*RowNumber will be used to identify first record 
       per company, this should not be given an 'X'. */ 
       ROW_NUMBER() OVER (PARTITION BY AccountNumber 
             ORDER BY RptPeriod) AS RN 
     FROM Report) 
SELECT AccountNumber, 
     RptPeriod, 
     /*Check whether first in group but not first over all*/ 
     CASE 
     WHEN ROW_NUMBER() OVER (PARTITION BY AccountNumber, Grp 
            ORDER BY RptPeriod) = 1 
       AND RN > 1 THEN 'X' 
     END AS Flag 
FROM T 
0
SELECT * 
FROM report r 
LEFT JOIN report r2 
ON  r.accountnumber = r.accountnumber 
AND {r2.rptperiod is one day after r.rptPeriod} 
JOIN report r3 
ON  r3.accountNumber = r.accountNumber 
AND r3.rptperiod > r1.rptPeriod 
WHERE r2.rptPeriod IS NULL 
AND r3 IS NOT NULL 

我不确定sql服务器日期逻辑的语法,但希望你明白了。 r将是下一个rptPeriod为空(r2)并且存在至少一个更大的rptPeriod(r3)的所有记录。我猜这个查询不是非常直接的,但如果你在两列上有一个索引,它可能是获取你的数据的最有效的方法。

0

基本上,您在每个帐户中编号行,然后使用行号比较相邻行的RptPeriod值。

这里假定RptPeriod是编码的年份和月份,对于这种情况,已经添加了年转换检查。

;WITH Report_sorted AS (
    SELECT 
    AccountNumber, 
    RptPeriod, 
    rownum = ROW_NUMBER() OVER (PARTITION BY AccountNumber ORDER BY RptPeriod) 
    FROM dbo.Report 
) 
SELECT 
    AccountNumber, 
    RptPeriod, 
    CASE ISNULL(CASE WHEN r1.RptPeriod/100 < r2.RptPeriod/100 THEN 12 ELSE 0 END 
       + r1.RptPeriod - r2.RptPeriod, 1) AS Chk 
    WHEN 1 THEN '' 
    ELSE 'X' 
    END 
FROM Report_sorted r1 
    LEFT JOIN Report_sorted r2 
    ON r1.AccountNumber = r2.AccountNumber AND r1.rownum = r2.rownum + 1 

它可以进一步与额外的检查,复杂的一年多的跨越,如果你需要的差距。