Оператор условного выполнения итогового SQL: для каждого отдельного месяца в наборе записей транзакций получить сумму столбца за последние двенадцать месяцев - PullRequest
0 голосов
/ 22 апреля 2019

Существует таблица транзакций, которая содержит датированные данные за 2006 - 2019 гг., Количество записей от нуля до многих за каждый месяц (сумма продажи). Требование - это оператор SQL, который за каждый месяц дает мне сумму продаж за последние двенадцать месяцев и количество отдельных месяцев, которые содержат значения.

Ниже показано, что SQL до сих пор (это немного мутно, потому что дата хранится в отдельной таблице, а дата должна исходить из пакета)

WITH monthly_totals AS 
(SELECT  
    sum(t1.[Transaction_totals]) AS sum_of_sales, 
    CASE 
        WHEN t2.month_id % 100 < 10 AND t2.month_id/100 < 10 THEN CONCAT('200', t2.month_id % 100, '-0', t2.month_id / 100, '-01')
        WHEN t2.month_id % 100 < 10 AND t2.month_id/100 >= 10 THEN CONCAT('200', t2.month_id % 100, '-', t2.month_id / 100, '-01')
        WHEN t2.month_id % 100 >= 10 AND t2.month_id/100 < 10 THEN CONCAT('20', t2.month_id % 100, '-0',t2. month_id / 100, '-01')
        ELSE CONCAT('20', t2.month_id % 100, '-', t2.month_id / 100, '-01')
    END as date, 
    t2.month_id
FROM 
    TRANSACTION t1
INNER JOIN
    BATCH  t2 ON t1.batch_id = t2.batch_id
GROUP BY 
    CASE 
        WHEN t2.month_id % 100 < 10 AND t2.month_id/100 < 10 THEN CONCAT('200', t2.month_id % 100, '-0', t2.month_id / 100, '-01')
        WHEN t2.month_id % 100 < 10 AND t2.month_id/100 >= 10 THEN CONCAT('200', t2.month_id % 100, '-', t2.month_id / 100, '-01')
        WHEN t2.month_id % 100 >= 10 AND t2.month_id/100 < 10 THEN CONCAT('20', t2.month_id % 100, '-0',t2. month_id / 100, '-01')
        ELSE CONCAT('20', t2.month_id % 100, '-', t2.month_id / 100, '-01')
    END, 
    t2.month_id
) 
SELECT 
    sum(sum_of_sales) AS sum_of_sales, 
    count(distinct month_id) as month_count, 
    date
FROM 
    monthly_totals
WHERE 
date IN (select distinct month_id
        from 
            vw_dimDate as d
        where 
            date >= (
                select 
                    distinct(date)
                from 
                    dimDate
                where 
                    month_id = month_id
                    and dayNumber = 1) - 365
        and 
            date <= (
                select 
                    distinct(date)
                from 
                    dimDate
                where 
                    month_id = month_id
                    and dayNumber = 1
            )
        )
GROUP BY 
    date

Но это вызывает следующую ошибку: Подзапрос вернул более 1 значения. Это недопустимо, если подзапрос следует =,! =, <, <=,>,> = Или когда подзапрос используется в качестве выражения.

Для таблицы, охватывающей 13 лет, конечный продукт должен выглядеть примерно так:

2006-01-01: 2 382 823 долл. США [сумма продаж за 2005-01-01 - 2006-01-01], 1 [количество транзакций в разных месяцах]

2006-02-01 $ 4 382 823 [сумма продаж за 2005-02-01 - 2006-02-01], 2 [количество транзакций в разных месяцах]

2006-03-01 $ 4 382 823 [сумма продаж за 2005-03-01 - 2006-03-01], 3 [количество транзакций в разных месяцах]

... 2010-01-01: 23 323 204 долл. США [сумма продаж за 2009-01-01 - 2010-01-01], 12 [количество транзакций в разных месяцах]

2011-01-01: 12 938 823 долл. США [сумма продаж за 2009-02-01 - 2010-02-01], 12 [количество транзакций в разных месяцах]

и т.д ... за каждый месяц в таблице

Ответы [ 4 ]

1 голос
/ 22 апреля 2019

Просто интересно, лучше ли, если бы у вас была таблица дат, управляющая этой таблицей, и вы присоединили к ней свою таблицу транзакций, то вы сможете использовать Sum Partition By для каждых предыдущих 12 месяцев и считать, где транзакция <> 0 ... что если вы присоединиться ниже к таблице.

