PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Lebih Banyak Kueri PostgreSQL Favorit Saya - dan Mengapa Mereka Juga Penting

Dalam posting blog sebelumnya Pertanyaan PostgreSQL Favorit Saya dan Mengapa Mereka Penting, saya mengunjungi pertanyaan menarik yang bermakna bagi saya saat saya belajar, mengembangkan, dan tumbuh menjadi peran pengembang SQL.

Salah satunya, khususnya, UPDATE multi-baris dengan ekspresi CASE tunggal, memicu percakapan menarik di Hacker News.

Dalam posting blog ini, saya ingin mengamati perbandingan antara kueri tertentu, dan yang melibatkan beberapa pernyataan UPDATE tunggal. Baik atau buruk.

Spesifikasi Mesin/Lingkungan:

  • CPU Intel(R) Core(TM) i5-6200U @ 2.30GHz
  • RAM 8 GB
  • Penyimpanan 1TB
  • Xubuntu Linux 16.04.3 LTS (Xenial Xerus)
  • PostgreSQL 10.4

Catatan:Untuk memulai, saya membuat tabel 'pementasan' dengan semua kolom jenis TEXT untuk memuat data.

Kumpulan data sampel yang saya gunakan, dapat ditemukan di tautan ini di sini.

Namun perlu diingat, data itu sendiri digunakan dalam contoh ini karena merupakan kumpulan ukuran yang layak dengan banyak kolom. Setiap 'analisis' atau UPDATES/INSERTS ke kumpulan data ini, tidak mencerminkan operasi GPS/GIS 'dunia nyata' yang sebenarnya dan tidak dimaksudkan seperti itu.

location=# \d data_staging;
               Table "public.data_staging"
    Column     |  Type   | Collation | Nullable | Default 
---------------+---------+-----------+----------+---------
 segment_num   | text    |           |          | 
 point_seg_num | text    |           |          | 
 latitude      | text    |           |          | 
 longitude     | text    |           |          | 
 nad_year_cd   | text    |           |          | 
 proj_code     | text    |           |          | 
 x_cord_loc    | text    |           |          | 
 y_cord_loc    | text    |           |          | 
 last_rev_date | text    |           |          | 
 version_date  | text    |           |          | 
 asbuilt_flag  | text    |           |          | 

location=# SELECT COUNT(*) FROM data_staging;
count
--------
546895
(1 row)

Kami memiliki sekitar setengah juta baris data dalam tabel ini.

Untuk perbandingan pertama ini, saya akan UPDATE kolom proj_code.

Berikut adalah kueri eksplorasi untuk menentukan nilainya saat ini:

location=# SELECT DISTINCT proj_code FROM data_staging;
proj_code
-----------
"70"
""
"72"
"71"
"51"
"15"
"16"
(7 rows)

Saya akan menggunakan trim untuk menghapus tanda kutip dari nilai dan memberikan ke INT dan menentukan berapa banyak baris yang ada untuk setiap nilai individu:

Mari kita gunakan CTE untuk itu, lalu PILIH darinya:

location=# WITH cleaned_nums AS (
SELECT NULLIF(trim(both '"' FROM proj_code), '') AS p_code FROM data_staging
)
SELECT COUNT(*),
CASE
WHEN p_code::int = 70 THEN '70'
WHEN p_code::int = 72 THEN '72'
WHEN p_code::int = 71 THEN '71'
WHEN p_code::int = 51 THEN '51'
WHEN p_code::int = 15 THEN '15'
WHEN p_code::int = 16 THEN '16'
ELSE '00'
END AS proj_code_num
FROM cleaned_nums
GROUP BY p_code
ORDER BY p_code DESC;
count  | proj_code_num
--------+---------------
353087 | 0
139057 | 72
25460  | 71
3254   | 70
1      | 51
12648  | 16
13388  | 15
(7 rows)

Sebelum menjalankan tes ini, saya akan melanjutkan dan MENGUBAH kolom proj_code untuk mengetik INTEGER:

