ការបញ្ចូល ការកែប្រែ និងការលុបទិន្នន័យ

មាតិកា

  1. កន្លែងដែលយើងឈប់
  2. INSERT មួយ row
  3. ច្រើន row និង RETURNING
  4. ហេតុអ្វី Insert បរាជ័យ
  5. ការសរសេរ seed.sql
  6. UPDATE និង WHERE Clause
  7. គ្រោះថ្នាក់នៃការគ្មាន WHERE
  8. DELETE និងការមើលមុននឹងធ្វើ
  9. TRUNCATE
  10. Upsert៖ INSERT ... ON CONFLICT
  11. សាកល្បងដោយខ្លួនឯង

1. កន្លែងដែលយើងឈប់

នៅជំពូកមុន អ្នកបានបង្កើត table ពីរក្នុង shopdb គឺ customers និង products។ ពួកវាមាន column, type និង constraint ប៉ុន្តែនៅទទេ។ table ដែលគ្មាន row មិនអាចឆ្លើយសំណួរអ្វីបានទេ។

ជំពូកនេះនិយាយអំពីផ្នែក DML នៃ SQL ដែលជា Data Manipulation Language៖ INSERT បន្ថែម row, UPDATE ផ្លាស់ប្តូរវា, DELETE លុបវា។ នៅចុងបញ្ចប់ អ្នកនឹងមានឯកសារ seed.sql ដែលបំពេញ shopdb ដោយទិន្នន័យចាប់ផ្តើមរបស់ហាង ហើយអ្នកអាចសាងសង់វាឡើងវិញដោយ command តែមួយ។

បើកសម័យ psql របស់អ្នក ប្រសិនបើវាមិនទាន់បើក៖

docker exec -it shopdb-pg psql -U postgres -d shopdb

ប្រសិនបើអ្នកមិនបានរក្សាទុកសេចក្តីថ្លែង CREATE TABLE ពីជំពូកមុន នេះជាវាម្តងទៀត។ នេះគឺជាមាតិកានៃ shopdb/schema.sql រហូតមកដល់ពេលនេះ៖

CREATE TABLE customers (
  id         integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  name       text NOT NULL,
  email      text NOT NULL UNIQUE,
  city       text,
  created_at timestamptz NOT NULL DEFAULT now()
);

CREATE TABLE products (
  id       integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  name     text NOT NULL,
  price    numeric(10,2) NOT NULL CHECK (price >= 0),
  stock    integer NOT NULL DEFAULT 0 CHECK (stock >= 0),
  category text
);

ចំណាំថា products មាន column category ជាអក្សរធម្មតាសម្រាប់ពេលនេះ។ នៅជំពូកទី 6 យើងនឹងជំនួសវាដោយទំនាក់ទំនងត្រឹមត្រូវទៅ table categories។

2. INSERT មួយ row

ទម្រង់មូលដ្ឋានដាក់ឈ្មោះ table, column ដែលអ្នកកំពុងបំពេញ និងតម្លៃ តាមលំដាប់ដូចគ្នា៖

INSERT INTO customers (name, email, city)
VALUES ('Sokha Chan', 'sokha@example.com', 'Phnom Penh');
INSERT 0 1

ចម្លើយ INSERT 0 1 មានន័យថា "បានបញ្ចូលមួយ row"។ (លេខ 0 ជាសំណល់ពី Postgres កំណែចាស់ៗ។ កុំខ្វល់ពីវា។)

សូមមើលអ្វីដែលអ្នក មិនបានផ្តល់៖ id និង created_at។ អ្នកមិនចាំបាច់ផ្តល់ទេ។ identity column បង្កើត id ហើយ DEFAULT now() បំពេញ timestamp។ ពិនិត្យលទ្ធផល៖

SELECT * FROM customers;
 id |    name    |       email       |    city    |          created_at
----+------------+-------------------+------------+-------------------------------
  1 | Sokha Chan | sokha@example.com | Phnom Penh | 2026-10-03 09:14:52.318+00
(1 row)

(timestamp នឹងជាពេលវេលាបច្ចុប្បន្នរបស់អ្នក។ លទ្ធផលទាំងអស់ក្នុងស៊េរីនេះជាលទ្ធផល psql ធម្មតា ដូច្នេះចន្លោះ និងពេលវេលានៅលើអេក្រង់របស់អ្នកអាចខុសបន្តិចបន្តួច។)

