Solusi Non-relasional
Saya tidak berpikir ada jawaban lain yang benar.
-
GROUP BY
tidak akan berfungsi -
Menggunakan
ROW_NUMBER()
memaksa data ke dalam struktur Sistem Pengarsipan Rekam, yang bersifat fisik, dan kemudian memprosesnya sebagai arsip fisik. Dengan biaya kinerja yang besar. Tentu saja, untuk menulis kode seperti itu, Anda harus berpikir dalam hal RFS daripada berpikir dalam istilah Relasional. -
Menggunakan CTE adalah sama. Iterasi melalui data, terutama data yang tidak berubah. Dengan biaya besar yang sedikit berbeda.
-
Kursor jelas merupakan hal yang salah karena serangkaian alasan yang berbeda. (a) Kursor memerlukan kode, dan Anda telah meminta Tampilan (b) Kursor meninggalkan mesin pemrosesan set, dan kembali ke pemrosesan baris demi baris. Sekali lagi, tidak wajib. Jika seorang pengembang di salah satu tim saya menggunakan kursor atau tabel sementara pada Basis Data Relasional (yaitu, bukan Sistem Pengarsipan Catatan), saya memotret mereka.
Solusi Relasional
-
Data Your Anda adalah Relasional, logis, keduanya memberikan data kolom adalah semua yang diperlukan.
-
Tentu, kita harus membentuk View (Relasi turunan), untuk mendapatkan laporan yang diinginkan, tetapi itu terdiri dari SELECT murni, yang sangat berbeda dengan pemrosesan (mengonversinya menjadi file , yang bersifat fisik, lalu memproses file; atau tabel temp; atau meja kerja; atau CTE; atau ROW_Number(); dll).
-
Berlawanan dengan ratapan "para ahli teori", yang memiliki agenda, SQL menangani data Relasional dengan sangat baik. Dan data Anda adalah Relasional.
Oleh karena itu, pertahankan pola pikir relasional, pandangan relasional dari data, dan mentalitas pemrosesan yang ditetapkan. Setiap persyaratan laporan melalui Database Relasional dapat dipenuhi menggunakan satu SELECT. Tidak perlu mundur ke metode penanganan File ISAM sebelum tahun 1970.
Saya akan menganggap Kunci Utama (kumpulan kolom yang memberikan keunikan baris Relasional) adalah Date,
dan berdasarkan contoh data yang diberikan, Tipe Datanya adalah DATE.
Coba ini:
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
Metode, Umum
Tentu saja ini adalah metode, oleh karena itu generik, dapat digunakan untuk menentukan From_
dan To_
rentang data apa pun (di sini, Date
rentang), berdasarkan perubahan data apa pun (di sini, perubahan Price
).
Di sini, Date
berturut-turut, jadi penentuan Date_Next
sederhana:tambahkan Date
dengan 1 hari. Jika PK meningkat tetapi tidak berturut-turut (mis. DateTime
atau TimeStamp
atau beberapa Kunci lainnya), ubah Tabel Turunan X
ke:
-- 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
Selamat menikmati.
Silakan berkomentar, mengajukan pertanyaan, dll.