BEGIN;
ALTER TABLE data_staging ALTER COLUMN proj_code SET DATA TYPE INTEGER USING NULLIF(trim(both '"' FROM proj_code), '')::INTEGER;
SAVEPOINT my_save;
COMMIT;

Dan bersihkan nilai kolom NULL itu (yang diwakili oleh ELSE '00' dalam ekspresi CASE eksplorasi di atas), atur ke angka arbitrer, 10, dengan UPDATE ini:

UPDATE data_staging
SET proj_code = 10
WHERE proj_code IS NULL;

Sekarang semua kolom kode_proj memiliki nilai INTEGER.

Mari kita lanjutkan dan jalankan ekspresi CASE tunggal yang memperbarui semua nilai kolom proj_code dan lihat apa yang dilaporkan waktunya. Saya akan menempatkan semua perintah dalam file sumber .sql untuk kemudahan penanganan.

Berikut isi filenya:

BEGIN;
\timing on
UPDATE data_staging
SET proj_code =
(
CASE proj_code
WHEN 72 THEN 7272
WHEN 71 THEN 7171
WHEN 15 THEN 1515
WHEN 51 THEN 5151
WHEN 70 THEN 7070
WHEN 10 THEN 1010
WHEN 16 THEN 1616
END
)
WHERE proj_code IN (72, 71, 15, 51, 70, 10, 16);
SAVEPOINT my_save;

Mari kita jalankan file ini dan periksa apa yang dilaporkan waktunya:

location=# \i /case_insert.sql
BEGIN
Time: 0.265 ms
Timing is on.
UPDATE 546895
Time: 6779.596 ms (00:06.780)
SAVEPOINT
Time: 0.300 ms

Lebih dari setengah juta baris dalam 6+ detik.

Berikut adalah perubahan yang tercermin dalam tabel sejauh ini:

location=# SELECT DISTINCT proj_code FROM data_staging;
proj_code
-----------
7070
1616
1010
7171
1515
7272
5151
(7 rows)

Saya akan ROLLBACK (tidak ditampilkan) perubahan ini sehingga saya dapat menjalankan pernyataan INSERT individual untuk mengujinya juga.

Di bawah ini mencerminkan modifikasi pada file sumber .sql untuk rangkaian perbandingan ini:

BEGIN;
\timing on

UPDATE data_staging
SET proj_code = 7222
WHERE proj_code = 72;

UPDATE data_staging
SET proj_code = 7171
WHERE proj_code = 71;

UPDATE data_staging
SET proj_code = 1515
WHERE proj_code = 15;

UPDATE data_staging
SET proj_code = 5151
WHERE proj_code = 51;

UPDATE data_staging
SET proj_code = 7070
WHERE proj_code = 70;

UPDATE data_staging
SET proj_code = 1010
WHERE proj_code = 10;

UPDATE data_staging
SET proj_code = 1616
WHERE proj_code = 16;
SAVEPOINT my_save;

Dan hasilnya,

location=# \i /case_insert.sql
BEGIN
Time: 0.264 ms
Timing is on.
UPDATE 139057
Time: 795.610 ms
UPDATE 25460
Time: 116.268 ms
UPDATE 13388
Time: 239.007 ms
UPDATE 1
Time: 72.699 ms
UPDATE 3254
Time: 162.199 ms
UPDATE 353087
Time: 1987.857 ms (00:01.988)
UPDATE 12648
Time: 321.223 ms
SAVEPOINT
Time: 0.108 ms

Mari kita periksa nilainya:

location=# SELECT DISTINCT proj_code FROM data_staging;
proj_code
-----------
7222
1616
7070
1010
7171
1515
5151
(7 rows)

Dan waktunya (Catatan:Saya akan menghitung dalam kueri karena \timing tidak melaporkan seluruh detik proses ini):