ទម្លាប់ពីរដែលគួរបង្កើតចាប់ពីពេលនេះ៖

  • តែងតែសរសេរបញ្ជី column។ INSERT INTO customers VALUES (...) ដំណើរការ ប៉ុន្តែវាពឹងផ្អែកលើលំដាប់ column ពិតប្រាកដ។ ប្រសិនបើនរណាម្នាក់បន្ថែម column នៅពេលក្រោយ សេចក្តីថ្លែងរបស់អ្នកនឹងខូចដោយស្ងៀមស្ងាត់ ឬបំពេញ field ខុស។
  • អក្សរប្រើសញ្ញាអញ្ញប្រកាសតែមួយ (single quote)។ 'Sokha Chan' គឺជា string។ សញ្ញាអញ្ញប្រកាសទ្វេ (double quote) ក្នុង SQL មានន័យថា identifier (ឈ្មោះ table ឬ column) មិនមែន string ទេ។ ដើម្បីដាក់ single quote ក្នុង string សូមសរសេរវាពីរដង៖ 'O''Brien'។

column ដែលអ្នកលោតរំលង នឹងទទួលបាន DEFAULT របស់វា ឬ NULL ប្រសិនបើគ្មាន default។ column city គ្មាន default និងគ្មាន NOT NULL ដូច្នេះនេះដំណើរការ ហើយរក្សាទុក NULL៖

INSERT INTO customers (name, email)
VALUES ('Maly Ros', 'maly@example.com');

3. ច្រើន row និង RETURNING

ការផ្ញើសេចក្តីថ្លែងមួយសម្រាប់ម្តងមួយ row គឺយឺត និងរញ៉េរញ៉ៃ។ VALUES ទទួលបញ្ជីនៃ row ដែលបំបែកដោយសញ្ញាក្បៀស៖

INSERT INTO customers (name, email, city) VALUES
  ('Dara Kim',   'dara@example.com',   'Siem Reap'),
  ('Linda Vong', 'linda@example.com',  'Phnom Penh'),
  ('Vuthy Sok',  'vuthy@example.com',  'Battambang');
INSERT 0 3

នេះជាសេចក្តីថ្លែងតែមួយ ដូច្នេះវា ទាំងអស់ ឬគ្មានអ្វីសោះ៖ ប្រសិនបើ row មួយក្នុងចំណោមបីបំពាន constraint នោះគ្មាន row ណាមួយត្រូវបានបញ្ចូលទេ។ នេះមានប្រយោជន៍ពេលផ្ទុកទិន្នន័យ។

ជារឿយៗអ្នកត្រូវដឹង id ដែលទើបតែត្រូវបានបង្កើតដោយ database ឧទាហរណ៍ដើម្បីបញ្ចូល row ដែលពាក់ព័ន្ធបន្ទាប់។ កុំដំណើរការ SELECT ទីពីរដើម្បីរកវា។ បន្ថែម RETURNING ដែលជាលក្ខណៈពិសេសរបស់ Postgres ដែលផ្ញើ column ត្រឡប់មកវិញពី row ដែលអ្នកទើបតែផ្លាស់ប្តូរ៖

INSERT INTO products (name, price, stock, category)
VALUES ('Wireless Mouse', 15.00, 40, 'Electronics')
RETURNING id, name, price;
 id |      name      | price
----+----------------+-------
  1 | Wireless Mouse | 15.00
(1 row)

INSERT 0 1

RETURNING ក៏ដំណើរការជាមួយ UPDATE និង DELETE ដែរ ហើយអ្នកអាចសរសេរ RETURNING * ដើម្បីទទួល column ទាំងអស់។ ក្នុងកម្មវិធី backend នេះជារបៀបដែលអ្នកដឹង id នៃ row ដែលអ្នកទើបតែបង្កើត ក្នុងការទៅមកតែមួយដង។

កំណត់ចំណាំអំពីលេខ id។ identity column ប្រើ sequence ដែលជាកម្មវិធីរាប់ដែលឡើងតែម្ខាង។ វាមិនថយក្រោយទេ ទោះបីជា insert បរាជ័យ ឬ row ត្រូវបានលុបនៅពេលក្រោយក៏ដោយ។ ដូច្នេះ id អាចមានចន្លោះ (1, 2, 4, 7) ហើយនោះជារឿងធម្មតា។ កុំពឹងផ្អែកលើ id ដែលតគ្នាជាប់ៗ។

4. ហេតុអ្វី Insert បរាជ័យ