Другие парни на этом сайте наверняка будут знать, сработает ли это.

with years as (
     select * from 
     (values(2006),(2007),(2008),(2009),(2010),(2011),(2012),(2013),(2014),(2015),(2016),(2017),(2018),(2019)
     ) as t (Year_id))
,months as (
     select * from 
     (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
     ) as t (month_id))
select Year_id,month_id,0 as [Transaction_totals]
from years
cross join months
order by 1,2
0 голосов
/ 23 апреля 2019

Спасибо, Роджер, Стуфан и доктор Старк за ваши рекомендации. Не будучи знакомым с перекрестными соединениями, я вчера пошел по другому пути и нашел альтернативное решение. Но, посмотрев таблицы дат, вы показали примеры того, как создать, если бы я сделал это сегодня, я мог бы пойти по этому пути. Для справки, вот как я решил это: (в основном дважды использовал один и тот же набор данных месячных итогов, что позволило в первом наборе данных указать даты, а во втором - в качестве скользящего среднегодового значения)

С помесячной_счетом КАК (SELECT
sum (t1. [Transaction_totals]) AS sum_of_sales, t5.date, Код товара, t1.store_id

FROM СДЕЛКИ t1

INNER JOIN BATCH t2 ON t1.batch_id = t2.batch_id

INNER JOIN vw_dimDate t5 ON t4.month_id = t5.month_id AND t4.year = t5.year AND t5.dayNumber = 1

GROUP BY t5.date, Код товара, t1.store_id ), year_totals as ( ВЫБРАТЬ t1.date, t1.store_id, t1.product_id, sum (t2.sum_of_sales) AS sum_of_sales, count (отличный t2.date) как month_count

FROM месячные_отчета t1

INNER JOIN month_totals t2 ON t2.date> DATEADD (год, -1, CONVERT (DATE, t1.date)) и t2.date <= CONVERT (DATE, t1.date) AND t1.store_id = t2.store_id AND t1.product_id = t2.product_id </p>

GROUP BY t1.date, t1.store_id, t1.product_id

) ВЫБРАТЬ Дата, store_id, Код товара, sum_of_sales / month_count * 12 как sum_of_sales, month_count

ЗАКАЗАТЬ t1.date, store_id, product_id

0 голосов
/ 23 апреля 2019
WITH CTE AS (
   SELECT 2006 AS Year
  UNION ALL
  SELECT Year + 1 FROM CTE  WHERE Year < 2019
 ),CTE2 AS (
 SELECT 1 AS Month
 UNION ALL
 SELECT Month + 1 FROM CTE2  WHERE Month < 12
 )
 select dateadd(mm,datediff(mm,-1,dateadd(year,-1,convert(varchar,year)+'- '+convert(varchar,Month)+'-'+'1')),-1)start_Date,
dateadd(mm,datediff(mm,-1,convert(varchar,year)+'-'+convert(varchar,Month)+'-  '+'1'),-1)End_Date
  from CTE 
cross join CTE2
order by 1
OPTION (MAXRECURSION 0)
0 голосов
/ 22 апреля 2019

Следуя предложению Роджера Клеркуэлла, я сначала создал бы таблицу дат с использованием блока With (CTE), чтобы затем использовать его в оставшейся части запроса. Это позволит вам запрашивать данные на основе дат, извлекаемых из таблицы дат.

Поскольку я работаю с базой данных Oracle, мое решение показывает, как создать таблицу дат, которая создает список дат начала месяца для диапазона дат, введенного в запрос. Он также может давать даты окончания месяца, однако я понимаю, что для этого вопроса дни окончания месяца не нужны. Я написал бесчисленное количество отчетов, где я использовал это. С некоторыми небольшими изменениями этот код может также выдавать отдельные дни, если вам нужно запрашивать результаты изо дня в день, а также все виды других полезных хаков, как только вы полностью поймете CONNECT BY LEVEL.

SELECT TRUNC(ADD_MONTHS('01-JUL-18', LEVEL-1), 'MM') START_DATE,
       LAST_DAY(ADD_MONTHS('01-JUL-18', LEVEL-1)) END_DATE
FROM DUAL CONNECT BY LEVEL <= CEIL(MONTHS_BETWEEN('30-JUN-19', '01-JUL-18'))
;

Код выдаст результаты, похожие на скриншот ниже. enter image description here

SQL Server, однако, не нужно использовать таблицу dual. См. THIS Вопрос Stackoverflow, если у вас есть вопросы по поводу двойной таблицы.

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