EN813304 · Midterm
บทที่ 5 / 12 · sql-part1.pptx · สัปดาห์ที่ 4

SQL Part 1 — DDL & Basic Queries

CREATE TABLE พร้อม integrity constraint · SELECT / FROM / WHERE · DISTINCT · rename · LIKE · ORDER BY

SQL 60%เขียนโค้ด
หัวข้อในบทนี้

วิดีโอที่อาจารย์ให้ดูก่อนเรียนบทนี้ (แบ่ง 2 ตอน):

Introduction to SQL (Part 1) — ตอนที่ 1
Introduction to SQL (Part 1) — ตอนที่ 2

5.1SQL คืออะไร และแบ่งเป็นกลุ่มไหนบ้าง

SQL (Structured Query Language) เกิดจากภาษา Sequel ที่ IBM พัฒนาในโครงการ System R ที่ห้องวิจัย San Jose ต่อมาเปลี่ยนชื่อเป็น SQL · มาตรฐาน ANSI/ISO ไล่มาตั้งแต่ SQL-86, SQL-89, SQL-92, SQL:1999, SQL:2003

ระบบเชิงพาณิชย์ส่วนใหญ่รองรับฟีเจอร์ SQL-92 เกือบทั้งหมด บวกกับฟีเจอร์จากมาตรฐานรุ่นหลังบางส่วน และฟีเจอร์เฉพาะตัวของแต่ละเจ้า ตัวอย่างในสไลด์บางอันจึงอาจไม่ทำงานบนทุกระบบ

กลุ่มคำสั่งหน้าที่
DDL
Data Definition Language
นิยามโครงสร้าง — schema ของ relation, ชนิดข้อมูล, index, สิทธิ์ · CREATE TABLE, ALTER TABLE, DROP TABLE
DML
Data Manipulation Language
จัดการข้อมูลข้างใน — query · insert · delete · modify tuple · SELECT, INSERT, UPDATE, DELETE
IntegrityDDL มีคำสั่งสำหรับระบุ integrity constraint
View definitionDDL มีคำสั่งสำหรับนิยาม view
Transaction controlระบุจุดเริ่มและจุดจบของ transaction
Embedded & dynamic SQLกำหนดวิธีฝัง SQL ไว้ในภาษาโปรแกรมทั่วไป
Authorizationระบุสิทธิ์การเข้าถึง relation และ view

DDL ของ SQL ให้เราระบุ: schema ของแต่ละ relation · ชนิดของค่าในแต่ละ attribute · integrity constraints · ชุด index ที่ต้องดูแลของแต่ละ relation · ข้อมูลความปลอดภัยและสิทธิ์ · โครงสร้างการจัดเก็บเชิงกายภาพบนดิสก์

Domain Types ใน SQL

ชนิดความหมาย
char(n)สตริงความยาวคงที่ n ตัวอักษร
varchar(n)สตริงความยาวแปรผัน ยาวสูงสุด n
intจำนวนเต็ม (ช่วงขึ้นกับเครื่อง)
smallintจำนวนเต็มขนาดเล็ก
numeric(p,d)เลขทศนิยมตายตัว p หลักรวม ทศนิยม d ตำแหน่ง · numeric(3,1) เก็บ 44.5 ได้ แต่ 444.5 หรือ 0.32 ไม่ได้
real, double precisionทศนิยมลอยตัว ความละเอียดขึ้นกับเครื่อง
float(n)ทศนิยมลอยตัว ความละเอียดอย่างน้อย n หลัก

5.2เชื่อมต่อและสร้างฐานข้อมูล

mysql.server start                    -- เริ่มเซิร์ฟเวอร์
mysql -u root -p                      -- เชื่อมต่อ
mysql -u <username> -p <database>     -- เชื่อมต่อพร้อมเลือก db เลย

CREATE DATABASE uni_demo;
USE uni_demo;                         -- เลือก/สลับฐานข้อมูล
SELECT DATABASE();                    -- ตอนนี้ใช้ db ไหนอยู่
SHOW DATABASES;                       -- มี db อะไรบ้าง
SHOW TABLES;                          -- มีตารางอะไรบ้าง
DESCRIBE Student;                     -- โครงสร้างตาราง (= relation schema)