Constraint ពីជំពូកទី 3 ឥឡូវនេះចាប់ផ្តើមមានតម្លៃ។ សាកល្បងបំពានម្តងមួយៗ ហើយអានសារ ព្រោះអ្នកនឹងឃើញវាញឹកញាប់។

តម្លៃ unique ស្ទួន។ email sokha@example.com មានរួចហើយ៖

INSERT INTO customers (name, email)
VALUES ('Another Sokha', 'sokha@example.com');
ERROR:  duplicate key value violates unique constraint "customers_email_key"
DETAIL:  Key (email)=(sokha@example.com) already exists.

បាត់តម្លៃដែលតម្រូវ។ name គឺ NOT NULL៖

INSERT INTO customers (email) VALUES ('nobody@example.com');
ERROR:  null value in column "name" of relation "customers" violates not-null constraint
DETAIL:  Failing row contains (7, null, nobody@example.com, null, 2026-10-03 09:20:11.402+00).

ច្បាប់ត្រូវបានបំពាន។ តម្លៃអវិជ្ជមានធ្លាក់ CHECK៖

INSERT INTO products (name, price) VALUES ('Free Money', -5);
ERROR:  new row for relation "products" violates check constraint "products_price_check"
DETAIL:  Failing row contains (2, Free Money, -5.00, 0, null).

កំណត់ id ដែលបង្កើតដោយស្វ័យប្រវត្តិដោយខ្លួនឯង។ column នេះគឺ GENERATED ALWAYS ដូច្នេះ Postgres បដិសេធតម្លៃរបស់អ្នក៖

INSERT INTO customers (id, name, email)
VALUES (100, 'Manual Id', 'manual@example.com');
ERROR:  cannot insert a non-DEFAULT value into column "id"
DETAIL:  Column "id" is an identity column defined as GENERATED ALWAYS.
HINT:  Use OVERRIDING SYSTEM VALUE to override.

បន្ទាត់ដំបូងនៃកំហុសនីមួយៗប្រាប់ឈ្មោះ constraint ដែលត្រូវបានបំពាន ហើយបន្ទាត់ DETAIL បង្ហាញទិន្នន័យពិតប្រាកដ។ ការអានបន្ទាត់ទាំងពីរនេះដោះស្រាយបញ្ហា insert ភាគច្រើន។ ចំណាំអ្វីមួយទៀតផង៖ insert ដែលបរាជ័យបានប្រើលេខពី identity sequence។ row អតិថិជនដែលបរាជ័យខាងលើបានប្រាប់ id 7 ទោះបីមានអតិថិជនតែប្រាំនាក់ក៏ដោយ។ នោះជាឥរិយាបថនៃចន្លោះ ដូចក្នុងផ្នែកមុន កំពុងដំណើរការ។

5. ការសរសេរ seed.sql

ការវាយ row ចូលក្នុង psql គឺល្អសម្រាប់ការស្វែងយល់ ប៉ុន្តែអ្នកមិនចង់វាយអតិថិជនប្រាំនាក់ និងផលិតផលប្រាំបីឡើងវិញរាល់ពេលទេ។ ហើយបន្ទាប់ពី insert ដែលបរាជ័យទាំងនោះ id របស់អ្នកលែងត្រូវនឹង id ដែលប្រើក្នុងផ្នែកផ្សេងទៀតនៃស៊េរីនេះ។ ដំណោះស្រាយគឺ ស្គ្រីប seed៖ ឯកសារ .sql ធម្មតានៅក្នុងគម្រោងរបស់អ្នក ដែលដាក់ database ទៅក្នុងស្ថានភាពដែលស្គាល់។

នៅក្នុងថត shopdb/ របស់អ្នក បង្កើត seed.sql៖

-- shopdb/seed.sql
-- កំណត់ table ឡើងវិញ ហើយផ្ទុកទិន្នន័យចាប់ផ្តើម។
TRUNCATE customers, products RESTART IDENTITY CASCADE;

INSERT INTO customers (name, email, city) VALUES
  ('Sokha Chan', 'sokha@example.com', 'Phnom Penh'),
  ('Dara Kim',   'dara@example.com',  'Siem Reap'),
  ('Linda Vong', 'linda@example.com', 'Phnom Penh'),
  ('Vuthy Sok',  'vuthy@example.com', 'Battambang'),
  ('Maly Ros',   'maly@example.com',  NULL);