location=# SELECT round((795.610 + 116.268 + 239.007 + 72.699 + 162.199 + 1987.857 + 321.223) / 1000, 3) AS seconds;
seconds
---------
3.695
(1 row)

INSERT individu membutuhkan waktu sekitar setengah dari waktu sebagai CASE tunggal.

Tes pertama ini mencakup seluruh tabel, dengan semua kolom. Saya ingin tahu perbedaan apa pun dalam tabel dengan jumlah baris yang sama, tetapi kolom lebih sedikit, oleh karena itu rangkaian pengujian berikutnya.

Saya akan membuat tabel dengan 2 kolom (terdiri dari tipe data SERIAL untuk PRIMARY KEY dan INTEGER untuk kolom proj_code) dan memindahkan data:

location=# CREATE TABLE proj_nums(n_id SERIAL PRIMARY KEY, proj_code INTEGER);
CREATE TABLE
location=# INSERT INTO proj_nums(proj_code) SELECT proj_code FROM data_staging;
INSERT 0 546895

(Perlu diperhatikan:Perintah SQL dari rangkaian operasi pertama digunakan dengan modifikasi yang sesuai. Saya menghilangkannya di sini untuk singkatnya dan tampilan di layar )

Saya akan menjalankan ekspresi CASE tunggal terlebih dahulu:

location=# \i /case_insert.sql
BEGIN
Timing is on.
UPDATE 546895
Time: 4355.332 ms (00:04.355)
SAVEPOINT
Time: 0.137 ms

Dan kemudian UPDATE individu:

location=# \i /case_insert.sql
BEGIN
Time: 0.282 ms
Timing is on.
UPDATE 139057
Time: 1042.133 ms (00:01.042)
UPDATE 25460
Time: 123.337 ms
UPDATE 13388
Time: 212.698 ms
UPDATE 1
Time: 43.107 ms
UPDATE 3254
Time: 52.669 ms
UPDATE 353087
Time: 2787.295 ms (00:02.787)
UPDATE 12648
Time: 99.813 ms
SAVEPOINT
Time: 0.059 ms
location=# SELECT round((1042.133 + 123.337 + 212.698 + 43.107 + 52.669 + 2787.295 + 99.813) / 1000, 3) AS seconds;
seconds
---------
4.361
(1 row)

Pengaturan waktunya agak seimbang antara kedua set operasi pada tabel hanya dengan 2 kolom.

Saya akan mengatakan bahwa menggunakan ekspresi CASE sedikit lebih mudah untuk diketik, tetapi belum tentu merupakan pilihan terbaik di semua kesempatan. Seperti yang dinyatakan dalam beberapa komentar di utas Berita Peretas yang dirujuk di atas, biasanya "hanya tergantung" pada banyak faktor yang mungkin atau mungkin bukan pilihan yang optimal.

Saya menyadari tes ini paling subjektif. Salah satunya, pada tabel dengan 11 kolom sementara yang lain hanya memiliki 2 kolom, keduanya bertipe data angka.

Ekspresi CASE untuk beberapa pembaruan baris masih merupakan salah satu kueri favorit saya, jika hanya untuk kemudahan mengetik di lingkungan yang terkendali di mana banyak kueri UPDATE individual adalah alternatif lainnya.

Namun, saya dapat melihat sekarang di mana itu tidak selalu merupakan pilihan yang optimal karena saya terus tumbuh dan belajar.

Seperti pepatah lama, "Setengah lusin di satu tangan, 6 di tangan lainnya ."

Kueri Favorit tambahan - Menggunakan PLpgSQL CURSOR's

Saya telah mulai menyimpan dan melacak semua statistik latihan (pendakian jejak) saya dengan PostgreSQL di mesin pengembangan lokal saya. Ada beberapa tabel yang terlibat, seperti halnya database yang dinormalisasi.

Namun, pada akhir bulan, saya ingin menyimpan statistik kolom tertentu, di tabelnya sendiri, terpisah.

Berikut adalah tabel 'bulanan' yang akan saya gunakan:

