Самостоятельное присоединение к переменным данным

StackOverflow https://stackoverflow.com/questions/1842459

Вопрос

У меня есть таблица со следующими данными:

Fiscal Year | Fiscal Quarter | Fiscal Week | Data
2009        | 2              | 22          | 9.5
2009        | 2              | 24          | 8.8
2009        | 2              | 26          | 8.8
2009        | 3              | 28          | 8.8
2009        | 3              | 31          | 9.1
2009        | 3              | 33          | 8.8

Я хотел бы написать запрос, который выдал бы следующее:

Fiscal Year | Fiscal Quarter | Fiscal Week | Data | Trend
2009        | 2              | 22          | 9.5  | NULL
2009        | 2              | 24          | 8.8  | -0.7
2009        | 2              | 26          | 8.8  | 0
2009        | 3              | 28          | 8.8  | 0
2009        | 3              | 31          | 9.1  | 0.3
2009        | 3              | 33          | 8.8  | -0.3 

Я знаю, что этого можно легко добиться, выполнив простое соединение таблицы с самой собой с предыдущей финансовой неделей, однако это не всегда будет простым t1.[Fiscal Week] = t2.[Fiscal Week] - 2 потому что иногда разница составляет 3 недели.

Я могу легко получить максимальную запись примерно так:

SELECT
    MAX(t1.[Fiscal Week]) "LastWeek"
FROM t1
WHERE t1.[Fiscal Year] = 2009
    AND t1.[Fiscal Week] < 31

Но я в растерянности, когда дело доходит до абстрагирования, чтобы заставить соединение работать.

Как я могу самостоятельно присоединиться к «самой крупной финансовой неделе, которая меньше текущего рекорда»?

Это было полезно?

Решение

Самый простой способ сделать это в Sql 2005+ — использовать функции ранжирования и оконные функции - просто разделите/упорядочите свои данные и назначьте соответствующую последовательность каждой записи (в этом случае вы разделяете по финансовому году и упорядочиваете по финансовой неделе в этом окне) - будет выглядеть примерно так:

with data as
(
    select  row_number() over (partition by a.fiscalYear order by a.fiscalWeek) as rn,
            a.fiscalYear, a.fiscalQuarter, a.fiscalWeek, a.Data
    from    #TableName a
)
select  a.fiscalYear, a.fiscalQuarter, a.fiscalWeek, a.Data, 
        a.Data - b.Data as Trend
from    data a
left join data b
on      a.fiscalYear = b.fiscalYear
and     a.rn = b.rn + 1
order by a.fiscalYear, a.rn

Этот конкретный запрос не допускает расширения за пределы границ финансового года - если вы хотите расширить границы этих лет, вам просто нужно удалить предложение «разделение по» и условие соединения «фискальный год» и вместо этого упорядочить набор с помощью комбинации финансового года. и FinancialWeek, что-то вроде этого:

with data as
(
    select  row_number() over (order by a.fiscalYear + a.fiscalWeek) as rn,
            a.fiscalYear, a.fiscalQuarter, a.fiscalWeek, a.Data
    from    #TableName a
)
select  a.fiscalYear, a.fiscalQuarter, a.fiscalWeek, a.Data, 
        a.Data - b.Data as Trend
from    data a
left join data b
on      a.rn = b.rn + 1
order by a.rn

Другие советы

Это работает?Встроенный запрос немного громоздкий, и, вероятно, есть лучший способ сделать это...

select
  [fiscal year]
, [fiscal quarter]
, [fiscal week]
, [data] 
, (
    select top 1 (i.data - t1.data) from t1 as i
    where i.[fiscal year] >= t1.[fiscal year]
    and i.[fiscal quarter] >= t1.[fiscal quarter]
    and i.[fiscal week] >= t1.[fiscal week]
    and (
          i.[fiscal year] <> t1.[fiscal year]
       or i.[fiscal quarter] <> t1.[fiscal quarter]
       or i.[fiscal week] <> t1.[fiscal week]
    )
    order by [fiscal year] asc, [fiscal quarter] asc, [fiscal week] asc
) as trend
from t1

Если вы используете SQL Server 2005, вы можете использовать CROSS APPLY пункт.

Здесь у вас может быть функция с табличным значением, которая будет возвращать строку за финансовую неделю, предшествовавшую той, что находится в текущей строке.

CREATE FUNCTION dbo.fn_GetFiscalWeekBeforeThis(@Year AS int, 
  @CurrentWeek as int)
  RETURNS TABLE
AS
RETURN
  SELECT TOP 1 *
  FROM t1
  WHERE [Fiscal Year] = @Year 
  AND [Fiscal Week] < @CurrentWeek
  ORDER BY [Fiscal Week] DESC
GO

А потом,

SELECT A.*,
A.Data - B.Data
FROM
t1 A
CROSS APPLY 
   dbo.fn_GetFiscalWeekBeforeThis(A.[Fiscal Year],  
   A.[Fiscal Week]) AS B

РЕДАКТИРОВАТЬ:Обратите внимание, что я адаптировал SQL, прочитав статью, без IDE.
Также я не знаю - как это будет работать для первого ряда.

Так что будьте любезны :)

РЕДАКТИРОВАТЬ2:Дайте мне знать, если это вообще не сработает.
Это поможет мне знать - не отвечать на вопросы, не проверив результаты.

РЕДАКТИРОВАТЬ3:Я убрал из функции необходимость в параметре Quarter.

DECLARE @Fiscal TABLE
  ( 
   FiscalYear int
  ,FiscalQuarter int
  ,FiscalWeek int
  ,[Data] decimal(4,1) 
  )

INSERT INTO @Fiscal
          ( FiscalYear, FiscalQuarter, FiscalWeek, [Data] )
SELECT 2009, 2, 22, 9.5 UNION
SELECT 2009, 2, 24, 8.8 UNION
SELECT 2009, 2, 26, 8.8 UNION
SELECT 2009, 3, 28, 8.8 UNION
SELECT 2009, 3, 31, 9.1 UNION
SELECT 2009, 3, 33, 8.8 UNION
SELECT 2010, 1, 1, 9.0 UNION
SELECT 2010, 1, 2, 9.2

;
WITH  abcd
        AS ( SELECT FiscalYear
                   ,FiscalQuarter
                   ,FiscalWeek
                   ,[Data]
                   ,row_number() OVER ( ORDER BY FiscalYear, FiscalWeek ) AS rn
             FROM   @Fiscal
           )
  SELECT  a.FiscalYear
         ,a.FiscalQuarter
         ,a.FiscalWeek
         ,a.[Data]
         ,a.[Data] - b.[Data] AS [Trend]
  FROM    abcd AS a
          LEFT JOIN abcd AS b ON b.rn = ( a.rn - 1 )
  ORDER BY a.FiscalYear
         ,a.FiscalWeek
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top