5.3CREATE TABLE และ Integrity Constraints

รูปแบบทั่วไป:

CREATE TABLE table_name (
    A₁ D₁,
    A₂ D₂,
    …,
    Aₙ Dₙ,
    (integrity-constraint₁),
    …,
    (integrity-constraintₖ)
);

โดย Aᵢ คือชื่อ attribute และ Dᵢ คือชนิดข้อมูลของ domain ของ attribute นั้น

ชนิดของ integrity constraint ที่ต้องรู้: primary key (A₁, …, Aₙ) · foreign key (Aₘ, …, Aₙ) references r · not null
SQL จะปฏิเสธการอัปเดตใด ๆ ที่ทำให้ integrity constraint ถูกละเมิด

ชุดตารางมหาวิทยาลัยจากสไลด์ — ครบทุกแบบของ constraint
CREATE TABLE department (
    dept_name  VARCHAR(20) PRIMARY KEY,
    building   VARCHAR(20),
    budget     NUMERIC(10,0)
);

CREATE TABLE instructor (
    ID         CHAR(5),
    name       VARCHAR(20) NOT NULL,
    dept_name  VARCHAR(20),
    salary     NUMERIC(8,2),
    PRIMARY KEY (ID),
    FOREIGN KEY (dept_name) REFERENCES department
);

CREATE TABLE student (
    ID         VARCHAR(5),
    name       VARCHAR(20) NOT NULL,
    dept_name  VARCHAR(20),
    tot_cred   NUMERIC(3,0),
    PRIMARY KEY (ID),
    FOREIGN KEY (dept_name) REFERENCES department(dept_name)
);

CREATE TABLE course (
    course_id  VARCHAR(8),
    title      VARCHAR(50),
    dept_name  VARCHAR(20),
    credits    NUMERIC(2,0),
    PRIMARY KEY (course_id),
    FOREIGN KEY (dept_name) REFERENCES department(dept_name)
);

-- composite primary key: ต้องใช้ 4 คอลัมน์รวมกันจึงระบุ section ได้
CREATE TABLE section (
    course_id   VARCHAR(8),
    sec_id      VARCHAR(8),
    semester    VARCHAR(6),
    year        NUMERIC(4,0),
    building    VARCHAR(15),      -- ตึกที่ใช้เรียน
    room_number VARCHAR(7),
    PRIMARY KEY (course_id, sec_id, semester, year)
);

-- FK แบบหลายคอลัมน์ ชี้ไปยัง composite PK ของ section
CREATE TABLE takes (
    ID         VARCHAR(5),
    course_id  VARCHAR(8),
    sec_id     VARCHAR(8),
    semester   VARCHAR(6),
    year       NUMERIC(4,0),
    grade      VARCHAR(2),
    PRIMARY KEY (ID, course_id, sec_id, semester, year),
    FOREIGN KEY (ID) REFERENCES student,
    FOREIGN KEY (course_id, sec_id, semester, year)
        REFERENCES section (course_id, sec_id, semester, year)
);
อ่านโค้ดข้างบนให้ครบ — 3 จุดที่มักมองข้าม 1. REFERENCES department ที่ไม่ใส่วงเล็บ หมายความว่าอะไร
สังเกตว่า instructor เขียน REFERENCES department เฉย ๆ แต่ student เขียน REFERENCES department(dept_name)
ตามมาตรฐาน SQL (และในตำราที่อาจารย์ใช้) ละวงเล็บได้ — ถ้าไม่ระบุคอลัมน์ จะใช้ primary key ของตารางปลายทาง โดยปริยาย (PK ของ department คือ dept_name อยู่แล้ว) สองบรรทัดนี้จึงหมายความเหมือนกัน
แต่เวลาเขียนจริง ให้ระบุคอลัมน์ทุกครั้ง — อ่านง่ายกว่ามาก และระบบจริงบางตัวไม่ยอมรับแบบละวงเล็บ → เขียน REFERENCES department(dept_name), REFERENCES student(ID) ไว้ก่อนปลอดภัยที่สุด
ในข้อสอบ ถ้าโจทย์ลอกมาจากสไลด์แบบละวงเล็บ ก็ตอบตามสไลด์ได้ — แต่เขียนครบไม่มีทางผิด


