Diberikan data berikut:
create table #histories
(
username varchar(10),
account varchar(10),
assigned date
);
insert into #histories
values
('PHIL','ACCOUNT1','2017-01-04'),
('PETER','ACCOUNT1','2017-01-15'),
('DAVE','ACCOUNT1','2017-03-04'),
('ANDY','ACCOUNT1','2017-05-06'),
('DAVE','ACCOUNT1','2017-05-07'),
('FRED','ACCOUNT1','2017-05-08'),
('JAMES','ACCOUNT1','2017-08-05'),
('DAVE','ACCOUNT2','2017-01-02'),
('PHIL','ACCOUNT2','2017-01-18'),
('JOSH','ACCOUNT2','2017-04-08'),
('JAMES','ACCOUNT2','2017-04-09'),
('DAVE','ACCOUNT2','2017-05-06'),
('PHIL','ACCOUNT2','2017-05-07') ;
... yang mewakili ketika pengguna tertentu ditugaskan ke akun.
Saya ingin mengetahui siapa yang memiliki akun tertentu pada hari terakhir setiap bulan (tanggal yang ditentukan adalah tanggal dimana akun mengalihkan kepemilikan), dengan setiap akhir bulan yang hilang diisi (mungkin dibuat dari dates
tabel praktis yang saya miliki, dengan kolom yang bermanfaat DateKey
, Date
dan LastDayOfMonth
, [milik @AaronBertrand]) 1 .
Hasil yang diinginkan adalah:
PETER, ACCOUNT1, 2017-01-31
PETER, ACCOUNT1, 2017-02-28
DAVE, ACCOUNT1, 2017-03-31
DAVE, ACCOUNT1, 2017-04-30
FRED, ACCOUNT1, 2017-05-31
FRED, ACCOUNT1, 2017-06-30
FRED, ACCOUNT1, 2017-07-31
JAMES, ACCOUNT1, 2017-08-31
PHIL, ACCOUNT2, 2017-01-31
PHIL, ACCOUNT2, 2017-02-28
PHIL, ACCOUNT2, 2017-03-31
JAMES, ACCOUNT2, 2017-04-30
PHIL, ACCOUNT2, 2017-05-31
Melakukan bagian awal dari ini dengan fungsi windowing adalah sepele, itu menambahkan baris "hilang" yang saya perjuangkan.
2017-05
karena ia sudah punya2017-05-07
dan tidak ada pemegang berikutnya?Jawaban:
Salah satu pendekatan untuk masalah ini adalah dengan melakukan hal berikut:
LEAD
pada SQL Server 2008. Anda dapat menggunakanAPPLY
atau suquery untuk ini.Saya memodifikasi data pengujian Anda sedikit untuk membuat hasilnya deterministik. Juga menambahkan indeks:
Berikut tabel dimensi tanggal paling malas sepanjang masa:
Untuk langkah 1, ada banyak cara untuk ditiru
LEAD
. Inilah satu metode:Untuk langkah 2, kita perlu mengubah nilai NULL ke yang lain. Anda ingin memasukkan bulan terakhir untuk setiap akun, jadi menambahkan satu bulan ke tanggal mulai sudah cukup:
Untuk langkah 3, kita bisa bergabung ke tabel dimensi tanggal. Kolom dari tabel dimensi adalah persis kolom yang Anda butuhkan untuk set hasil:
Saya tidak suka permintaan yang saya dapatkan ketika saya menggabungkan semuanya. Mungkin ada masalah dengan pesanan gabungan saat menggabungkan
OUTER APPLY
danINNER JOIN
. Untuk mendapatkan pesanan bergabung, saya ingin saya menulis ulang dengan sebuah subquery:Saya tidak tahu berapa banyak data yang Anda miliki sehingga mungkin tidak masalah bagi Anda. Tapi rencananya terlihat seperti yang saya inginkan:
Hasilnya cocok dengan Anda:
sumber
Di sini saya tidak menggunakan tabel kalender tetapi tabel angka alami nums.dbo.nums (Saya harap Anda juga mendapatkannya, jika tidak, dapat dengan mudah dibuat)
Saya memiliki jawaban yang sedikit berbeda dari milik Anda ('JOSH' <-> 'JAMES') karena data Anda berisi 2 baris ini:
dengan akun yang sama dan tanggal yang ditentukan dan Anda tidak tahu mana yang harus diambil adalah situasi ini.
sumber
Ini tidak berarti solusi yang tampak bersih, tetapi tampaknya memberikan hasil yang Anda cari (saya yakin orang lain akan memiliki pertanyaan yang bagus, bersih, sepenuhnya dioptimalkan untuk Anda).
sumber
Saya menggunakan tabel dimensi tanggal dari Aaron Bertrand, seperti yang Anda juga sebutkan dalam pertanyaan Anda (yang merupakan tabel yang sangat berguna untuk skenario seperti itu) dan saya menulis kode berikut:
Saya menambahkan
EndOfMonth
kolom ke#dim
tabel (tepat setelahFirstOfMonth
kolom) menggunakan kode berikut:Dan solusinya:
sumber
Triangle BERGABUNG untuk kemenangan!
Hasilnya adalah:
Rencana Eksekusi Interaktif di sini.
Statistik I / O dan TIME (memotong semua nilai nol setelah pembacaan logis):
Kueri untuk membuat tabel temp yang diperlukan dan menguji pernyataan T-SQL yang saya sarankan:
sumber