INSERT INTO products (name, price, stock, category) VALUES
  ('Wireless Mouse',      15.00,  40, 'Electronics'),
  ('USB-C Cable',          5.50, 120, 'Electronics'),
  ('Mechanical Keyboard', 79.00,  15, 'Electronics'),
  ('SQL Cookbook',        32.00,  25, 'Books'),
  ('Clean Code',          28.50,  30, 'Books'),
  ('Desk Lamp',           22.00,   0, 'Home'),
  ('Coffee Mug',           6.00,  80, 'Home'),
  ('Notebook Pack',        9.50,  60, 'Books');

សេចក្តីថ្លែងដំបូង TRUNCATE ធ្វើឱ្យ table ទទេ ហើយចាប់ផ្តើមកម្មវិធីរាប់ id ម្តងទៀតពី 1 (បន្ថែមអំពីវាក្នុងផ្នែកទី 9)។ បន្ទាប់មក insert ដំណើរការតាមលំដាប់ ដូច្នេះ id ត្រូវបានកំណត់ពី 1 ដល់ 5 និង 1 ដល់ 8។ ដោយសារលំដាប់ថេរ id គឺដូចគ្នារាល់ពេល។ ផ្នែកដែលនៅសល់នៃស៊េរីពឹងផ្អែកលើរឿងនេះ៖ "អតិថិជន 1" តែងតែជា Sokha, "ផលិតផល 3" តែងតែជា keyboard។

ឥឡូវនេះដំណើរការឯកសារប្រឆាំងនឹង database ពី terminal ធម្មតារបស់អ្នក មិនមែនពីក្នុង psql ទេ៖

docker exec -i shopdb-pg psql -U postgres -d shopdb < seed.sql
TRUNCATE TABLE
INSERT 0 5
INSERT 0 8

flag -i (ជំនួសឱ្យ -it) ប្រាប់ Docker ឱ្យបញ្ជូនឯកសាររបស់អ្នកជា input ហើយសញ្ញា < គឺ shell ដែលបញ្ចូល seed.sql ទៅក្នុង command។ ប្រសិនបើអ្នកនៅក្នុង psql រួចហើយ ហើយឯកសាររបស់អ្នកអាចចូលដំណើរការបានពីទីនោះ command \i ពីជំពូកទី 2 ធ្វើការងារដូចគ្នា។

តាមលំនាំដើម psql បន្តដំណើរការបន្ទាប់ពីមានកំហុស ដែលអាចទុកឱ្យអ្នកមានទិន្នន័យផ្ទុកពាក់កណ្តាល និងសារវែងៗជាច្រើន។ សម្រាប់ស្គ្រីប សូមប្រាប់វាឱ្យឈប់នៅកំហុសដំបូង៖

docker exec -i shopdb-pg psql -U postgres -d shopdb \
  -v ON_ERROR_STOP=1 < seed.sql

ផ្ទៀងផ្ទាត់អ្វីដែលអ្នកមាន៖

SELECT id, name, price, stock, category FROM products ORDER BY id;
 id |        name         | price | stock |  category
----+---------------------+-------+-------+-------------
  1 | Wireless Mouse      | 15.00 |    40 | Electronics
  2 | USB-C Cable         |  5.50 |   120 | Electronics
  3 | Mechanical Keyboard | 79.00 |    15 | Electronics
  4 | SQL Cookbook        | 32.00 |    25 | Books
  5 | Clean Code          | 28.50 |    30 | Books
  6 | Desk Lamp           | 22.00 |     0 | Home
  7 | Coffee Mug          |  6.00 |    80 | Home
  8 | Notebook Pack       |  9.50 |    60 | Books
(8 rows)

ចាប់ពីពេលនេះទៅ រាល់ពេលដែលទិន្នន័យរបស់អ្នករញ៉េរញ៉ៃដោយសារការពិសោធន៍ សូមដំណើរការ seed.sql ម្តងទៀតដើម្បីត្រឡប់ទៅស្ថានភាពដែលស្គាល់។ database ដែលអ្នកអាចសាងសង់ឡើងវិញតាមចិត្ត គឺជា database ដែលអ្នកមិនភ័យខ្លាចក្នុងការពិសោធន៍លើវា។

6. UPDATE និង WHERE Clause

UPDATE ផ្លាស់ប្តូរតម្លៃក្នុង row ដែលមានស្រាប់។ រូបរាងគឺ៖

UPDATE table_name
SET column = new_value [, column = new_value ...]
WHERE condition;

WHERE clause សម្រេច row ណាខ្លះ។ ឧបមាថាតម្លៃ Wireless Mouse ឡើងទៅ 16.00៖