fitness=> \d hiking_month_total;
                     Table "public.hiking_month_total"
     Column      |          Type          | Collation | Nullable | Default 
-----------------+------------------------+-----------+----------+---------
 day_hiked       | date                   |           |          | 
 calories_burned | numeric(4,1)           |           |          | 
 miles           | numeric(4,2)           |           |          | 
 duration        | time without time zone |           |          | 
 pace            | numeric(2,1)           |           |          | 
 trail_hiked     | text                   |           |          | 
 shoes_worn      | text                   |           |          |

Saya akan berkonsentrasi pada hasil Mei dengan kueri SELECT ini:

fitness=> SELECT hs.day_walked, hs.cal_burned, hs.miles_walked, hs.duration, hs.mph, tr.name, sb.name_brand
fitness-> FROM hiking_stats AS hs
fitness-> INNER JOIN hiking_trail AS ht
fitness-> ON hs.hike_id = ht.th_id
fitness-> INNER JOIN trail_route AS tr
fitness-> ON ht.tr_id = tr.trail_id
fitness-> INNER JOIN shoe_brand AS sb
fitness-> ON hs.shoe_id = sb.shoe_id
fitness-> WHERE extract(month FROM hs.day_walked) = 5
fitness-> ORDER BY hs.day_walked ASC;

Dan berikut adalah 3 baris sampel yang dikembalikan dari kueri itu:

day_walked | cal_burned | miles_walked | duration | mph | name | name_brand
------------+------------+--------------+----------+-----+------------------------+---------------------------------------
2018-05-02 | 311.2 | 3.27 | 00:57:13 | 3.4 | Tree Trail-extended | New Balance Trail Runners-All Terrain
2018-05-03 | 320.8 | 3.38 | 00:58:59 | 3.4 | Sandy Trail-Drive | New Balance Trail Runners-All Terrain
2018-05-04 | 291.3 | 3.01 | 00:53:33 | 3.4 | House-Power Line Route | Keen Koven WP(keen-dry)
(3 rows)

Sejujurnya, saya dapat mengisi tabel target hiking_month_total menggunakan kueri SELECT di atas dalam pernyataan INSERT.

Tapi di mana kesenangannya?

Saya akan melupakan kebosanan untuk fungsi PLpgSQL dengan CURSOR sebagai gantinya.

Saya datang dengan fungsi ini untuk melakukan INSERT dengan KURSOR:

CREATE OR REPLACE function monthly_total_stats()
RETURNS void
AS $month_stats$
DECLARE
v_day_walked date;
v_cal_burned numeric(4, 1);
v_miles_walked numeric(4, 2);
v_duration time without time zone;
v_mph numeric(2, 1);
v_name text;
v_name_brand text;
v_cur CURSOR for SELECT hs.day_walked, hs.cal_burned, hs.miles_walked, hs.duration, hs.mph, tr.name, sb.name_brand
FROM hiking_stats AS hs
INNER JOIN hiking_trail AS ht
ON hs.hike_id = ht.th_id
INNER JOIN trail_route AS tr
ON ht.tr_id = tr.trail_id
INNER JOIN shoe_brand AS sb
ON hs.shoe_id = sb.shoe_id
WHERE extract(month FROM hs.day_walked) = 5
ORDER BY hs.day_walked ASC;
BEGIN
OPEN v_cur;
<<get_stats>>
LOOP
FETCH v_cur INTO v_day_walked, v_cal_burned, v_miles_walked, v_duration, v_mph, v_name, v_name_brand;
EXIT WHEN NOT FOUND;
INSERT INTO hiking_month_total(day_hiked, calories_burned, miles,
duration, pace, trail_hiked, shoes_worn)
VALUES(v_day_walked, v_cal_burned, v_miles_walked, v_duration, v_mph, v_name, v_name_brand);
END LOOP get_stats;
CLOSE v_cur;
END;
$month_stats$ LANGUAGE PLpgSQL;

