Saya membuat SQL Fiddle untuk pertanyaan ini jika itu membuat segalanya lebih mudah bagi siapa pun.
Saya memiliki semacam database olahraga fantasi dan apa yang saya coba cari tahu adalah bagaimana menghasilkan data "arus beruntun" (seperti 'W2' jika tim telah memenangkan 2 pertarungan terakhir mereka, atau 'L1' jika mereka kalah pertarungan terakhir mereka setelah memenangkan pertarungan sebelumnya - atau 'T1' jika mereka mengikat pertarungan terbaru mereka).
Ini skema dasar saya:
CREATE TABLE FantasyTeams (
team_id BIGINT NOT NULL
)
CREATE TABLE FantasyMatches(
match_id BIGINT NOT NULL,
home_fantasy_team_id BIGINT NOT NULL,
away_fantasy_team_id BIGINT NOT NULL,
fantasy_season_id BIGINT NOT NULL,
fantasy_league_id BIGINT NOT NULL,
fantasy_week_id BIGINT NOT NULL,
winning_team_id BIGINT NULL
)
Nilai NULL
di winning_team_id
kolom menunjukkan dasi untuk pertandingan itu.
Berikut ini contoh pernyataan DML dengan beberapa data sampel untuk 6 tim dan 3 minggu pertandingan:
INSERT INTO FantasyTeams
SELECT 1
UNION
SELECT 2
UNION
SELECT 3
UNION
SELECT 4
UNION
SELECT 5
UNION
SELECT 6
INSERT INTO FantasyMatches
SELECT 1, 2, 1, 2, 4, 44, 2
UNION
SELECT 2, 5, 4, 2, 4, 44, 5
UNION
SELECT 3, 6, 3, 2, 4, 44, 3
UNION
SELECT 4, 2, 4, 2, 4, 45, 2
UNION
SELECT 5, 3, 1, 2, 4, 45, 3
UNION
SELECT 6, 6, 5, 2, 4, 45, 6
UNION
SELECT 7, 2, 6, 2, 4, 46, 2
UNION
SELECT 8, 3, 5, 2, 4, 46, 3
UNION
SELECT 9, 4, 1, 2, 4, 46, NULL
GO
Berikut adalah contoh dari output yang diinginkan (berdasarkan DML di atas) yang saya mengalami kesulitan bahkan mulai mencari cara untuk mendapatkan:
| TEAM_ID | STEAK_TYPE | STREAK_COUNT |
|---------|------------|--------------|
| 1 | T | 1 |
| 2 | W | 3 |
| 3 | W | 3 |
| 4 | T | 1 |
| 5 | L | 2 |
| 6 | L | 1 |
Saya sudah mencoba berbagai metode menggunakan subqueries dan CTE tetapi saya tidak bisa menggabungkannya. Saya ingin menghindari menggunakan kursor karena saya dapat memiliki dataset besar untuk menjalankan ini melawan di masa depan. Saya merasa mungkin ada cara yang melibatkan variabel tabel yang menggabungkan data ini ke dirinya sendiri, tetapi saya masih mengerjakannya.
Info Tambahan: Mungkin ada jumlah tim yang bervariasi (angka genap antara 6 dan 10) dan total pertarungan akan meningkat sebesar 1 untuk setiap tim setiap minggu. Ada ide tentang bagaimana saya harus melakukan ini?
sumber
bigint
untuk begitu banyak kolom di manaint
mungkin akan melakukan 3) mengapa semua_
s ?! 4) Saya lebih suka nama tabel tunggal tetapi mengakui tidak semua orang setuju dengan saya // tapi selain itu yang Anda tunjukkan di sini terlihat masuk akal, yaJawaban:
Karena Anda menggunakan SQL Server 2012, Anda dapat menggunakan beberapa fungsi windowing baru.
SQL Fiddle
C1
menghitungstreak_type
untuk setiap tim dan pertandingan.C2
menemukan yang sebelumnyastreak_type
dipesan olehmatch_id desc
.C3
menghasilkan jumlah berjalan yangstreak_sum
dipesan denganmatch_id desc
mempertahankan0
selamastreak_type
sama dengan nilai terakhir.Permintaan jumlah utama sampai garis-garis di mana
streak_sum
adalah0
.sumber
LEAD()
. Tidak cukup banyak orang tahu tentang fungsi-fungsi windowing baru pada 2012FantasyTeams JOIN FantasyMatches
denganFantasyMatches CROSS APPLY (VALUES (home_fantasy_team_id), (away_fantasy_team_id))
demikian berpotensi meningkatkan kinerja.FantasyTeams
itu, mungkin lebih baik bergabung dalam permintaan utama.Salah satu pendekatan intuitif untuk menyelesaikan masalah ini adalah:
Strategi ini mungkin menang atas solusi fungsi jendela (yang melakukan pemindaian penuh data) karena tabel tumbuh lebih besar, dengan asumsi strategi rekursif diterapkan secara efisien. Kunci keberhasilan adalah menyediakan indeks yang efisien untuk menemukan baris dengan cepat (menggunakan pencarian) dan menghindari pengurutan. Indeks yang dibutuhkan adalah:
Untuk membantu dalam optimasi kueri, saya akan menggunakan tabel sementara untuk menahan baris yang diidentifikasi sebagai bagian dari rangkaian beruntun saat ini. Jika goresan biasanya pendek (seperti halnya untuk tim yang saya ikuti, sayangnya) tabel ini harus cukup kecil:
Solusi kueri rekursif saya adalah sebagai berikut ( SQL Fiddle di sini ):
Teks T-SQL cukup panjang, tetapi setiap bagian dari kueri terkait erat dengan garis besar proses yang diberikan pada awal jawaban ini. Permintaan dibuat lebih lama dengan kebutuhan untuk menggunakan trik tertentu untuk menghindari jenis dan untuk menghasilkan
TOP
bagian rekursif dari permintaan (yang biasanya tidak diizinkan).Paket eksekusi relatif kecil dan sederhana jika dibandingkan dengan kueri. Saya telah memberi warna kuning pada area jangkar, dan bagian rekursif berwarna hijau pada tangkapan layar di bawah ini:
Dengan deretan baris yang ditangkap dalam tabel sementara, mudah untuk mendapatkan hasil ringkasan yang Anda butuhkan. (Menggunakan tabel sementara juga menghindari tumpahan pengurutan yang mungkin terjadi jika kueri di bawah ini dikombinasikan dengan permintaan rekursif utama)
Kueri yang sama dapat digunakan sebagai dasar untuk memperbarui
FantasyTeams
tabel:Atau, jika Anda lebih suka
MERGE
:Salah satu pendekatan menghasilkan rencana eksekusi yang efisien (berdasarkan jumlah baris yang diketahui dalam tabel sementara):
Akhirnya, karena metode rekursif secara alami menyertakan
match_id
dalam pemrosesan, mudah untuk menambahkan daftarmatch_id
s yang membentuk setiap goresan ke output:Keluaran:
Rencana eksekusi:
sumber
EXISTS (... INTERSECT ...)
bukan hanyaStreaks.streak_type = CASE ...
? Saya tahu metode mantan dapat berguna ketika Anda harus mencocokkan NULLs di kedua sisi serta nilai-nilai tapi tidak seolah-olah bagian kanan bisa menghasilkan NULLs apapun dalam hal ini, jadi ...CASE
digunakan, pengoptimal tidak dapat menggunakan gabungan penggabungan (yang mempertahankan urutan kunci gabungan) dan menggunakan penggabungan ditambah jenis sebagai gantinya.Cara lain untuk mendapatkan hasilnya adalah dengan CTE rekursif
Demo SQLFiddle
sumber