UPDATE products
SET price = 16.00
WHERE id = 1
RETURNING id, name, price;
 id |      name      | price
----+----------------+-------
  1 | Wireless Mouse | 16.00
(1 row)

UPDATE 1

ចម្លើយ UPDATE 1 ប្រាប់អ្នកថាមានប៉ុន្មាន row ដែលបានផ្លាស់ប្តូរ។ សូមអានលេខនេះរាល់ពេល។ ប្រសិនបើអ្នករំពឹងមួយ row ហើយឃើញ UPDATE 0 នោះលក្ខខណ្ឌរបស់អ្នកត្រូវនឹងអ្វីទាំងអស់ (id ខុស ឬវាយខុស)។ ប្រសិនបើអ្នករំពឹងមួយ ហើយឃើញ UPDATE 340 សូមឈប់ ហើយគិត។

ផ្នែកខាងស្តាំនៃ SET អាចប្រើតម្លៃបច្ចុប្បន្នរបស់ row ដូច្នេះអ្នកអាចគណនាពីពួកវា។ បំពេញស្តុក Desk Lamp (យើងមិនមានទេ) ហើយកត់ត្រាការលក់ Coffee Mug បីដង៖

UPDATE products SET stock = stock + 10 WHERE name = 'Desk Lamp';
UPDATE products SET stock = stock - 3  WHERE name = 'Coffee Mug';

ផ្លាស់ប្តូរ column ច្រើនក្នុងពេលតែមួយដោយបំបែកវាដោយសញ្ញាក្បៀស៖

UPDATE customers
SET city = 'Kampot', name = 'Maly Ros-Chea'
WHERE email = 'maly@example.com';

ដោយសារ stock មាន CHECK (stock >= 0) database ការពារអ្នកពីការលក់លើសស្តុកដោយចៃដន្យ៖

UPDATE products SET stock = stock - 100 WHERE name = 'Mechanical Keyboard';
ERROR:  new row for relation "products" violates check constraint "products_stock_check"
DETAIL:  Failing row contains (3, Mechanical Keyboard, 79.00, -85, Electronics).

ការ update ត្រូវបានបដិសេធ ហើយ row នៅតែ 15។ នេះជាគោលបំណងនៃ constraint៖ ច្បាប់រស់នៅក្នុង database ដូច្នេះវាមានតម្លៃមិនថាកម្មវិធី ស្គ្រីប ឬអ្នកអភិវឌ្ឍន៍ដែលអស់កម្លាំងណាដំណើរការសេចក្តីថ្លែងនោះទេ។

ដាក់តម្លៃ mouse ត្រឡប់មកវិញ ដើម្បីឱ្យទិន្នន័យរបស់អ្នកត្រូវនឹង seed ម្តងទៀត៖

UPDATE products SET price = 15.00 WHERE id = 1;

7. គ្រោះថ្នាក់នៃការគ្មាន WHERE

ឥឡូវនេះជាកំហុសដ៏ល្បីបំផុតក្នុង SQL។ តើសេចក្តីថ្លែងនេះធ្វើអ្វី?

UPDATE products SET price = 0;

វាមិនសួរថា "តើអ្នកប្រាកដទេ?" ទេ។ WHERE clause គឺជាជម្រើស ហើយបើគ្មានវា សេចក្តីថ្លែងអនុវត្តលើ គ្រប់ row។ ផលិតផលទាំងប្រាំបីឥឡូវនេះមានតម្លៃសូន្យ។

តោះមើលវាដោយសុវត្ថិភាពលើច្បាប់ចម្លងសាកល្បង ដើម្បីឱ្យ shopdb នៅស្អាត។ សេចក្តីថ្លែង CREATE TABLE ... AS SELECT សាងសង់ table ថ្មីពី query៖

CREATE TABLE products_scratch AS SELECT * FROM products;

UPDATE products_scratch SET price = 0;
SELECT 8
UPDATE 8

UPDATE 8 គឺជាសំឡេងរោទ៍ព្រមាន៖ អ្នកបានផ្លាស់ប្តូរទាំងប្រាំបី row។ ក្នុងជីវិតពិត លេខនឹងជា 80,000 ហើយទូរស័ព្ទរបស់អ្នកនឹងរោទ៍។ ដូចគ្នាដែរសម្រាប់ DELETE FROM products; ដែលលុបគ្រប់ row។