Mari kita panggil fungsi bulanan_total_stats() untuk melakukan INSERT:

fitness=> SELECT monthly_total_stats();
monthly_total_stats
---------------------
(1 row)

Karena fungsi didefinisikan RETURNS void, kita dapat melihat tidak ada nilai yang dikembalikan ke pemanggil.

Saat ini, saya tidak tertarik secara khusus pada nilai pengembalian apa pun,

hanya fungsi yang menjalankan operasi yang ditentukan, mengisi tabel hiking_month_total.

Saya akan menanyakan jumlah catatan di tabel target, mengonfirmasi bahwa tabel tersebut memiliki data:

fitness=> SELECT COUNT(*) FROM hiking_month_total;
count
-------
25
(1 row)

Fungsi bulanan_total_stats() berfungsi, tetapi mungkin kasus penggunaan yang lebih baik untuk CURSOR adalah menggulir sejumlah besar catatan. Mungkin meja dengan sekitar setengah juta catatan?

CURSOR berikutnya ini terikat dengan kueri yang menargetkan tabel data_staging dari rangkaian perbandingan di bagian di atas:

CREATE OR REPLACE FUNCTION location_curs()
RETURNS refcursor
AS $location$
DECLARE
v_cur refcursor;
BEGIN
OPEN v_cur for SELECT segment_num, latitude, longitude, proj_code, asbuilt_flag FROM data_staging;
RETURN v_cur;
END;
$location$ LANGUAGE PLpgSQL;

Kemudian, untuk menggunakan KURSOR ini, operasikan dalam TRANSAKSI (ditunjukkan dalam dokumentasi di sini).

location=# BEGIN;
BEGIN
location=# SELECT location_curs();
location_curs 
--------------------
<unnamed portal 1>
(1 row)

Jadi apa yang dapat Anda lakukan dengan "" ini?

Berikut ini beberapa hal:

Kita dapat mengembalikan baris pertama dari CURSOR menggunakan yang pertama atau MUTLAK 1:

location=# FETCH first FROM "<unnamed portal 1>";
segment_num | latitude | longitude | proj_code | asbuilt_flag 
-------------+------------------+-------------------+-----------+--------------
" 3571" | " 29.0202942600" | " -90.2908612800" | 72 | "Y"
(1 row)

location=# FETCH ABSOLUTE 1 FROM "<unnamed portal 1>";
segment_num | latitude | longitude | proj_code | asbuilt_flag 
-------------+------------------+-------------------+-----------+--------------
" 3571" | " 29.0202942600" | " -90.2908612800" | 72 | "Y"
(1 row)

Ingin satu baris hampir setengah jalan melalui hasil yang ditetapkan? (Dengan asumsi kita tahu sekitar setengah juta baris terikat ke CURSOR.)

Bisakah Anda menjadi 'spesifik' dengan KURSOR?

Ya.

Kita dapat memposisikan, dan FETCH nilai untuk record pada baris 234888 (hanya nomor acak yang saya pilih):

location=# FETCH ABSOLUTE 234888 FROM "<unnamed portal 1>";
segment_num | latitude | longitude | proj_code | asbuilt_flag 
-------------+------------------+-------------------+-----------+--------------
" 11261" | " 28.1159541400" | " -90.7778003500" | 10 | "Y"
(1 row)

Setelah diposisikan di sana, kita dapat memindahkan CURSOR 'backward one':

location=# FETCH BACKWARD FROM "<unnamed portal 1>";
segment_num | latitude | longitude | proj_code | asbuilt_flag 
-------------+------------------+-------------------+-----------+--------------
" 11261" | " 28.1159358200" | " -90.7778242300" | 10 | "Y"
(1 row)

Yang sama dengan:

location=# FETCH ABSOLUTE 234887 FROM "<unnamed portal 1>";
segment_num | latitude | longitude | proj_code | asbuilt_flag 
-------------+------------------+-------------------+-----------+--------------
" 11261" | " 28.1159358200" | " -90.7778242300" | 10 | "Y"
(1 row)