2. composite PK ของ section — ต้องใช้ 4 คอลัมน์รวมกันจึงชี้ได้ว่าเป็นกลุ่มเรียนไหน เพราะวิชาเดียวกันเปิดหลายกลุ่ม หลายเทอม หลายปี

3. FK ของ takes มี 2 อัน คนละแบบ — FOREIGN KEY (ID) REFERENCES student เป็น FK คอลัมน์เดียว ส่วน FOREIGN KEY (course_id, sec_id, semester, year) เป็น FK 4 คอลัมน์ ที่ต้องจับคู่กับ composite PK ของ section ครบทุกคอลัมน์พร้อมกัน — ลำดับคอลัมน์ในวงเล็บต้องตรงกับลำดับที่ประกาศไว้ฝั่ง section ด้วย เพราะการจับคู่เป็นแบบตามตำแหน่ง ไม่ใช่ตามชื่อ — สลับลำดับแล้วระบบจะเอา semester ไปเทียบกับ sec_id โดยไม่ฟ้อง error

เพิ่ม constraint ให้ตารางที่มีอยู่แล้ว

ALTER TABLE table_name ADD PRIMARY KEY (column_name);

ALTER TABLE table_name
  ADD CONSTRAINT fk_name
  FOREIGN KEY (column_name) REFERENCES referenced_table(referenced_column);

INSERT · DELETE · DROP

INSERT INTO instructor VALUES ('10101','Srinivasan','Comp. Sci.', 65000);

DELETE FROM instructor;          -- ลบทุกแถว โครงสร้างยังอยู่
DROP TABLE instructor;           -- ลบทั้งข้อมูลและโครงสร้าง
DELETE vs DROP — ออกสอบแน่ Data vs Structure — DELETE กระทบเฉพาะข้อมูล · DROP กระทบทั้งข้อมูลและโครงสร้าง
Recovery — ข้อมูลที่ลบด้วย DELETE มักกู้คืนได้ง่ายกว่า object ที่ถูก DROP
Performance — ถ้าจะลบข้อมูลทั้งหมดของตารางใหญ่ การ DROP แล้วสร้างใหม่มักเร็วกว่า DELETE

5.4โครงสร้างพื้นฐานของ Query

SELECT A₁, A₂, …, Aₙ      -- attribute ที่ต้องการ
FROM   r₁, r₂, …, rₘ      -- relation ที่เกี่ยวข้อง
WHERE  P;                 -- predicate

ผลลัพธ์ของ SQL query คือ relation เสมอ

SELECT clause — 5 เรื่องที่ต้องรู้

  1. ตรงกับ projection ใน relational algebra · SELECT name FROM instructor
  2. SQL ยอมให้มีแถวซ้ำ ทั้งใน relation และในผลลัพธ์ · SELECT DISTINCT dept_name เพื่อกำจัดซ้ำ · SELECT ALL dept_name เพื่อคงไว้ (เป็นค่าเริ่มต้น)
จุดที่ทฤษฎีกับของจริงไม่ตรงกัน — ออกสอบบ่อย
ทฤษฎี (บทที่ 2–3)SQL ของจริง (บทที่ 5)
relation คืออะไรset — แถวซ้ำกันไม่ได้multiset / bag — แถวซ้ำกันได้
เลือกคอลัมน์Π ตัดแถวซ้ำให้อัตโนมัติSELECT ไม่ตัด — ต้องเขียน DISTINCT เอง
ทำไมถึงต่างกัน: การตัดแถวซ้ำต้องเรียงหรือ hash ข้อมูลทั้งชุดก่อน ซึ่งแพงมาก SQL จึงเลือก “ไม่ตัดให้ ถ้าไม่สั่ง” เพื่อความเร็ว · แต่ตารางที่มี primary key ก็ยังไม่มีแถวซ้ำจริง ๆ อยู่ดี เพราะ PK บังคับไว้ — ที่ซ้ำได้คือผลลัพธ์ของ query หลังจาก project คอลัมน์บางส่วนทิ้งไป

