Anda tidak akan menulis aplikasi dengan fungsi sepanjang 200 baris. Anda akan menguraikan fungsi yang panjang itu menjadi fungsi yang lebih kecil, masing-masing dengan satu tanggung jawab yang jelas.
Mengapa menulis SQL Anda seperti itu?
Dekomposisi kueri Anda, sama seperti Anda menguraikan fungsi Anda. Ini membuatnya lebih pendek, sederhana, lebih mudah dipahami, lebih mudah diuji , lebih mudah difaktor ulang. Dan ini memungkinkan Anda untuk menambahkan "shims" di antara mereka, dan "pembungkus" di sekitarnya, seperti yang Anda lakukan dalam kode prosedural.
Bagaimana kamu melakukan ini? Dengan membuat setiap hal penting yang dilakukan kueri menjadi tampilan. Kemudian Anda membuat kueri yang lebih kompleks dari tampilan yang lebih sederhana ini, sama seperti Anda membuat fungsi yang lebih kompleks dari fungsi yang lebih primitif.
Dan yang hebat adalah, untuk sebagian besar komposisi tampilan, Anda akan mendapatkan kinerja yang persis sama dari RDBMS Anda. (Untuk beberapa Anda tidak akan; lalu kenapa? Pengoptimalan prematur adalah akar dari semua kejahatan. Buat kode dengan benar terlebih dahulu, kemudian optimalkan jika perlu.)
Berikut adalah contoh penggunaan beberapa tampilan untuk menguraikan kueri yang rumit.
Dalam contoh, karena setiap tampilan hanya menambahkan satu transformasi, masing-masing dapat diuji secara independen untuk menemukan kesalahan, dan pengujiannya sederhana.
Berikut tabel dasar pada contoh:
create table month_value(
eid int not null, month int, year int, value int );
Tabel ini cacat, karena menggunakan dua kolom, bulan dan tahun, untuk mewakili satu datum, satu bulan absolut. Berikut spesifikasi kami untuk kolom terhitung baru:
Kita akan melakukannya sebagai transformasi linier, sehingga mengurutkan sama seperti (tahun, bulan), dan untuk setiap tupel (tahun, bulan) hanya ada satu nilai, dan semua nilai berurutan:
create view cm_absolute_month as
select *, year * 12 + month as absolute_month from month_value;
Sekarang apa yang harus kita uji melekat pada spesifikasi kita, yaitu untuk setiap tuple (tahun, bulan), ada satu dan hanya satu (absolute_month), dan itu (absolute_month) adalah berurutan. Mari kita tulis beberapa tes.
Pengujian kami akan menjadi select
kueri SQL , dengan struktur berikut: nama pengujian dan pernyataan kasus yang dikategorikan bersama. Nama pengujian hanyalah string arbitrer. Pernyataan kasus hanyalah case when
pernyataan uji then 'passed' else 'failed' end
.
Pernyataan pengujian hanya akan berupa pemilihan SQL (subkueri) yang harus benar agar pengujian dapat lulus.
Inilah tes pertama kami:
--a select statement that catenates the test name and the case statement
select concat(
-- the test name
'For every (year, month) there is one and only one (absolute_month): ',
-- the case statement
case when
-- one or more subqueries
-- in this case, an expected value and an actual value
-- that must be equal for the test to pass
( select count(distinct year, month) from month_value)
--expected value,
= ( select count(distinct absolute_month) from cm_absolute_month)
-- actual value
-- the then and else branches of the case statement
then 'passed' else 'failed' end
-- close the concat function and terminate the query
);
-- test result.
Menjalankan kueri itu menghasilkan hasil ini: For every (year, month) there is one and only one (absolute_month): passed
Selama ada cukup data pengujian di month_value, pengujian ini berfungsi.
Kami juga dapat menambahkan pengujian untuk data pengujian yang memadai:
select concat( 'Sufficient and sufficiently varied month_value test data: ',
case when
( select count(distinct year, month) from month_value) > 10
and ( select count(distinct year) from month_value) > 3
and ... more tests
then 'passed' else 'failed' end );
Sekarang mari kita uji berturut-turut:
select concat( '(absolute_month)s are consecutive: ',
case when ( select count(*) from cm_absolute_month a join cm_absolute_month b
on ( (a.month + 1 = b.month and a.year = b.year)
or (a.month = 12 and b.month = 1 and a.year + 1 = b.year) )
where a.absolute_month + 1 <> b.absolute_month ) = 0
then 'passed' else 'failed' end );
Sekarang mari kita letakkan pengujian kita, yang hanya berupa kueri, ke dalam file, dan menjalankan skrip tersebut pada database. Memang, jika kita menyimpan definisi tampilan dalam skrip (atau skrip, saya merekomendasikan satu file per tampilan terkait) untuk dijalankan terhadap database, kita dapat menambahkan pengujian untuk setiap tampilan ke skrip yang sama , sehingga tindakan (re -) membuat tampilan kita juga menjalankan pengujian tampilan. Dengan begitu, kita berdua mendapatkan pengujian regresi saat membuat ulang tampilan, dan saat pembuatan tampilan bertentangan dengan produksi, tampilan tersebut juga akan diuji dalam produksi.