Kemudian kita dapat memindahkan CURSOR kembali ke ABSOLUTE 234888 dengan:

location=# FETCH FORWARD FROM "<unnamed portal 1>";
segment_num | latitude | longitude | proj_code | asbuilt_flag 
-------------+------------------+-------------------+-----------+--------------
" 11261" | " 28.1159541400" | " -90.7778003500" | 10 | "Y"
(1 row)

Kiat Praktis:untuk memposisikan ulang CURSOR, gunakan MOVE alih-alih FETCH jika Anda tidak memerlukan nilai dari baris itu.

Lihat bagian ini dari dokumentasi:

"MOVE memposisikan ulang kursor tanpa mengambil data apa pun. MOVE bekerja persis seperti perintah FETCH, kecuali hanya memposisikan kursor dan tidak mengembalikan baris."

Nama "" adalah nama umum dan sebenarnya bisa 'bernama' sebagai gantinya.

Saya akan mengunjungi kembali data statistik kebugaran saya untuk menulis fungsi dan memberi nama CURSOR, bersama dengan kasus penggunaan 'dunia nyata' yang potensial.

CURSOR akan menargetkan tabel tambahan ini, yang menyimpan hasil tidak terbatas pada bulan Mei (pada dasarnya semua yang telah saya kumpulkan sejauh ini) seperti pada contoh sebelumnya:

fitness=> CREATE TABLE cp_hiking_total AS SELECT * FROM hiking_month_total WITH NO DATA;
CREATE TABLE AS

Kemudian isi dengan data:

fitness=> INSERT INTO cp_hiking_total 
SELECT hs.day_walked, hs.cal_burned, hs.miles_walked, hs.duration, hs.mph, tr.name, sb.name_brand
FROM hiking_stats AS hs
INNER JOIN hiking_trail AS ht
ON hs.hike_id = ht.th_id
INNER JOIN trail_route AS tr
ON ht.tr_id = tr.trail_id
INNER JOIN shoe_brand AS sb
ON hs.shoe_id = sb.shoe_id
ORDER BY hs.day_walked ASC;
INSERT 0 51

Sekarang dengan fungsi PLpgSQL di bawah ini, BUAT KURSOR 'bernama':

CREATE OR REPLACE FUNCTION stats_cursor(refcursor)
RETURNS refcursor
AS $$
BEGIN
OPEN $1 FOR
SELECT *
FROM cp_hiking_total;
RETURN $1;
END;
$$ LANGUAGE plpgsql;

Saya akan menyebut CURSOR ini sebagai 'statistik':

fitness=> BEGIN;
BEGIN
fitness=> SELECT stats_cursor('stats');
stats_cursor 
--------------
stats
(1 row)

Misalkan, saya ingin baris '12' terikat ke CURSOR.

Saya dapat memposisikan CURSOR pada baris itu, mengambil hasil tersebut dengan perintah di bawah ini:

fitness=> FETCH ABSOLUTE 12 FROM stats;
day_hiked | calories_burned | miles | duration | pace | trail_hiked | shoes_worn 
------------+-----------------+-------+----------+------+---------------------+---------------------------------------
2018-05-02 | 311.2 | 3.27 | 00:57:13 | 3.4 | Tree Trail-extended | New Balance Trail Runners-All Terrain
(1 row)

Untuk tujuan posting blog ini, bayangkan saya tahu secara langsung nilai kolom kecepatan untuk baris ini salah.

Saya secara khusus ingat menjadi 'mati karena kaki saya lelah' hari itu dan hanya mempertahankan kecepatan 3,0 selama kenaikan itu. (Hei itu terjadi.)

Oke, saya akan UPDATE tabel cp_hiking_total untuk mencerminkan perubahan itu.

Relatif sederhana tidak diragukan lagi. Membosankan…

Bagaimana dengan CURSOR statistik?

