Создать диапазон дат - PullRequest
       21

Создать диапазон дат

0 голосов
/ 29 ноября 2018

Я пытаюсь сгенерировать диапазон дат на основе определенных условий.

Мои данные содержат данные о поставщике, upc, invdate и цене.Я хочу создать 1 строку, показывающую поставщика, upc, ценовую точку, начальную дату, конечную дату, пока разрыв между 1 новой и следующей ценой у любого конкретного поставщика, upc, ценовой точки составляет менее 4 дней.

МыСовсем недавно перешел на SQL Server 2016, и я не уверен, что это лучший / самый простой способ сделать это.

sample

Заранее спасибо.

Результаты должныбыть:

183020   2840000211 1.47  12/23/16 - 12/26/16
183020   2840000211 1.39  12/31/16 - 01/03/17
183020   2840000211 1.39  01/09/17 - 01/16/17

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

Это идеальный сценарий , где каждая запись в желаемом выводе представляет остров (где net_cost не изменяется, и у вас есть inv_date снимков, подтверждающих его менее чем за 4 дняпосле предыдущего).Пробелы представляют собой значения net_cost / inv_date, которые не представлены (например, мы не знаем, что было net_cost в inv_date из 2016-12-27 до 2016-12-30).

Запросниже приведены три вещи:

  1. Идентифицирует пробелы (столбец is_gap_start), проверяя, есть ли нарушения двух ограничений, изложенных в вопросе (изменение в net_cost или пробел 4дней или более значений inv_date)
  2. Назначение номера острова (столбец island_nbr) с использованием промежуточного итога обнаруженных пробелов.
  3. Определяет значения, отображаемые для каждого островав конечном результате

Ответ:

select b.vnd_nbr
, b.upc_nbr
, b.net_cost
, min(b.inv_date) as inv_date_bgn
, max(b.inv_date) as inv_date_end
from (
    select a.vnd_nbr
    , a.upc_nbr
    , a.inv_date
    , a.net_cost
    --determine the island number
    , sum(a.is_gap_start) over (partition by a.vnd_nbr, a.upc_nbr order by a.inv_date asc rows between unbounded preceding and 1 preceding) as island_nbr
    from (
        select t.vnd_nbr
        , t.upc_nbr
        , t.inv_date
        , t.net_cost
        --check if the next row meets either condition to start new date range (4 day gap, change in net_cost)
        , case when datediff(d, t.inv_date, lead(t.inv_date, 1, t.inv_date) over (partition by t.vnd_nbr, t.upc_nbr order by t.inv_date asc)) >= 4 
                    or t.net_cost <> lead(t.net_cost, 1, t.net_cost) over (partition by t.vnd_nbr, t.upc_nbr order by t.inv_date asc)
            then 1 
            else 0 
            end as is_gap_start
        from data_table as t
        ) as a
    ) as b
group by b.vnd_nbr
, b.upc_nbr
, b.net_cost
, isnull(b.island_nbr, 0) --forces each island to be a separate row
order by b.vnd_nbr
, b.upc_nbr
, isnull(b.island_nbr, 0)

Результаты:

+---------+------------+----------+--------------+--------------+
| vnd_nbr |  upc_nbr   | net_cost | inv_date_bgn | inv_date_end |
+---------+------------+----------+--------------+--------------+
|  183020 | 2840000211 | 1.47     | 2016-12-23   | 2016-12-26   |
|  183020 | 2840000211 | 1.39     | 2016-12-31   | 2017-01-03   |
|  183020 | 2840000211 | 1.39     | 2017-01-09   | 2017-01-16   |
+---------+------------+----------+--------------+--------------+
0 голосов
/ 29 ноября 2018

Это то, что я придумал и НЕ РЕШАЕТ ВАШУ ПРОБЛЕМУ ТОЧНО, но я чувствую, что мог бы опубликовать этот код, чтобы, по крайней мере, вы поработали с остальными и, возможно, получили ответ, с которым вы можете работать (помнямой комментарий)

DECLARE @TableVar TABLE 
  ( 
     vnd_nbr  INT, 
     upc_nbr  VARCHAR(10), 
     inv_date DATE, 
     net_cost DECIMAL(16, 2) 
  ) 

INSERT INTO @TableVar 
            (vnd_nbr, 
             upc_nbr, 
             inv_date, 
             net_cost) 
VALUES      (183020, 
             '2840000211', 
             '23-Dec-2016', 
             1.47), 
            (183020, 
             '2840000211', 
             '26-Dec-2016', 
             1.47), 
            (183020, 
             '2840000211', 
             '31-Dec-2016', 
             1.39), 
            (183020, 
             '2840000211', 
             '2-Jan-2017', 
             1.39), 
            (183020, 
             '2840000211', 
             '3-Jan-2017', 
             1.39), 
            (183020, 
             '2840000211', 
             '09-Jan-2017', 
             1.39), 
            (183020, 
             '2840000211', 
             '12-Jan-2017', 
             1.39), 
            (183020, 
             '2840000211', 
             '13-Jan-2017', 
             1.39), 
            (183020, 
             '2840000211', 
             '14-Jan-2017', 
             1.39), 
            (183020, 
             '2840000211', 
             '16-Jan-2017', 
             1.39) 

SELECT vnd_nbr, 
       upc_nbr, 
       net_cost, 
       Min(Isnull(previous_date, inv_date)) AS StartDate, 
       Max(inv_date)                        AS EndDate 
FROM   (SELECT vnd_nbr, 
               upc_nbr, 
               inv_date, 
               net_cost, 
               previous_date, 
               CASE 
                 WHEN Datediff(day, Isnull(previous_date, inv_date), inv_date) < 
                      4 THEN 
                 0 
                 ELSE 1 
               END GreaterThanFourDays 
        FROM   (SELECT vnd_nbr, 
                       upc_nbr, 
                       inv_date, 
                       net_cost, 
                       Lag(inv_date, 1, NULL) 
                         OVER ( 
                           partition BY vnd_nbr, upc_nbr, net_cost 
                           ORDER BY inv_date) AS previous_date 
                FROM   @TableVar) r) rr 
GROUP  BY greaterthanfourdays, 
          vnd_nbr, 
          upc_nbr, 
          net_cost 
ORDER  BY Min(inv_date) 

Вышеприведенное выводит следующее:

vnd_nbr upc_nbr net_cost    StartDate   EndDate
183020  2840000211  1.47    2016-12-23  2016-12-26
183020  2840000211  1.39    2016-12-31  2017-01-16
183020  2840000211  1.39    2017-01-03  2017-01-09

Дата начала / окончания не совпадает, но разбивает ее, если она превышает 4 дня / принимает во внимание net_cost.

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

...