ទម្លាប់បីការពារអ្នក៖

  1. សរសេរ WHERE មុន។ វាយ UPDATE products ... WHERE id = 1 បន្ទាប់មកត្រឡប់ទៅបំពេញផ្នែក SET។ អ្នកនឹងមិនភ្លេចលក្ខខណ្ឌទេ ព្រោះវានៅទីនោះរួចហើយ។
  2. សាកល្បងជាមួយ SELECT មុន។ បម្លែងសេចក្តីថ្លែងទៅជា query ដែលមាន WHERE ដូចគ្នា ហើយមើល row ដែលវានឹងប៉ះពាល់៖
    SELECT id, name, price FROM products WHERE category = 'Books';
    
    តែនៅពេលដែល row ទាំងនោះជា row ដែលអ្នកចង់បានយ៉ាងពិតប្រាកដ ទើបប្តូរ SELECT ... ទៅជា UPDATE ... SET ... ហើយរក្សា WHERE ដដែល។
  3. ប្រើ transaction ដើម្បីអាចមិនធ្វើវិញ (undo)។ អ្នកនឹងរៀន BEGIN និង ROLLBACK ឱ្យបានត្រឹមត្រូវក្នុងជំពូកទី 12។ សម្រាប់ពេលនេះ សូមចាំថា database មានការមិនធ្វើវិញសម្រាប់កំហុសបែបនេះ ប៉ុន្តែលុះត្រាតែអ្នកស្នើសុំវា មុន ពេលដំណើរការសេចក្តីថ្លែង។

សម្អាត table សាកល្បង៖

DROP TABLE products_scratch;

8. DELETE និងការមើលមុននឹងធ្វើ

DELETE លុប row ហើយមានរូបរាងដូច UPDATE៖ table និង WHERE។

DELETE FROM table_name WHERE condition;

បន្ថែមអតិថិជនបណ្តោះអាសន្នម្នាក់ ហើយបន្ទាប់មកលុបគាត់ ដោយប្រើទម្លាប់ SELECT មុន៖

INSERT INTO customers (name, email) VALUES ('Test Person', 'test@example.com')
RETURNING id;
 id
----
  6
(1 row)

INSERT 0 1
SELECT id, name FROM customers WHERE email = 'test@example.com';
 id |    name
----+-------------
  6 | Test Person
(1 row)

ពិតជា row មួយដែលយើងចង់បាន។ ឥឡូវនេះលុបវា ដោយផ្គូផ្គងលើ primary key ដែលជារបៀបសុវត្ថិភាពបំផុតក្នុងការកំណត់គោលដៅ row តែមួយ៖

DELETE FROM customers WHERE id = 6 RETURNING *;

RETURNING លើ DELETE ផ្តល់ row ដែលអ្នកទើបតែលុបមកអ្នកវិញ ជាកំណត់ត្រាងាយស្រួលក្នុងករណីដែលអ្នកលុបខុស។ ចម្លើយបញ្ចប់ដោយ៖

DELETE 1

ពីរចំណុចដែលត្រូវចងចាំអំពីការលុប៖

  • ការលុបគឺអចិន្ត្រៃយ៍។ មិនដូចថតធុងសំរាមទេ គ្មានអ្វីអាចយកមកវិញបានទេ លុះត្រាតែអ្នកមាន backup ឬ transaction។ កម្មវិធីពិតជាច្រើនជៀសវាងការលុប row សំខាន់ៗទាំងស្រុង (សូមមើល "soft delete" ក្នុងជំពូកទី 10)។
  • ទំនាក់ទំនងអាចរារាំងវា។ ពេលដែល order យោងទៅអតិថិជន (ជំពូកបន្ទាប់) អ្នកមិនអាចលុបអតិថិជនដែលនៅតែមាន order បានទេ លុះត្រាតែទំនាក់ទំនងនិយាយផ្សេង។ ការការពារនោះគឺជាអ្វីដែល foreign key មានសម្រាប់។

9. TRUNCATE

ប្រសិនបើអ្នកចង់ធ្វើឱ្យ table ទាំងមូលទទេ DELETE FROM products; ដំណើរការ ប៉ុន្តែយឺតលើ table ធំៗ ព្រោះ Postgres លុប row ម្តងមួយៗ។ TRUNCATE បោះចោលពួកវាក្នុងជំហានតែមួយ៖

TRUNCATE products;