fitness=> UPDATE cp_hiking_total
fitness-> SET pace = 3.0
fitness-> WHERE CURRENT OF stats;
UPDATE 1

Untuk membuat perubahan ini permanen, keluarkan COMMIT:

fitness=> COMMIT;
COMMIT

Mari kita query dan lihat bahwa UPDATE tercermin dalam tabel cp_hiking_total:

fitness=> SELECT * FROM cp_hiking_total
fitness-> WHERE day_hiked = '2018-05-02';
day_hiked | calories_burned | miles | duration | pace | trail_hiked | shoes_worn 
------------+-----------------+-------+----------+------+---------------------+---------------------------------------
2018-05-02 | 311.2 | 3.27 | 00:57:13 | 3.0 | Tree Trail-extended | New Balance Trail Runners-All Terrain
(1 row)

Keren banget kan?

Bergerak dalam kumpulan hasil CURSOR, dan jalankan UPDATE jika diperlukan.

Cukup kuat jika Anda bertanya kepada saya. Dan nyaman.

Beberapa 'hati-hati' dan informasi dari dokumentasi jenis KURSOR ini:

"Secara umum disarankan untuk menggunakan FOR UPDATE jika kursor dimaksudkan untuk digunakan dengan UPDATE ... WHERE CURRENT OF atau DELETE ... WHERE CURRENT OF. Menggunakan FOR UPDATE mencegah sesi lain mengubah baris di antara waktu mereka diambil dan waktunya diperbarui. Tanpa FOR UPDATE, perintah WHERE CURRENT OF berikutnya tidak akan berpengaruh jika baris diubah sejak kursor dibuat.

Alasan lain untuk menggunakan FOR UPDATE adalah bahwa tanpanya, WHERE CURRENT OF berikutnya mungkin gagal jika kueri kursor tidak memenuhi aturan standar SQL karena "dapat diperbarui" (khususnya, kursor harus merujuk hanya satu tabel dan tidak menggunakan pengelompokan atau ORDER BY). Kursor yang tidak hanya dapat diperbarui mungkin berfungsi, atau mungkin tidak, tergantung pada detail pilihan paket; jadi dalam kasus terburuk, aplikasi mungkin bekerja dalam pengujian dan kemudian gagal dalam produksi."

Dengan CURSOR yang saya gunakan di sini, saya telah mengikuti aturan standar SQL (dari bagian di atas) dalam aspek:Saya hanya mereferensikan satu tabel, tanpa pengelompokan atau klausa ORDER demi.

Mengapa itu penting.

Seperti banyak operasi, kueri, atau tugas di PostgreSQL (dan SQL secara umum), biasanya ada lebih dari satu cara untuk mencapai dan mencapai tujuan akhir Anda. Itulah salah satu alasan utama saya tertarik pada SQL dan berusaha untuk belajar lebih banyak.

Saya harap melalui posting blog lanjutan ini, saya telah memberikan beberapa wawasan mengapa UPDATE multi-baris dengan CASE dimasukkan sebagai salah satu pertanyaan favorit saya, dalam posting blog pertama yang menyertainya. Hanya memilikinya sebagai pilihan yang bermanfaat bagi saya.

Selain itu, menjelajahi KURSOR, untuk melintasi kumpulan hasil yang besar. Melakukan operasi DML, seperti UPDATES dan/atau DELETES, dengan jenis CURSOR yang benar, hanyalah 'memperbaiki kue'. Saya ingin mempelajarinya lebih lanjut untuk kasus penggunaan lainnya.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Menghubungkan postgresql dengan sqlalchemy

  2. Bagaimana cara melakukan transaksi database dengan psycopg2/python db api?

  3. Pengecualian dalam JPA saat menggunakan file benih untuk PostgreSQL

  4. Temukan nama tabel yang direferensikan menggunakan tabel, bidang, dan nama skema

  5. Bagaimana cara mendapatkan perbedaan hari/bulan/tahun (tanggal) antara dua tanggal?