ยกเว้น UNION, INTERSECT, EXCEPT ซึ่งตัดแถวซ้ำให้เหมือนทฤษฎี — ถ้าอยากเก็บซ้ำไว้ต้องเขียน UNION ALL
  1. SELECT * = ทุก attribute · literal ได้โดยไม่มี FROM เช่น SELECT '437' ได้ตาราง 1 คอลัมน์ 1 แถว · ตั้งชื่อคอลัมน์ด้วย SELECT '437' AS FOO
  2. literal พร้อม FROM เช่น SELECT 'A' FROM instructor ได้ตาราง 1 คอลัมน์ N แถว (เท่าจำนวน tuple ใน instructor) ทุกแถวมีค่า 'A'
  3. ใส่นิพจน์คณิตศาสตร์ได้ ด้วย + − * / บนค่าคงที่หรือ attribute · SELECT ID, name, salary/12 AS monthly_salary FROM instructor
Case sensitivity — สับสนกันบ่อย ชื่อใน SQL ไม่สนตัวพิมพ์เล็กใหญ่ — Name ≡ NAME ≡ name · หลายคนนิยมพิมพ์ keyword เป็นตัวใหญ่เพื่อให้อ่านง่าย
แต่ค่าข้อมูลที่เป็นสตริงและ pattern ของ LIKE เป็น case-sensitive — 'Comp. Sci.' ไม่เท่ากับ 'comp. sci.'

WHERE clause

ตรงกับ selection predicate ของ relational algebra · รวมผลการเปรียบเทียบด้วย AND, OR, NOT และเปรียบเทียบผลของนิพจน์คณิตศาสตร์ได้

SELECT name FROM instructor
WHERE  dept_name = 'Comp. Sci.' AND salary > 80000;

FROM clause · Cartesian product vs Join

FROM ตรงกับ Cartesian product ของ relational algebra — SELECT * FROM instructor, teaches สร้างทุกคู่ที่เป็นไปได้ พร้อม attribute จากทั้งสอง relation · attribute ที่ชื่อซ้ำกัน (เช่น ID) จะถูกเปลี่ยนชื่อโดยเติมชื่อ relation นำหน้า เช่น instructor.ID

Cartesian product — ไม่ใส่เงื่อนไข
SELECT name, department.dept_name
FROM   instructor, department;

ฐานข้อมูลตัวอย่างในตำรา Silberschatz มี instructor 12 แถว และ department 7 แถว (ที่นี่อ้างแค่จำนวนแถว ไม่ได้แสดงข้อมูลเต็ม) → ทุกคู่ที่เป็นไปได้ = 12 × 7 = 84 แถว
ในนั้นมีแถวอย่าง “Mozart (Music) คู่กับ Physics” ซึ่งไม่เป็นความจริง — ส่วนใหญ่จึงไร้ความหมาย

Join — ใส่เงื่อนไขจับคู่
SELECT name, department.dept_name
FROM   instructor, department
WHERE  instructor.dept_name = department.dept_name;

เหลือเฉพาะคู่ที่ dept_name ตรงกันจริง = อาจารย์ละ 1 แถว = 12 แถว
(อาจารย์ทุกคนสังกัดได้แผนกเดียว จาก 84 แถวจึงรอด 12 แถว ตกไป 72 แถว)

Rename ด้วย AS — และการ join ตารางกับตัวเอง

-- หาชื่ออาจารย์ที่เงินเดือนสูงกว่าอาจารย์บางคนในภาค COE
SELECT DISTINCT T.name
FROM   instructor AS T, instructor AS S
WHERE  T.salary > S.salary AND S.dept_name = 'COE';

คำว่า AS ละได้ — instructor AS T เท่ากับ instructor T
การให้ชื่อแทน (alias) สองชื่อกับตารางเดียวกัน ทำให้เปรียบเทียบแถวในตารางเดียวกันได้ — เรียกว่า self join