វាលឿន ប៉ុន្តែវាជាញញួរធំជាង DELETE៖

  • វាមិនយក WHERE ទេ។ វាតែងតែជា table ទាំងមូល។
  • តាមលំនាំដើម វា មិន កំណត់ identity counter ឡើងវិញទេ។ row ថ្មីបន្តរាប់ពីកន្លែងដែល row ចាស់ឈប់។ បន្ថែម RESTART IDENTITY ដើម្បីចាប់ផ្តើមពី 1 ម្តងទៀត។
  • វាបដិសេធមិនដំណើរការលើ table ដែល table ផ្សេងទៀតយោងតាមរយៈ foreign key។ បន្ថែម CASCADE ដើម្បីធ្វើឱ្យ table ទាំងនោះទទេផងដែរ។ នេះជាហេតុផលដែល seed.sql របស់អ្នកនិយាយថា RESTART IDENTITY CASCADE៖ នៅពេល orders មាន ការ truncate customers ត្រូវតែធ្វើឱ្យ orders ទទេដែរ ហើយ CASCADE ធ្វើឱ្យវាច្បាស់លាស់។

ចាត់ទុក TRUNCATE ... CASCADE ដូច DELETE ដែលគ្មាន WHERE ប៉ុន្តែឮខ្លាំងជាង។ វាល្អឥតខ្ចោះសម្រាប់ស្គ្រីប seed សម្រាប់ការអភិវឌ្ឍ ហើយជាគំនិតអាក្រក់ក្នុងការវាយដោយមិនប្រុងប្រយ័ត្ននៅជិតទិន្នន័យពិត។

ប្រសិនបើអ្នកទើបតែដំណើរការ TRUNCATE products ពេលកំពុងពិសោធន៍ សូមដំណើរការ seed.sql ម្តងទៀតដើម្បីស្តារអ្វីៗទាំងអស់។

10. Upsert៖ INSERT ... ON CONFLICT

តម្រូវការទូទៅមួយ៖ "បន្ថែម row នេះ ប៉ុន្តែប្រសិនបើវាមានរួចហើយ សូម update វាជំនួសវិញ"។ ការធ្វើដោយដៃគឺស្មុគស្មាញ៖ ដំណើរការ SELECT ពិនិត្យលទ្ធផលក្នុងកម្មវិធីរបស់អ្នក បន្ទាប់មកដំណើរការ INSERT ឬ UPDATE។ រវាងជំហានទាំងនោះ នរណាម្នាក់ទៀតអាចបញ្ចូល row ដូចគ្នា។

Postgres ធ្វើវាក្នុងសេចក្តីថ្លែង atomic តែមួយដោយ ON CONFLICT ដែលតែងហៅថា upsert (update + insert)។ វាពឹងផ្អែកលើ unique constraint ដែលនៅទីនេះគឺមួយលើ email៖

INSERT INTO customers (name, email, city)
VALUES ('Maly Ros', 'maly@example.com', 'Takeo')
ON CONFLICT (email)
DO UPDATE SET city = EXCLUDED.city
RETURNING id, name, city;
 id |     name      | city
----+---------------+-------
  5 | Maly Ros-Chea | Takeo
(1 row)

INSERT 0 1

Maly មានរួចហើយ (id 5) ដូច្នេះជំនួសឱ្យកំហុស duplicate key ដែលអ្នកបានឃើញក្នុងផ្នែកទី 4 row ដែលមានស្រាប់ត្រូវបាន update។ EXCLUDED គឺជាឈ្មោះពិសេសសម្រាប់ "row ដែលខ្ញុំបានព្យាយាមបញ្ចូល" ដូច្នេះ EXCLUDED.city គឺ 'Takeo'។ មានតែ city ប៉ុណ្ណោះដែលត្រូវបានផ្លាស់ប្តូរ៖ ឈ្មោះក្នុង table នៅតែជា Maly Ros-Chea ពីផ្នែកទី 6 ព្រោះ DO UPDATE ប៉ះពាល់តែ column ដែលអ្នកចុះបញ្ជី។

ប្រសិនបើអ្នកចង់ទុក row ដែលមានស្រាប់ឱ្យនៅដដែល ហើយគ្រាន់តែរំលង insert សូមប្រើ DO NOTHING៖

INSERT INTO customers (name, email)
VALUES ('Maly Ros', 'maly@example.com')
ON CONFLICT (email) DO NOTHING;
INSERT 0 0

INSERT 0 0 មានន័យថាបញ្ចូលសូន្យ row ហើយគ្មានកំហុស។ នេះធ្វើឱ្យស្គ្រីប seed និងស្គ្រីបនាំចូលមានសុវត្ថិភាពក្នុងការដំណើរការឡើងវិញ។ ដាក់ city របស់ Maly ត្រឡប់ទៅ NULL ដើម្បីឱ្យត្រូវនឹង seed ឬគ្រាន់តែដំណើរការ seed.sql ម្តងទៀត ដែលក៏ជួសជុលឈ្មោះផងដែរ៖

