Мин. / Макс. Значения даты в большом диапазоне дат в зависимости от значения - PullRequest
7 голосов
/ 10 июля 2019

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

Конечная игра состоит в том, чтобы определитьминимальная и максимальная даты, когда клиент находился в значении £ 0.

Первоначально я пытался сгруппировать MIN (Дата) и Макс (Дата) по Клиенту и Значению.Однако, если клиент упал до £ 0 в разных диапазонах дат, он вернул бы максимум самого последнего диапазона дат и минимум самого раннего, вместо идеального - вернул оба диапазона, где он был £ 0.

Я пытался использовать DENSE_RANK () для разделения каждого значения клиента, но при этом просто ранжировал все значения £ 0 в одном и том же ранге.

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

DROP TABLE IF EXISTS #SnapshotTable
CREATE TABLE #SnapshotTable
(
    Row_ID INT IDENTITY(1,1)
    ,SnapshotDate DATE
    ,SnapshotDateKey INT
    ,CustomerId INT
    ,Value DECIMAL(18,2)
)
INSERT INTO #SnapshotTable (SnapshotDate, SnapshotDateKey, CustomerId, Value)
SELECT '2019-01-01', 20190101, 1, 0.00
UNION SELECT '2019-01-02', 20190102, 1, 0.00
UNION SELECT '2019-01-03', 20190103, 1, 5.00
UNION SELECT '2019-01-04', 20190104, 1, 5.00
UNION SELECT '2019-01-05', 20190105, 1, 3.00
UNION SELECT '2019-01-06', 20190106, 1, 3.00
UNION SELECT '2019-01-07', 20190107, 1, 0.00
UNION SELECT '2019-01-08', 20190108, 1, 0.00
UNION SELECT '2019-01-09', 20190109, 1, 10.00
UNION SELECT '2019-01-10', 20190110, 1, 0.00

SELECT * FROM #SnapshotTable

-- Code that doesn't work correctly
SELECT
    CustomerId
    ,Value
    ,MinDate = MIN(SnapshotDateKey)
    ,MaxDate = MAX(SnapshotDateKey)
FROM #SnapshotTable
GROUP BY
    CustomerId
    ,Value

-- Attempted with dense rank
ALTER TABLE #SnapshotTable
ADD DenseRankTest INT NULL
GO
-- Update with Dense Rank
UPDATE TGT
SET 
    TGT.DenseRankTest = SRC.NewRank
FROM #SnapshotTable TGT
INNER JOIN (SELECT
                Row_ID
                ,NewRank = DENSE_RANK() OVER (PARTITION BY CustomerId ORDER BY Value ASC)
            FROM #SnapshotTable

            ) AS SRC
    ON SRC.Row_ID = TGT.Row_ID 

SELECT * FROM #SnapshotTable

Теперь я вижу, что функция density_rank () вроде как работает, как я хочу, но, честно говоря, я смотрел наэто ненадолго, и я не могу понять, как это сделать правильно.

Может кто-нибудь посоветовать, что мне нужно делать?

Я ожидаю увидеть:

SELECT [StartDateKey] = 20190101, [EndDateKey] = 20190102, [CustomerId] = 1, [Value] = 0
UNION SELECT [StartDateKey] = 20190103, [EndDateKey] = 20190104, [CustomerId] = 1, [Value] = 5
UNION SELECT [StartDateKey] = 20190105, [EndDateKey] = 20190106, [CustomerId] = 1, [Value] = 3
UNION SELECT [StartDateKey] = 20190107, [EndDateKey] = 20190108, [CustomerId] = 1, [Value] = 0
UNION SELECT [StartDateKey] = 20190109, [EndDateKey] = 20190109, [CustomerId] = 1, [Value] = 10
UNION SELECT [StartDateKey] = 20190120, [EndDateKey] = 20190110, [CustomerId] = 1, [Value] = 0

Редактировать: Для тех, кто наткнулся на это, с помощью людей здесь я нашел это как хорошее чтение для понимания проблемы / решения проблемы.

1 Ответ

2 голосов
/ 10 июля 2019

Это проблема пробелов и островков. Но принятый ответ на предполагаемом дубликате - просто не лучший способ приблизиться к этому. И ответ с более высоким рейтингом все еще слишком сложен.

Гораздо более простой метод:

select customerid, value, min(SnapshotDateKey), max(SnapshotDateKey)
from (select st.*,
             row_number() over (partition by customerid, value order by snapshotdate) as seqnum
      from snapshottable st
     ) st
group by dateadd(day, -seqnum, snapshotdate), customerid, value
order by min(SnapshotDateKey);

Здесь - это дБ <> скрипка.

...