5.5String Operations และ LIKE

SQL มีตัวดำเนินการจับคู่สตริงชื่อ like ซึ่งใช้อักขระพิเศษ 2 ตัว

Patternความหมาย
'Intro%'สตริงที่ขึ้นต้นด้วย "Intro"
'%Comp%'สตริงที่มี "Comp" อยู่ข้างใน
'%ma%'ชื่อที่มี "ma" เป็นสตริงย่อย
'___'สตริงที่ยาวสามตัวพอดี
'___%'สตริงที่ยาวอย่างน้อยสามตัว
'The%Adventure'ขึ้นต้นด้วย "The" และลงท้ายด้วย "Adventure"
'___ of%'มีสามตัวอักษรพอดีก่อนคำว่า " of"
LIKE '100 \%' ESCAPE '\'จับคู่สตริง "100 %" จริง ๆ โดยใช้ backslash เป็นอักขระ escape

Pattern เป็น case-sensitive · SQL ยังรองรับ operation อื่นกับสตริง เช่น การต่อสตริงด้วย || · แปลงตัวพิมพ์ใหญ่เป็นเล็กและกลับกัน · หาความยาว · ตัดสตริงย่อย

โจทย์แบบฝึกหัดข้อ 4 — เขียน LIKE ให้ถูก

a) หนังสือที่ชื่อขึ้นต้นด้วย "The" และลงท้ายด้วย "Adventure" โดยมีอักขระกี่ตัวก็ได้ตรงกลาง

SELECT title FROM books WHERE title LIKE 'The%Adventure';

ได้: The Great Adventure, The Last Jungle Adventure, The Adventure (เพราะ % จับคู่กับช่องว่างตัวเดียวได้)
ไม่ได้: The Adventure Begins เพราะไม่ได้ลงท้ายด้วย Adventure · A Grand Adventure เพราะไม่ได้ขึ้นต้นด้วย The

b) หนังสือที่มีสามตัวอักษรพอดีก่อนคำว่า "of"

SELECT title FROM books WHERE title LIKE '___ of%';

ได้: Age of Empires, Art of War, Sea of Stars
ไม่ได้: Lord of the Rings (4 ตัว), Book of Life (4 ตัว), An of Grammar (2 ตัว)

5.6ORDER BY และ Predicate เพิ่มเติม

SELECT DISTINCT name FROM instructor ORDER BY name;
SELECT * FROM instructor ORDER BY name DESC;
SELECT * FROM instructor ORDER BY dept_name, name;   -- เรียงหลายคอลัมน์

ASC เป็นค่าเริ่มต้น · ระบุ DESC เพื่อเรียงจากมากไปน้อย · กำหนดทิศทางแยกกันแต่ละคอลัมน์ได้

-- BETWEEN: รวมปลายทั้งสองข้าง (>= 60000 AND <= 80000)
SELECT name FROM instructor WHERE salary BETWEEN 60000 AND 80000;

Tuple comparison — เปรียบเทียบหลายคอลัมน์พร้อมกัน

SQL ให้เราเอาคอลัมน์หลายตัวมาใส่วงเล็บแล้วเทียบเป็นชุดเดียว ผลลัพธ์เป็นจริงก็ต่อเมื่อตรงกันครบทุกตำแหน่ง — ตำแหน่งที่ 1 เทียบกับตำแหน่งที่ 1, ตำแหน่งที่ 2 เทียบกับตำแหน่งที่ 2

-- สองบรรทัดนี้ให้ผลเหมือนกันทุกประการ
WHERE (course_id, sec_id) = ('CS-101', '1')
WHERE course_id = 'CS-101' AND sec_id = '1'

ใช้จริงตอนไหน — เมื่อคีย์มีหลายคอลัมน์ (composite key) การเขียนเป็นชุดจะสั้นและอ่านง่ายกว่า:

