Нерелационно решение
Не мисля, че някой от другите отговори е правилен.
-
GROUP BY
няма да работи -
Използване на
ROW_NUMBER()
принуждава данните в структура на системата за архивиране на записи, която е физическа, и след това ги обработва като физически записи. При огромна цена за производителност. Разбира се, за да напишете такъв код, той ви принуждава да размислите по отношение на RFS вместо да мислим в релационни термини. -
Използването на CTEs е същото. Итерация през данните, особено данни, които не се променят. На малко по-различна огромна цена.
-
Курсорите определено са грешно нещо поради различни причини. (a) Курсорите изискват код, а вие сте поискали изглед (b) Курсорите изоставят механизма за обработка на набори и се връщат към обработка ред по ред. Отново не е задължително. Ако разработчик в някой от моите екипи използва курсори или временни таблици в релационна база данни (т.е. не система за архивиране на записи), аз ги снимам.
Релационно решение
-
Вашите данни е Релационна, логична, двете дадени данни колони са всичко, което е необходимо.
-
Разбира се, трябва да формираме изглед (получена релация), за да получим желания отчет, но той се състои от чисти SELECT, което е доста различно от обработката (преобразуването му във файл , което е физическо, и след това обработвафайла; или временни таблици; или работни маси; или CTEs; или ROW_Number(); и др.).
-
Противно на оплакванията на "теоретици", които имат дневен ред, SQL се справя перфектно с релационните данни. И вашите данни са релационни.
Затова поддържайте релационен начин на мислене, релационен изглед на данните и манталитет за обработка на набори. Всяко изискване за отчет върху релационна база данни може да бъде изпълнено с помощта на един SELECT. Няма нужда да се връщате към методите за обработка на файлове от преди 1970 г. ISAM.
Предполагам, че първичният ключ (наборът от колони, които дават уникалност на релационния ред) е Date,
и въз основа на дадените примерни данни, типът на данните е DATE.
Опитайте това:
CREATE VIEW MyTable_Base_V -- Foundation View
AS
SELECT Date,
Date_Next,
Price
FROM (
-- Derived Table: project rows with what we need
SELECT Date,
[Date_Next] = DATEADD( DD, 1, O.Date ),
Price,
[Price_Next] = (
SELECT Price -- NULL if not exists
FROM MyTable
WHERE Date = DATEADD( DD, 1, O.Date )
)
FROM MyTable MT
) AS X
WHERE Price != Price_Next -- exclude unchanging rows
GO
CREATE VIEW MyTable_V -- Requested View
AS
SELECT [Date_From] = (
-- Date of the previous row
SELECT MAX( Date_Next ) -- previous row
FROM MyTable_V
WHERE Date_Next < MT.Date
),
[Date_To] = Date, -- this row
Price
FROM MyTable_Base_V MT
GO
SELECT *
FROM MyTable_V
GO
Метод, общ
Разбира се, това е метод, следователно е общ, може да се използва за определяне на From_
и To_
на всеки диапазон от данни (тук Date
диапазон), въз основа на всяка промяна на данните (тук промяна в Price
). ).
Ето вашите Dates
са последователни, така че определянето на Date_Next
е просто:увеличете Date
до 1 ден. Ако PK се увеличава, но не последователни (напр. DateTime
или TimeStamp
или някакъв друг ключ), променете извлечената таблица X
до:
-- Derived Table: project rows with what we need
SELECT DateTime,
[DateTime_Next] = (
-- first row > this row
SELECT TOP 1
DateTime -- NULL if not exists
FROM MyTable
WHERE DateTime > MT.DateTime
),
Price,
[Price_Next] = (
-- first row > this row
SELECT TOP 1
Price -- NULL if not exists
FROM MyTable
WHERE DateTime > MT.DateTime
)
FROM MyTable MT
Насладете се.
Моля, не се колебайте да коментирате, да задавате въпроси и т.н.