Saya menulis pernyataan kasus dengan> 100 pilihan di mana saya menggunakan pernyataan yang sama di 4 tempat dalam permintaan sederhana.
Kueri yang sama dua kali dengan penyatuan di antara mereka tetapi juga melakukan penghitungan dan karenanya grup juga berisi pernyataan kasus.
Ini untuk memberi label ulang beberapa nama perusahaan di mana catatan yang berbeda untuk perusahaan yang sama dieja secara berbeda.
Saya mencoba mendeklarasikan variabel sebagai VarChar (MAX)
declare @CaseForAccountConsolidation varchar(max)
SET @CaseForAccountConsolidation = 'CASE
WHEN ac.accountName like ''AIR NEW Z%'' THEN ''AIR NEW ZEALAND''
WHEN ac.accountName LIKE ''AIR BP%'' THEN ''AIR BP''
WHEN ac.accountName LIKE ''ADDICTION ADVICE%'' THEN ''ADDICTION ADVICE''
WHEN ac.accountName LIKE ''AIA%'' THEN ''AIA''
...
Ketika saya pergi untuk menggunakannya dalam pernyataan pilih saya - permintaan hanya mengembalikan pernyataan kasus sebagai teks dan tidak mengevaluasinya.
Saya juga tidak dapat menggunakannya dalam grup oleh - Saya mendapat pesan kesalahan ini:
Each GROUP BY expression must contain at least one column that is not an outer reference.
Idealnya saya ingin memiliki KASUS hanya di satu tempat - sehingga tidak ada kesempatan saya memperbarui satu baris dan tidak mereplikasi itu di tempat lain.
Apakah ada cara untuk melakukan ini?
Saya terbuka untuk cara lain (Seperti mungkin suatu fungsi - tapi saya tidak yakin bagaimana menggunakannya seperti ini)
Berikut adalah contoh SELECT yang saya gunakan saat ini
SELECT
SUM(c.charge_amount) AS GSTExcl
,dl.FirstDateOfMonth AS MonthBilled
,dl.FirstDateOfWeek AS WeekBilled
,CASE
WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
ELSE ac.accountName
END AS accountName
,dl.FinancialYear
,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
LEFT Join charge c ON a.accession_id = c.accession_id
LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
WHERE a.datecreated = CONVERT(DATE,now())
GROUP BY
dl.FirstDateOfMonth
,dl.FinancialYear
,dl.FirstDateOfWeek
,CONVERT(Date,c.date_charged)
,CASE
WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
ELSE ac.accountName
END
UNION
SELECT
SUM(c.charge_amount) AS GSTExcl
,dl.FirstDateOfMonth AS MonthBilled
,dl.FirstDateOfWeek AS WeekBilled
,CASE
WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
ELSE ac.accountName
END AS accountName
,dl.FinancialYear
,CONVERT(Date,c.date_charged) AS date_charged
FROM [accession] a
LEFT JOIN account_code ac ON a.account_code_id = ac.account_code_id
LEFT Join charge c ON a.accession_id = c.accession_id
LEFT JOIN dateLookup dl ON convert(date,c.date_charged) = dl.date
WHERE a.datecreated = DATEADD(YEAR,-1,CONVERT(DATE,now()))
GROUP BY
dl.FirstDateOfMonth
,dl.FinancialYear
,dl.FirstDateOfWeek
,CONVERT(Date,c.date_charged)
,CASE
WHEN ac.accountName like 'AIR NEW Z%' THEN 'AIR NEW ZEALAND'
WHEN ac.accountName LIKE 'AIR BP%' THEN 'AIR BP'
WHEN ac.accountName LIKE 'ADDICTION ADVICE%' THEN 'ADDICTION ADVICE'
WHEN ac.accountName LIKE 'AIA%' THEN 'AIA'
ELSE ac.accountName
END
Tujuan untuk UNION ini adalah untuk mengembalikan semua data untuk periode waktu, dan JUGA untuk mengembalikan data untuk periode yang sama selama 12 bulan sebelumnya
EDIT: Menambahkan hilang "CATCH-ALL"
EDIT2: Menambahkan ½ kedua dari pernyataan UNION
EDIT3: Koreksi GROUP BY untuk memasukkan beberapa elemen yang diperlukan lainnya
sumber
WHERE a.datecreated = CONVERT(DATE,now()) OR a.datecreated = DATEADD(YEAR,-1,CONVERT(DATE,now()))
?Jawaban:
Salah satu cara mudah untuk menghilangkan pengulangan ekspresi CASE adalah dengan menggunakan CROSS APPLY seperti ini:
Dengan bantuan CROSS BERLAKU Anda menetapkan nama untuk ekspresi KASUS Anda sedemikian rupa sehingga dapat dirujuk di mana saja dalam pernyataan Anda. Ini berfungsi karena secara tegas Anda mendefinisikan kolom yang dikomputasi dalam SELECT bersarang - SELECT DARI-kurang yang mengikuti CROSS BERLAKU.
Ini sama dengan mereferensikan kolom alias dari tabel turunan - yang secara teknis SELECT bersarang ini. Ini adalah subquery yang berkorelasi dan tabel turunan. Sebagai subquery yang dikorelasikan, diizinkan untuk mereferensikan kolom lingkup luar, dan sebagai tabel turunan memungkinkan lingkup luar untuk referensi kolom yang didefinisikannya.
Untuk kueri UNION yang menggunakan ekspresi KASUS yang sama, Anda harus mendefinisikannya di setiap kaki, tidak ada solusi untuk itu kecuali menggunakan metode penggantian yang sama sekali berbeda daripada KASUS. Namun, dalam kasus spesifik Anda dimungkinkan untuk mengambil hasilnya tanpa UNION.
Kedua kaki berbeda dalam kondisi WHERE saja. Seseorang memiliki ini:
dan yang lainnya ini:
Anda dapat menggabungkan mereka seperti ini:
dan menerapkannya pada SELECT yang dimodifikasi pada awal jawaban ini.
sumber
CTE
- Saya tidak yakin mana pendekatan terbaik!UNION
dan cukup sertakandatecreated
kolom diGROUP BY
klausa Anda (dan perbaruiWHERE
klausa untuk menyertakan kedua tanggal yang Anda minati).datecreated
kolom dalam GROUP BY. Selain itu, saya sepenuhnya setuju, mereka hanya bisa menggabungkan klausa WHERE dan membuang UNION.Masukkan data ke dalam tabel
dan bergabunglah untuk itu.
Dengan begitu Anda dapat menghindari memperbarui data di banyak tempat. Cukup gunakan di
COALESCE
mana Anda membutuhkannya. Anda dapat memasukkan ini ke dalam CTE atauVIEW
s sesuai saran lainnya.sumber
Opsi lain yang saya pikir jika Anda perlu menggunakannya kembali di beberapa tempat, fungsi nilai tabel Inline akan bagus.
Pilihan Anda akan seperti ini.
Juga, saya belum menguji ini dan kinerja kode juga harus ditentukan.
EDIT1 : Saya pikir andriy sudah memberikan satu yang menggunakan cross berlaku yang redacts kode. Nah, yang ini bisa terpusat karena setiap perubahan dalam fungsi akan mencerminkan semuanya karena Anda mengulangi hal yang sama di bagian lain dari kode.
sumber
Saya akan menggunakan
VIEW
untuk melakukan apa yang Anda coba lakukan. Anda tentu saja dapat memperbaiki data yang mendasarinya, tetapi seringkali di situs ini, mereka yang mengajukan pertanyaan (konsultan / dBA /) tidak memiliki wewenang untuk melakukan ini. MenggunakanVIEW
kaleng memecahkan masalah ini! Saya juga memanfaatkanUPPER
fungsi - cara murah untuk menyelesaikan kesalahan dalam kasus seperti ini.Sekarang, Anda hanya mendeklarasikan
VIEW
sekali dan dapat menggunakannya di mana saja! Dengan cara ini, Anda hanya memiliki satu tempat di mana algoritma konversi data Anda disimpan dan dijalankan, sehingga meningkatkan keandalan dan ketahanan sistem Anda.Anda juga dapat menggunakan CTE ( Common Table Expression ) - lihat bagian bawah jawabannya!
Untuk menjawab pertanyaan Anda, saya melakukan yang berikut:
Buat tabel sampel:
Masukkan beberapa catatan sampel:
Kemudian buat
VIEW
seperti yang disarankan:Lalu,
SELECT
dari AndaVIEW
:Hasil:
Dan lagi!
Anda dapat menemukan semua ini di biola di sini .
The
CTE
Pendekatan:Sama seperti di atas, kecuali untuk yang
CTE
digantiVIEW
sebagai berikut:Hasilnya sama. Anda kemudian dapat memperlakukan
CTE
seperti halnya meja lainnya -SELECT
hanya untuk! Biola tersedia di sini .Secara keseluruhan, saya pikir
VIEW
pendekatannya lebih baik dalam hal ini!sumber
Meja tertanam
Lewati serikat dan gunakan
OR
di tempat seperti yang disarankan oleh orang lain.sumber