SQL если взломать шаблон номера, пометить запись? - PullRequest
0 голосов
/ 17 февраля 2011

У меня следующий запрос:

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 ]

2 голосов
/ 17 февраля 2011

ОК, это немного уродливо (двойное соединение + анти-соединение), но оно выполняет свою работу, И это чистый переносимый 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 голосов
/ 17 февраля 2011

Обычно вы нумеруете строки в каждой учетной записи, а затем, используя номера строк, сравниваете значения 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

Это может быть осложнено дополнительной проверкой разрывов, охватывающих год и более, если вам это нужно.

0 голосов
/ 17 февраля 2011
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 равен NULL (r2) и существует по крайней мере один больший rptPeriod (r3). Я полагаю, что этот запрос не слишком прост, но если у вас есть индекс по двум столбцам, он, вероятно, будет наиболее эффективным способом получения ваших данных.

0 голосов
/ 17 февраля 2011
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 голосов
/ 17 февраля 2011

Что-то вроде этого должно сделать это:

--  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

(отредактировано для добавления комментариев)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...