UPDATE customers
SET city = NULL, name = 'Maly Ros'
WHERE email = 'maly@example.com';

11. សាកល្បងដោយខ្លួនឯង

  1. បន្ថែមផលិតផលពីរ។ បញ្ចូលផលិតផលថ្មីពីរតាមជម្រើសរបស់អ្នកក្នុងសេចក្តីថ្លែង INSERT តែមួយ ដោយប្រើ RETURNING id, name។ តើអ្នកទទួលបាន id អ្វី? ហេតុអ្វីបានជាវាមិនមែន 9 និង 10 ប្រសិនបើអ្នកធ្លាប់មាន insert ដែលបរាជ័យពីមុន?
  2. បង្កឱ្យមានកំហុសនីមួយៗ។ បង្កការបំពាន unique លើ customers, ការបំពាន NOT NULL និងការបំពាន CHECK លើ products។ សម្រាប់នីមួយៗ ចម្លងបន្ទាត់ DETAIL ហើយពន្យល់ដោយពាក្យរបស់អ្នកថាវាប្រាប់អ្វី។
  3. Select មុន ហើយបន្ទាប់មក update។ ឡើងតម្លៃគ្រប់ផលិតផលក្នុងប្រភេទ Books ដោយ 10 ភាគរយ។ ជាដំបូងសរសេរ SELECT បង្ហាញ row ដែលនឹងផ្លាស់ប្តូរ បន្ទាប់មក UPDATE (ជំនួយ៖ price * 1.10)។ ពិនិត្យថាចំនួនក្នុងចម្លើយ UPDATE n ត្រូវនឹង SELECT របស់អ្នក។
  4. គ្រោះមហន្តរាយ table សាកល្បង។ បង្កើតច្បាប់ចម្លងសាកល្បងនៃ customers ដោយ CREATE TABLE customers_scratch AS SELECT * FROM customers។ ដំណើរការ DELETE ដែលគ្មាន WHERE លើវា ពិនិត្យមើលថាសល់ប៉ុន្មាន row បន្ទាប់មកលុបវា (drop)។ ហេតុអ្វី CREATE TABLE ... AS ជាវិធីល្អក្នុងការហាត់?
  5. Upsert តារាងតម្លៃ។ សរសេរសេចក្តីថ្លែង INSERT ... ON CONFLICT សម្រាប់ customers ដែលបន្ថែមអតិថិជនថ្មីប្រសិនបើ email ថ្មី ហើយបើមិនដូច្នោះទេ update តែ name។ ដំណើរការវាពីរដងជាមួយឈ្មោះខុសគ្នា និង email ដូចគ្នា។ តើមានប៉ុន្មាន row ក្នុង table បន្ទាប់ពីនោះ?
  6. សាងសង់ឡើងវិញ។ ធ្វើឱ្យ table ទាំងពីររញ៉េរញ៉ៃ បន្ទាប់មកស្តារវាដោយដំណើរការ seed.sql ជាមួយ -v ON_ERROR_STOP=1។ បញ្ជាក់ដោយ SELECT count(*) លើ table នីមួយៗថាអ្នកត្រឡប់ទៅ 5 អតិថិជន និង 8 ផលិតផលវិញ។

ទៅទីណាបន្ត។ ឥឡូវនេះ table របស់អ្នកមានទិន្នន័យពិត។ អ្វីដែលមានប្រយោជន៍បំផុតដែលអ្នកអាចធ្វើជាមួយទិន្នន័យគឺសួរសំណួរអំពីវា ហើយសម្រាប់នោះអ្នកត្រូវការ SELECT។ ជំពូកបន្ទាប់គ្របដណ្តប់ការច្រោះ ការតម្រៀប ការផ្គូផ្គងលំនាំ ភាពភ្ញាក់ផ្អើលនៃ NULL និងលំដាប់ដែល SQL វាយតម្លៃ query ជាក់ស្តែង៖ ការ Query ដោយ SELECT។

ទិញកាហ្វេជូនខ្ញុំ

ចូលចិត្តមេរៀននេះមែនទេ? សូមពិចារណាទិញកាហ្វេជូនខ្ញុំមួយកែវ ដើម្បីគាំទ្រការបង្កើតមាតិកាឥតគិតថ្លៃបន្ថែមទៀត!