SQL получает квартальные значения за квартал

#sql #fiscal #quarter

#sql #финансовый

Вопрос:

Я хотел бы получить QoQ из набора данных с данными Q3 и Q4, в котором также есть столбец даты отчета, каждая строка должна иметь значение QoQ для каждого финансового месяца (представленное датой отчета), Q4 должен сравниваться с Q3, но мое утверждение, похоже, сравнивается только в пределах одного квартала, т.Е. Q4сравнивается с Q4 вместо Q4 по сравнению с Q3..

Я использую lag функцию, но не уверен, что я делаю неправильно, если кто-нибудь может посмотреть код ниже.

  SELECT [Year], 
  [SalesDate] as Report_Date,
       [Quarter], 
       Sales,
     
       LAG(Sales,  1, 0) OVER(
       PARTITION BY [Year] ,[Quarter]
       ORDER BY [Year], 
                [Quarter],
                salesDate
                ASC) AS [QuarterSales_Offset],
                sales - LAG(Sales) OVER(
       PARTITION BY [Year] ,[Quarter]
       ORDER BY [Year], 
                [Quarter],
                salesDate
                ASC) as diff,
Case When 
LAG(Sales,1,0) OVER(
       PARTITION BY [Year],[Quarter]
       ORDER BY [Year], 
                [Quarter],
                salesDate
                ASC) = 0 then null else

(
sales - LAG(Sales,1,0) OVER(
       PARTITION BY [Year],[Quarter]
       ORDER BY [Year], 
                [Quarter],
                salesDate
                ASC))/ LAG(Sales,1,0) OVER(
       PARTITION BY [Year],[Quarter]
       ORDER BY [Year], 
                [Quarter],
                salesDate
                ASC) end as QoQ
FROM dbo.ProductSales_2;
  

Вывод запроса:

введите описание изображения здесь

Комментарии:

1. Отметьте правильную базу данных. Вы не рассказали о проблеме, с которой столкнулись.

Ответ №1:

Поскольку LAG() при смещении 1 возвращается предыдущая строка, а ваши данные находятся на уровне месяца, вы фактически сравниваете месяц за месяцем в каждом квартале. Рассмотрите другой подход, например, объединение двух подмножеств ваших данных по кварталам и месяцам в квартале.

QuarterMonth столбец может быть вычислен с ROW_NUMBER() помощью выражения (т. Е. Текущего количества месяцев в каждом квартале). Поскольку потенциально могут возникнуть месячные пробелы в данных о продажах, используйте year_quarter_month календарную таблицу, выровненную по вашему финансовому году. В целом, это позволяет сравнивать первый финансовый месяц 4 квартала ( 2020-08-31 ) с первым финансовым месяцем 3 квартала ( 2020-05-31 ) по столбцам.

 WITH unit AS (
   SELECT yqm.[Year]
        , yqm.[Quarter]
        , yqm.[Month]
        , COALESCE(p.[Report_Date], DATEADD(DAY, -1, DATEFROMPARTS(yqm.[Year], yqm.[Month] 1, 1))) AS [Report_Date]
        , p.[Sales]
   FROM year_quarter_month_table yqm
   LEFT JOIN dbo.ProductSales_2 p
      ON yq.[Year] = p.[Year]
      AND yq.[Quarter] = p.[Quarter]
      AND yq.[Month] = p.[Month]

), sub AS (
   SELECT [Year]
        , [Quarter]
        , [Month]
        , ROW_NUMBER() OVER(PARTITION BY [Year], [Quarter] 
                            ORDER BY [Report_Date]) AS [QuarterMonth]
        , [Report_Date]
        , [Sales]
   FROM unit
 )

SELECT q4.[Year]
     , q4.[Report_Date] AS Q4_Date
     , q4.[Sales] AS Q4_Sales
     , q3.[Report_Date] AS Q3_Date
     , q3.[Sales] AS Q3_Sales
     , q4.[Sales] - q3.[Sales] AS Diff
     , COALESCE((q4.[Sales] - q3.[Sales]) / q3.[Sales], 0) AS QoQ
FROM sub q4
LEFT JOIN sub q3
   ON  q4.[Year] = q3.[Year]
   AND q4.[Quarter] = 4
   AND q3.[Quarter] = 3
   AND q4.[QuarterMonth] = q3.[QuarterMonth]
  

Возможно, вы сможете выполнить обобщение для любого расчета за квартал, а не только за 3 и 4 кварталы:

 WITH sub AS (
  -- SAME CTEs AS ABOVE
)

SELECT curr_qtr.[Year]
     , curr_qtr.[Report_Date] AS Curr_Qtr_Date
     , curr_qtr.[Sales] AS Curr_Qtr_Sales
     , last_qtr.[Report_Date] AS Last_Qtr_Date
     , last_qtr.[Sales] AS Last_Qtr_Sales
     , curr_qtr.[Sales] - last_qtr.[Sales] AS Diff
     , COALESCE((curr_qtr.[Sales] - last_qtr.[Sales]) / last_qtr.[Sales], 0) AS QoQ
FROM sub curr_qtr
LEFT JOIN sub last_qtr
   ON  curr_qtr.[Year] = last_qtr.[Year]  -- ASSUMING FISCAL YEAR AND NOT CALENDAR YEAR
   AND curr_qtr.[Quarter] = last_qtr.[Quarter]   1
   AND curr_qtr.[QuarterMonth] = last_qtr.[QuarterMonth]
  

Комментарии:

1. Это решение довольно хорошо работает в сценариях, где в Q присутствуют все месяцы, поэтому в F-Q3 будут присутствовать май, июнь и июль, однако, похоже, не работает, когда в предыдущем / последнем квартале отсутствует месяц, скажем, только июль присутствует в наборе данных для F-Q3, работающего, чтобы увидетьесли я смогу манипулировать вашим приведенным выше кодом, но любой дополнительный ввод будет оценен

2. Как я уже упоминал, это решение предполагает отсутствие пропущенного месяца в каждом квартале . Чтобы заполнить пробелы, добавьте первый CTE, который слева присоединяется к фиктивной таблице календаря за год / квартал / месяц, а второй CTE основан на первой заполненной таблице с пробелами. См. Редактирование. REPORT_DATE заполняется с использованием различных функций даты для возврата последнего дня месяца. Существует много способов создания таблицы календаря (с помощью рекурсивного CTE, с помощью кода приложения, такого как Python, или вашего базового Excel). Найдите этот термин в Интернете.

3. Да, вы правы, я пропустил это предостережение о пропущенных месяцах в ваших предыдущих комментариях… Теперь я поступил так, как вы предложили… Я создал финансовый календарь, чтобы заполнить пробелы, и вывод выглядит так, как я ожидал. Очень признателен.

4. Фантастика! Приятно слышать и рад помочь. Счастливого SQLing!