SQL如果打破数字模式,标记记录?

时间:2011-02-17 15:04:07

标签: sql sql-server-2005

我有以下查询:

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行,我想在公司的基础上,所以在不同的公司之间,我不在乎数字是什么,我只是想让同一家公司显示数字模式中断的地方。

任何想法?

谢谢!

5 个答案:

答案 0 :(得分:2)

好的,这有点难看(双连接+反连接)但它完成了工作,并且是纯粹的可移植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
        )

答案 1 :(得分: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

(编辑添加评论)

答案 2 :(得分: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  

答案 3 :(得分: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 server的日期逻辑语法,但希望你明白了。 r将是下一个rptPeriod为NULL(r2)并且至少存在一个更大的rptPeriod(r3)的所有记录。我想这个查询不是超级直接的,但是如果你有两列的索引,它可能是获得数据最有效的方法。

答案 4 :(得分: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

如果您需要,可以进一步检查是否存在一年或更长时间的差距。