-- นักศึกษาที่ลงเรียนกลุ่ม CS-101 sec 1 ของ Fall 2017
SELECT ID, grade
FROM   takes
WHERE  (course_id, sec_id, semester, year) = ('CS-101', '1', 'Fall', 2017);
ประโยชน์จริงอยู่ตอนใช้กับ subquery รูปแบบที่จะได้ใช้จริงในบทที่ 8 คือเทียบชุดคอลัมน์กับผลของ subquery:
WHERE (course_id, sec_id, semester, year) IN (
        SELECT course_id, sec_id, semester, year
        FROM   section WHERE building = 'Watson' )
ถ้าไม่มีไวยากรณ์นี้ ต้องเขียนเป็น join หรือ EXISTS ที่ยาวกว่ามาก
ระวัง: ลำดับคอลัมน์ในวงเล็บซ้ายต้องตรงกับลำดับใน SELECT ของ subquery เป๊ะ ๆ สลับกันไม่ได้ — เพราะการจับคู่เป็นแบบตามตำแหน่ง ไม่ใช่ตามชื่อ สลับแล้วระบบจะเทียบผิดคู่โดยไม่ฟ้อง error

5.7โจทย์แบบฝึกหัดในคาบ พร้อมเฉลย

ทุกข้อข้างล่างใช้ชุดข้อมูลนี้ (ตั้งชื่อตารางแบบพหูพจน์ตามใบงาน) — เปิดดูควบคู่กับเฉลยจะเห็นภาพ

instructors
IDnamedept_namesalary
1001SomchaiCOE95000
1002ManeeCOE120000
1003ChujaiCOE90000
1004PreechaEE110000
courses
course_idtitledepartmentcredit
9101Database SystemsCOE3
9102Data StructuresCOE3
9201Circuit AnalysisEE3
students
IDnamedept_name
6601NaraCOE
6602BeamCOE
6603ChompooCOE
6604DewEE
6605EarnCOE
takes
IDcourse_idgrade
66019101A
66029101B
66039101B+
66039102A
66049201C

Earn (6605) ไม่มีแถวใน takes เลย

ข้อ 1 — สร้างตาราง courses และ departments พร้อม constraint ที่เหมาะสม
CREATE TABLE IF NOT EXISTS departments (
    dept_name     VARCHAR(50) PRIMARY KEY,
    building_name VARCHAR(50)
);

CREATE TABLE IF NOT EXISTS courses (
    course_id  INT PRIMARY KEY,
    title      VARCHAR(60) NOT NULL,
    department VARCHAR(50),
    credit     INT CHECK (credit > 0),
    FOREIGN KEY (department) REFERENCES departments(dept_name)
);

สร้าง departments ก่อนเสมอ เพราะ courses อ้างอิงมันด้วย FK — ถ้าสร้างสลับกันจะ error ว่าตารางปลายทางไม่มีอยู่

ข้อ 2 — หาอาจารย์ในภาค COE ที่เงินเดือนเกิน 90,000
SELECT * FROM instructors
WHERE  dept_name = 'COE' AND salary > 90000;

ไล่ทีละแถวจากตาราง instructors ข้างบน → ได้ Somchai (95,000) และ Manee (120,000)
ระวัง: Chujai ได้ 90,000 พอดี → ไม่ผ่าน เพราะโจทย์ใช้ > ไม่ใช่ >= · Preecha (110,000) อยู่ EE จึงไม่เข้าเงื่อนไข

ข้อ 3 — หานักศึกษาทุกคนที่เคยลงวิชาในภาค COE
SELECT DISTINCT s.ID, s.name
FROM   students s, takes t, courses c
WHERE  s.ID = t.ID
  AND  t.course_id = c.course_id
  AND  c.department = 'COE';

หรือเขียนด้วย JOIN แบบชัดเจน (บทที่ 6):

SELECT DISTINCT s.ID, s.name
FROM   students s
JOIN   takes   t ON s.ID = t.ID
JOIN   courses c ON t.course_id = c.course_id
WHERE  c.department = 'COE';

