Самостоятельное присоединение к переменным данным
-
12-09-2019 - |
Вопрос
У меня есть таблица со следующими данными:
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