Solución no relacional
No creo que ninguna de las otras respuestas sea correcta.
-
GROUP BY
no funcionará -
Usando
ROW_NUMBER()
fuerza los datos en una estructura de sistema de archivo de registros, que es física, y luego los procesa como registros físicos. A un costo de rendimiento masivo. Por supuesto, para escribir dicho código, te obliga a pensar en términos de RFS en lugar de pensar en términos relacionales. -
Usar CTE es lo mismo. Iterando a través de los datos, especialmente los datos que no cambian. A un costo masivo ligeramente diferente.
-
Los cursores definitivamente son algo incorrecto por un conjunto diferente de razones. (a) Los cursores requieren código y usted ha solicitado una Vista (b) Los cursores abandonan el motor de procesamiento de conjuntos y vuelven al procesamiento fila por fila. Nuevamente, no es obligatorio. Si un desarrollador de alguno de mis equipos usa cursores o tablas temporales en una base de datos relacional (es decir, no en un sistema de archivo de registros), le disparo.
Solución Relacional
-
Tus datos es relacional, lógico, los dos dados datos las columnas son todo lo que se necesita.
-
Claro, tenemos que formar una Vista (Relación derivada) para obtener el informe deseado, pero eso consiste en SELECCIONES puras, que es bastante diferente al procesamiento (convertirlo en un archivo , que es físico, y luego procesa el archivo; o tablas temporales; o mesas de trabajo; o CTE; o FILA_Número(); etc.).
-
Contrariamente a las lamentaciones de los "teóricos", que tienen una agenda, SQL maneja perfectamente los datos relacionales. Y sus datos son relacionales.
Por lo tanto, mantenga una mentalidad relacional, una visión relacional de los datos y una mentalidad de procesamiento de conjuntos. Cada requisito de informe sobre una base de datos relacional se puede cumplir con un solo SELECT. No hay necesidad de regresar a los métodos de manejo de archivos ISAM anteriores a 1970.
Asumiré que la clave principal (el conjunto de columnas que dan un carácter único a una fila relacional) es Date,
y según los datos de ejemplo proporcionados, el tipo de datos es DATE.
Prueba esto:
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
Método, Genérico
Por supuesto, este es un método, por lo tanto, es genérico, se puede usar para determinar el From_
y To_
de cualquier rango de datos (aquí, una Date
rango), basado en cualquier cambio de datos (aquí, un cambio en Price
).
Aquí, sus Dates
son consecutivos, por lo que la determinación de Date_Next
es simple:incrementa la Date
por 1 día. Si el PK está aumentando pero no consecutivos (por ejemplo, DateTime
o TimeStamp
o alguna otra Clave), cambie la Tabla Derivada X
a:
-- 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
Disfruta.
No dude en comentar, hacer preguntas, etc.