ชื่อคอลัมน์ต้องตรงกับที่ประกาศไว้ในข้อ 1 — ในตาราง courses คอลัมน์ชื่อ department ไม่ใช่ dept_name (ที่เป็นชื่อคอลัมน์ในตาราง departments) เขียนผิดจะได้ ERROR 1054: Unknown column 'c.dept_name'

ไล่ผลลัพธ์ทีละขั้นจากข้อมูลข้างบน:

  1. วิชาของ COE = {9101, 9102} (9201 เป็นของ EE)
  2. แถวใน takes ที่ course_id อยู่ในเซตนั้น = (6601,9101), (6602,9101), (6603,9101), (6603,9102) → 4 แถว
  3. join กับ students แล้วเอาชื่อ → Nara, Beam, Chompoo, Chompoo
  4. DISTINCT ยุบ Chompoo ที่ซ้ำ → Nara, Beam, Chompoo (3 คน)

ทำไมต้อง DISTINCT: Chompoo ลงวิชา COE ไว้ 2 วิชา จึงมี 2 แถวใน takes ที่ผ่านเงื่อนไข ถ้าไม่ใส่ DISTINCT จะได้ 4 แถว โดยมีชื่อ Chompoo โผล่มา 2 ครั้ง
คนที่ไม่เข้าเงื่อนไข: Dew ลงแค่ 9201 ซึ่งเป็นวิชาของ EE · Earn ไม่มีแถวใน takes เลย

ข้อ 4 เป็นโจทย์ LIKE — เฉลยอยู่ใน §5.5 เพราะต้องใช้เรื่อง pattern matching

ข้อ 5 — INSERT ไหนสำเร็จ ไหนล้มเหลว เพราะอะไร

ข้อนี้ใช้ schema เล็ก ๆ ของตัวเอง (ไม่ใช่ชุดข้อมูลด้านบน) ตามที่โจทย์กำหนดมา:

CREATE TABLE Departments (
    dept_id   INT PRIMARY KEY,
    dept_name VARCHAR(50) NOT NULL
);
CREATE TABLE Employees (
    emp_id   INT PRIMARY KEY,
    emp_name VARCHAR(50),
    dept_id  INT,
    FOREIGN KEY (dept_id) REFERENCES Departments(dept_id)
);

INSERT INTO Departments VALUES (1,'HR'), (2,'IT');
-- ตอนนี้ Departments มีอยู่แค่ 2 แถว: dept_id = 1 และ 2 เท่านั้น
a) INSERT INTO Employees VALUES (101, 'John Doe', 2);   -- สำเร็จ
b) INSERT INTO Employees VALUES (102, 'Jane Smith', 4); -- ล้มเหลว

a) สำเร็จ — dept_id = 2 มีอยู่จริงใน Departments (IT) จึงผ่าน foreign key constraint

b) ล้มเหลว — dept_id = 4 ไม่มีอยู่ใน Departments · FK constraint บังคับว่าค่าใน referencing relation ต้องปรากฏเป็นค่า primary key ของ referenced relation จึงเกิด error
ERROR 1452: Cannot add or update a child row: a foreign key constraint fails

นี่คือ referential integrity ทำงาน — ฐานข้อมูลกันข้อมูลขยะให้เราตั้งแต่ต้นทาง


5.8สรุปบทนี้

SELECT 'A' FROM instructor; เมื่อ instructor มี 12 แถว จะได้ผลลัพธ์อย่างไร
literal ที่มี FROM จะถูกคืนออกมา 1 แถวต่อ 1 tuple ในตาราง · ถ้าไม่มี FROM เช่น SELECT '437' จะได้แค่แถวเดียว — สองกรณีนี้ต่างกัน
WHERE title LIKE '___%' จับคู่กับข้อใด
_ สามตัว = อักขระ 3 ตัวพอดี แล้ว % = อีกกี่ตัวก็ได้ (รวมทั้ง 0 ตัว) → อย่างน้อย 3 ตัว · ถ้าอยากได้ 3 ตัวพอดีต้องใช้ '___' เฉย ๆ
ระบบจำไว้ในเบราว์เซอร์นี้ จะได้รู้ว่าอ่านถึงไหนแล้ว