Как написать эти два запроса для простого хранилища данных, используя ANSI SQL? - PullRequest
3 голосов
/ 26 мая 2010

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

В целях простоты я представлю очень упрощенные (почти тривиальные) версии таблиц, которые я здесь использую. Таблица данных о продажах является представлением и имеет следующую структуру:

CREATE TABLE sales_data (
     sales_time date NOT NULL,
     sales_amt double NOT NULL
)

Для целей этого вопроса. Я пропустил другие поля, которые вы ожидаете увидеть, например product_id, sales_person_id и т. Д., Поскольку они не имеют прямого отношения к этому вопросу. AFAICT, единственными полями, которые будут использоваться в запросе, являются поля sales_time и sales_amt (если я не ошибаюсь).

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

CREATE TABLE date_dimension (
  id integer  NOT NULL,
  datestamp   date NOT NULL,
  day_part    integer NOT NULL,
  week_part   integer NOT NULL,
  month_part  integer NOT NULL,
  qtr_part    integer NOT NULL, 
  year_part   integer NOT NULL, 
);

какие даты делятся на диапазоны отчетности.

Мне нужно написать запросы, которые позволят мне сделать следующее:

  1. Возвращает изменение в неделю на неделе sales_amt за указанный период. Например, изменение между продажами сегодня и продажами N дней назад, где N - положительное целое число (в данном случае N == 7).

  2. Возвращает изменение в изменении sales_amt за указанный период. Для в (1). мы посчитали неделю за неделей. Теперь мы хотим знать, чем это изменение отличается от изменение (неделя в неделю), рассчитанное на прошлой неделе.

Однако я застрял на этом этапе, так как SQL - мой самый слабый навык. Я был бы признателен, если бы мастер SQL мог объяснить, как я могу писать эти запросы независимо от БД (т.е. с использованием ANSI SQL).

Ответы [ 2 ]

5 голосов
/ 26 мая 2010

Как отмечалось в комментарии выше, я, вероятно, не понимаю вашу модель - поэтому вот простая для начала.

dim4_model_01_1

Теперь, если я хочу, чтобы еженедельные продажи за календарный год 2010

select 
    CalendarYearWeek
  , sum(SalesAmount)
from factSales as f
join dimDate as d on d.DateKey = f.DateKey
where Year = 2010
group by CalendarYearWeek

CalendarYearWeek - это столбец в dimDate, varchar (8), например, '2010-w03', Year - это целочисленный столбец вdimDate тоже.

Не уверен, что это близко к тому, что вы искали, но может быть началом.

РЕДАКТИРОВАТЬ

dimDate также имеет следующие столбцы:

WeekNumberInEpoch , целое число - увеличивает увеличиваетсяначиная с какой-то эпохи в прошлом.Все строки в dimDate за одну и ту же неделю имеют одинаковое значение WeekNumberInEpoch.

DayOfWeek , varchar (10) - 'воскресенье', 'понедельник', ...

DayNumberInWeek , целое число - 1-7

Использует CTE, должно работать с последними версиями PostgreSQL, SQL Server, Oracle, DB2.Для других вы можете упаковать CTE (q_00) в подзапрос.

-- for week to previous week
with
q_00 as (
    select
        WeekNumberInEpoch
      , sum(SalesAmount) as Amount
    from factSale as f
    join dimDate  as d on d.DateKey = f.DateKey
    where CalendarYear = 2010
    group by WeekNumberInEpoch
)
select
    a.WeekNumberInEpoch
  , a.Amount as ThisWeekSales
  , b.Amount as LastWeekSales
  , a.Amount - b.Amount as Difference
from q_00 as a
join q_00 as b on b.WeekNumberInEpoch = a.WeekNumberInEpoch - 1
order by a.WeekNumberInEpoch desc ;


-- for day of week to day of previous week 
-- monday to monday, tuesday to tuesday, ...
with
q_00 as (
    select
        WeekNumberInEpoch
      , DayOfWeek  
      , sum(SalesAmount) as Amount
    from factSale as f
    join dimDate  as d on d.DateKey = f.DateKey
    where CalendarYear = 2010
    group by WeekNumberInEpoch, DayOfWeek
)
select
    a.WeekNumberInEpoch
  , a.DayOfWeek  
  , a.Amount as ThisWeekSales
  , b.Amount as LastWeekSales
  , a.Amount - b.Amount as Difference
from q_00 as a
join q_00 as b on (b.WeekNumberInEpoch = a.WeekNumberInEpoch - 1
                   and b.DayOfWeek = a.DayOfWeek)
order by a.WeekNumberInEpoch desc, a.DayOfWeek ;



-- Sliding by day and day difference (= 7)
with
q_00 as (
    select
        DayNumberInEpoch
      , FullDate
      , DayOfWeek
      , sum(SalesAmount) as Amount
    from factSale as f
    join dimDate as d on d.DateKey = f.DateKey
    where CalendarYear = 2010
    group by DayNumberInEpoch, FullDate, DayOfWeek
)
select
    a.FullDate  as ThisDay
  , a.DayOfWeek as ThisDayName
  , a.Amount    as ThisDaySales
  , b.FullDate  as PreviousPeriodDay
  , b.DayOfWeek as PreviousDayName
  , b.Amount    as PreviousPeriodDaySales
  , a.Amount - b.Amount as Difference
from q_00 as a
join q_00 as b on b.DayNumberInEpoch = a.DayNumberInEpoch - 7
order by a.FullDate desc ;
2 голосов
/ 26 мая 2010

Я предлагаю вам создать отдельную таблицу измерений для «времени» (один день на строку, содержащую информацию о повторяющихся периодах времени (день, неделя, месяц, квартал), чтобы вы могли легко объединять / выбирать для этого типа информации.

Ваши запросы для (1.) и (2.) могут быть построены таким образом.

Да, большинство диалектов SQL позволяют выводить эту информацию с помощью функции времени / даты ... но они медленнее (-er) и сложнее, чем использование таблицы измерений ....

...