คีย์หลักและคีย์ต่างประเทศเข้า SQLite ด้วยตัวอย่าง

⚡ สรุปอย่างชาญฉลาด

คีย์หลักและคีย์รองใน SQLite รักษาความสมบูรณ์ของข้อมูลโดยการระบุแต่ละแถวอย่างไม่ซ้ำกันและเชื่อมโยงตารางที่เกี่ยวข้อง เพื่อให้มั่นใจว่าค่าที่อ้างอิงมีอยู่เสมอ และป้องกันระเบียนที่ซ้ำกัน ค่าว่าง หรือระเบียนที่ไม่มีเจ้าของในฐานข้อมูลเชิงสัมพันธ์

  • 🔑 คีย์หลัก: คีย์หลักใช้ระบุแต่ละแถวได้อย่างเฉพาะเจาะจง และค่าของคีย์หลักต้องไม่ซ้ำกันและห้ามเป็นค่าว่างเด็ดขาด
  • 🧩 คีย์คอมโพสิต: การรวมคอลัมน์สองคอลัมน์ขึ้นไปจะสร้างคีย์หลักแบบผสมเมื่อไม่มีคอลัมน์ใดคอลัมน์หนึ่งมีค่าที่ไม่ซ้ำกัน
  • 🔗 รหัสต่างประเทศ: คีย์ต่างประเทศ (Foreign key) อ้างอิงถึงคีย์ของตารางแม่ และบังคับใช้ความสมบูรณ์ของข้อมูลอ้างอิงระหว่างตารางที่เกี่ยวข้องกัน
  • ⚙️ เปิดใช้งานการบังคับใช้: SQLite โดยค่าเริ่มต้น ระบบจะปิดใช้งานคีย์ต่างประเทศ ดังนั้นให้เรียกใช้คำสั่ง PRAGMA foreign_keys = ON เพื่อเปิดใช้งาน
  • 🧱 ข้อจำกัดของคอลัมน์: กฎ NOT NULL, DEFAULT, UNIQUE และ CHECK จะตรวจสอบความถูกต้องของค่าก่อนที่จะป้อนเข้าสู่คอลัมน์
  • 🤖 ความช่วยเหลือจาก AI: ผู้ช่วย AI แปลงข้อความเป็น SQL และ GitHub Copilot สร้าง SQL หลักและข้อจำกัดจากภาษาอังกฤษธรรมดา

คีย์หลักและคีย์ต่างประเทศเข้า SQLite

หัวข้อด้านล่างนี้จะอธิบาย SQLite อธิบายข้อจำกัดโดยละเอียด เริ่มจาก PRIMARY KEY และ FOREIGN KEY ที่กำหนดและเชื่อมต่อตาราง และครอบคลุมกฎ NOT NULL, DEFAULT, UNIQUE และ CHECK ที่ใช้ตรวจสอบความถูกต้องของข้อมูลในแต่ละคอลัมน์

SQLite ข้อ จำกัด

ข้อจำกัดของคอลัมน์บังคับใช้กฎเกณฑ์กับค่าที่แทรกเข้าไปในคอลัมน์เพื่อตรวจสอบความถูกต้องของข้อมูล ข้อจำกัดเหล่านี้ถูกกำหนดไว้เมื่อสร้างตาราง ภายในคำจำกัดความของคอลัมน์ ข้อจำกัดเหล่านี้ช่วยให้ข้อมูลที่จัดเก็บมีความสอดคล้องและถูกต้องแม่นยำโดยการปฏิเสธค่าที่ฝ่าฝืนกฎที่คุณตั้งไว้ เช่น ค่าซ้ำ ค่าว่าง หรือค่าที่ไม่มีอยู่ในตารางที่เกี่ยวข้อง

SQLite คีย์หลัก

ค่าทั้งหมดในคอลัมน์คีย์หลักต้องไม่ซ้ำกันและต้องไม่ใช่ค่าว่าง คีย์หลักใช้ระบุแต่ละแถวในตารางได้อย่างเฉพาะเจาะจง

คีย์หลักสามารถใช้กับคอลัมน์เดียวหรือหลายคอลัมน์ก็ได้ ในกรณีหลัง ค่าของคอลัมน์เหล่านั้นจะต้องไม่ซ้ำกันในทุกแถวของตาราง

ไวยากรณ์:

มีหลายวิธีในการกำหนดคีย์หลักบนตาราง:

ในคำจำกัดความของคอลัมน์เอง:

ColumnName INTEGER NOT NULL PRIMARY KEY;

เป็นคำจำกัดความแยกต่างหาก:

PRIMARY KEY(ColumnName);

หากต้องการสร้างการรวมคอลัมน์เป็นคีย์หลัก:

PRIMARY KEY(ColumnName1, ColumnName2);

SQLite ข้อจำกัด NOT NULL, DEFAULT, UNIQUE และ CHECK

นอกจากคีย์หลักแล้ว SQLite มีข้อจำกัดหลายประการสำหรับคอลัมน์ที่ใช้ตรวจสอบความถูกต้องของค่าที่ป้อนลงในตาราง ข้อจำกัด NOT NULL, DEFAULT, UNIQUE และ CHECK แต่ละข้อถูกกำหนดไว้ในคำจำกัดความของคอลัมน์ และแต่ละข้อจะบังคับใช้กฎเฉพาะกับคอลัมน์นั้นๆ ประเภทข้อมูล และค่านิยม

ข้อจำกัด NOT NULL

การขอ SQLite ข้อจำกัด NOT NULL ป้องกันไม่ให้คอลัมน์มีค่าว่าง (null):

ColumnName INTEGER  NOT NULL;

ข้อจำกัดเริ่มต้น

กับ SQLite ข้อจำกัด DEFAULT คือ หากคุณไม่ได้ใส่ค่าใดๆ ในคอลัมน์ ระบบจะใส่ค่าเริ่มต้นแทน

ตัวอย่างเช่น:

ColumnName INTEGER DEFAULT 0;

หากคุณเขียนคำสั่งแทรกข้อมูลและไม่ได้ระบุค่าใดๆ สำหรับคอลัมน์นั้น คอลัมน์นั้นจะมีค่าเป็น 0

ข้อจำกัดเฉพาะตัว

การขอ SQLite ข้อจำกัด UNIQUE ป้องกันไม่ให้มีค่าซ้ำกันในคอลัมน์นั้น

ตัวอย่างเช่น:

EmployeeId INTEGER NOT NULL UNIQUE;

การตั้งค่านี้บังคับให้ค่า “EmployeeId” ต้องไม่ซ้ำกัน ไม่อนุญาตให้มีค่าซ้ำกัน โปรดทราบว่าข้อกำหนดนี้ใช้กับค่าในคอลัมน์ “EmployeeId” เท่านั้น

ตรวจสอบข้อจำกัด

การขอ SQLite ข้อจำกัด CHECK กำหนดเงื่อนไขเพื่อตรวจสอบค่าที่ป้อน หากค่าไม่ตรงกับเงื่อนไข ค่าจะไม่ถูกป้อน

Quantity INTEGER NOT NULL CHECK(Quantity > 10);

คุณไม่สามารถใส่ค่าที่น้อยกว่า 10 ในช่อง "จำนวน" ได้

SQLite ต่างประเทศที่สำคัญ

การขอ SQLite คีย์ต่างประเทศ (Foreign Key) คือข้อจำกัดที่ตรวจสอบว่าค่าที่มีอยู่ในตารางหนึ่งนั้นมีอยู่ในอีกตารางหนึ่งที่มีความสัมพันธ์กับตารางแรกที่กำหนดคีย์ต่างประเทศนั้นหรือไม่

ในการทำงานกับหลายตาราง อาจมีบางกรณีที่สองตารางมีความสัมพันธ์กันผ่านคอลัมน์ร่วมกัน หากคุณต้องการให้แน่ใจว่าค่าที่ใส่ในตารางหนึ่งจะต้องมีอยู่ในคอลัมน์ของอีกตารางหนึ่ง คุณควรใช้ข้อจำกัดคีย์ต่างประเทศ (Foreign Key Constraint) กับคอลัมน์ร่วมกันนั้น

ในกรณีนี้ เมื่อคุณพยายามแทรกค่าลงในคอลัมน์นั้น คีย์ต่างประเทศจะตรวจสอบให้แน่ใจว่าค่าที่แทรกเข้าไปนั้นมีอยู่ในคอลัมน์ของตารางที่อ้างอิงอยู่แล้ว

โปรดทราบว่าข้อจำกัดคีย์ต่างประเทศไม่ได้เปิดใช้งานโดยค่าเริ่มต้นใน SQLiteคุณต้องเปิดใช้งานก่อนโดยเรียกใช้คำสั่งต่อไปนี้:

PRAGMA foreign_keys = ON;

มีการนำข้อจำกัดคีย์ต่างประเทศมาใช้ SQLite เริ่มตั้งแต่เวอร์ชัน 3.6.19

ตัวอย่างของการ SQLite ต่างประเทศที่สำคัญ

สมมติว่าเรามีตารางอยู่สองตาราง คือ ตารางนักเรียน และตารางแผนก

ตาราง Students มีรายชื่อนักเรียน และตาราง Departments มีรายชื่อภาควิชา นักเรียนแต่ละคนสังกัดภาควิชาใดภาควิชาหนึ่ง กล่าวคือ นักเรียนแต่ละคนจะมีคอลัมน์ departmentId

ต่อไปนี้เราจะมาดูกันว่าข้อจำกัดคีย์ต่างประเทศ (Foreign Key Constraint) มีประโยชน์อย่างไรในการทำให้มั่นใจว่าค่ารหัสแผนกในตารางนักเรียน (Students) จะต้องมีอยู่ในตารางแผนก (Departments) ด้วย

ดังนั้น หากเราสร้างข้อจำกัดคีย์ต่างประเทศบน DepartmentId ในตาราง Students แต่ละ DepartmentId ที่ถูกแทรกเข้าไปจะต้องมีอยู่ในตาราง Departments ด้วย

CREATE TABLE [Departments] (
	[DepartmentId] INTEGER  NOT NULL PRIMARY KEY AUTOINCREMENT,
	[DepartmentName] NVARCHAR(50)  NULL
);
CREATE TABLE [Students] (
	[StudentId] INTEGER  PRIMARY KEY AUTOINCREMENT NOT NULL,
	[StudentName] NVARCHAR(50)  NULL,
	[DepartmentId] INTEGER  NOT NULL,
	[DateOfBirth] DATE  NULL,
	FOREIGN KEY(DepartmentId) REFERENCES Departments(DepartmentId)
);

เพื่อตรวจสอบว่าข้อจำกัดคีย์ต่างประเทศสามารถป้องกันการแทรกองค์ประกอบหรือค่าที่ไม่กำหนดลงในตารางที่มีความสัมพันธ์กับตารางอื่นได้อย่างไร เราจะพิจารณาตัวอย่างต่อไปนี้

ในตัวอย่างนี้ ตาราง Departments มีความสัมพันธ์แบบคีย์นอกกับตาราง Students ดังนั้นค่า departmentId ใดๆ ที่แทรกเข้าไปในตาราง Students จะต้องมีอยู่ในตาราง Departments ด้วย หากคุณพยายามแทรกค่า departmentId ที่ไม่มีอยู่ในตาราง Departments ข้อจำกัดของคีย์นอกจะป้องกันไม่ให้คุณทำเช่นนั้น

ให้เราเพิ่มสองแผนก ได้แก่ “ไอที” และ “ศิลปะ” ลงในตารางแผนก โดยใช้ข้อมูลดังต่อไปนี้ คำสั่ง INSERT:

INSERT INTO Departments VALUES(1, 'IT');
INSERT INTO Departments VALUES(2, 'Arts');

คำสั่งทั้งสองนี้จะเพิ่มแผนกสองแผนกเข้าไปในตาราง Departments คุณสามารถตรวจสอบว่าค่าทั้งสองถูกเพิ่มเข้าไปแล้วหรือไม่โดยการเรียกใช้คำสั่ง “SELECT * FROM Departments” ในภายหลัง:

ผลลัพธ์จากคำสั่ง SELECT ที่แสดงแผนกไอทีและแผนกศิลปะใน SQLite

จากนั้นลองเพิ่มนักเรียนใหม่โดยใช้ departmentId ที่ไม่มีอยู่ในตาราง Departments:

INSERT INTO Students(StudentName,DepartmentId) VALUES('John', 5);

ข้อมูลแถวจะไม่ถูกเพิ่ม และคุณจะได้รับข้อผิดพลาดว่า: ข้อจำกัด FOREIGN KEY ล้มเหลว

SQLite ข้อความแสดงข้อผิดพลาด "ข้อจำกัด FOREIGN KEY ล้มเหลว"

ความแตกต่างระหว่างคีย์หลักและคีย์รองใน SQLite

คีย์หลักและคีย์รองต่างก็ช่วยรักษาความถูกต้องของข้อมูล แต่มีบทบาทที่แตกต่างกัน คีย์หลักใช้ระบุแถวภายในตารางเดียว ในขณะที่คีย์รองเชื่อมโยงแถวระหว่างสองตารางที่เกี่ยวข้องกัน ตารางด้านล่างสรุปความแตกต่างหลักๆ ไว้

ฐาน คีย์หลัก ต่างประเทศที่สำคัญ
จุดมุ่งหมาย ระบุแต่ละแถวในตารางได้อย่างเฉพาะเจาะจง อ้างอิงถึงคีย์หลักของตารางอื่นเพื่อเชื่อมโยงตารางทั้งสองเข้าด้วยกัน
ความเป็นเอกลักษณ์ ค่าต่างๆ ต้องมีความเป็นเอกลักษณ์ ค่าต่างๆ อาจซ้ำกันได้ ดังนั้นแถวข้อมูลย่อยหลายแถวจึงอาจมีแถวข้อมูลหลักเดียวกัน
ค่า Null ไม่สามารถเป็นค่าว่างได้ สามารถเป็นค่าว่างได้เมื่อความสัมพันธ์เป็นทางเลือก
จำนวนต่อโต๊ะ แต่ละตารางมีคีย์หลักเพียงหนึ่งเดียวเท่านั้น ตารางหนึ่งสามารถมีคีย์ต่างประเทศได้หลายคีย์
การจัดทำดัชนี จัดทำดัชนีโดยอัตโนมัติ ไม่ได้ถูกจัดทำดัชนีโดยอัตโนมัติ โปรดเพิ่มดัชนีเพื่อประสิทธิภาพที่ดีขึ้น

ในตัวอย่างเรื่องนักเรียนและภาควิชา DepartmentId เป็นคีย์หลักของตาราง Departments และเป็นคีย์นอกในตาราง Students ซึ่งเป็นตัวเชื่อมโยงนักเรียนแต่ละคนเข้ากับภาควิชาที่ถูกต้อง

SQLite คีย์หลักแบบผสม

คีย์หลักแบบผสม คือ คีย์หลักที่สร้างขึ้นจากสองคอลัมน์ขึ้นไป โดยใช้ในกรณีที่ไม่มีคอลัมน์ใดคอลัมน์หนึ่งมีค่าที่ไม่ซ้ำกัน แต่การรวมกันของคอลัมน์เหล่านั้นจะมีค่าที่ไม่ซ้ำกันสำหรับทุกแถว SQLite ถือว่าค่าที่รวมกันเป็นคีย์เดียว

ตัวอย่างเช่น ตารางการลงทะเบียนอาจอนุญาตให้นักเรียนคนเดียวกันลงทะเบียนในหลายวิชา และอนุญาตให้นักเรียนหลายคนลงทะเบียนในวิชาเดียวกันได้ แต่คู่ของนักเรียนและวิชาแต่ละคู่ควรปรากฏเพียงครั้งเดียวเท่านั้น:

CREATE TABLE Enrollments (
	StudentId INTEGER NOT NULL,
	CourseId INTEGER NOT NULL,
	Grade TEXT,
	PRIMARY KEY (StudentId, CourseId)
);

ในกรณีนี้ ทั้ง StudentId และ CourseId อาจไม่ซ้ำกันเมื่ออยู่เดี่ยวๆ แต่คู่ของ StudentId และ CourseId นั้นไม่ซ้ำกัน ดังนั้นนักเรียนคนเดียวกันจึงไม่สามารถลงทะเบียนเรียนในหลักสูตรเดียวกันได้สองครั้ง โปรดสังเกตประเด็นต่อไปนี้เมื่อคุณใช้คีย์แบบผสม:

  • ใช้คีย์ผสมเมื่อคอลัมน์เดียวไม่สามารถระบุแถวได้อย่างเฉพาะเจาะจง
  • คอลัมน์ทุกคอลัมน์ในคีย์ผสมต้องเป็นไปตามกฎของคีย์หลัก ดังนั้นค่าที่รวมกันจะต้องไม่ซ้ำกันและไม่ใช่ค่าว่าง
  • คีย์ผสมจะถูกเขียนไว้ในส่วนของคำสั่ง PRIMARY KEY แยกต่างหากในระดับตาราง ไม่ใช่ภายในคำจำกัดความของคอลัมน์เดียว

SQLite การดำเนินการคีย์นอก: เมื่อลบ และ เมื่ออัปเดต

คีย์นอกยังสามารถควบคุมสิ่งที่เกิดขึ้นกับแถวลูกเมื่อแถวแม่ที่อ้างอิงถูกลบหรืออัปเดตได้อีกด้วย การกระทำที่เกี่ยวข้องกับการอ้างอิงเหล่านี้จะถูกเพิ่มเข้าไปในส่วนของคำสั่ง ON DELETE และ ON UPDATE เมื่อคุณกำหนดคีย์นอก SQLite สนับสนุนการดำเนินการห้าประการ:

  • ไม่มีการดำเนินการ — การดำเนินการเริ่มต้น ซึ่งจะแสดงข้อผิดพลาดหากแถวย่อยยังคงอ้างอิงถึงแถวหลักอยู่
  • จำกัด — ป้องกันการลบหรืออัปเดตทันที ก่อนที่การเปลี่ยนแปลงอื่นใดจะเกิดขึ้น
  • ตั้งค่าเป็นโมฆะ — กำหนดค่าคอลัมน์คีย์ต่างประเทศของลูกให้เป็นค่าว่าง (null)
  • ตั้งค่าเริ่มต้น — กำหนดค่าให้กับคอลัมน์คีย์นอกของลูกเป็นค่าเริ่มต้นที่ประกาศไว้
  • น้ำตก — การเปลี่ยนแปลงนี้จะใช้หลักการเดียวกันกับแถวของลูก ดังนั้นการลบแถวหลักจะลบแถวของลูกไปด้วย

ตัวอย่างด้านล่างนี้สร้างตารางนักเรียนขึ้นใหม่ โดยที่การลบแผนกจะลบนักเรียนในแผนกนั้นโดยอัตโนมัติ และการอัปเดตรหัสแผนกจะอัปเดตนักเรียนที่ตรงกัน:

CREATE TABLE Students (
	StudentId INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
	StudentName NVARCHAR(50) NULL,
	DepartmentId INTEGER NOT NULL,
	FOREIGN KEY(DepartmentId) REFERENCES Departments(DepartmentId)
		ON DELETE CASCADE
		ON UPDATE CASCADE
);

โปรดจำไว้ว่า การดำเนินการอ้างอิงจะทำงานก็ต่อเมื่อเปิดใช้งานการสนับสนุนคีย์ต่างประเทศเท่านั้น ดังนั้นให้รันคำสั่ง PRAGMA foreign_keys = ON ในตอนเริ่มต้นของการเชื่อมต่อทุกครั้ง หากไม่ทำเช่นนั้น... SQLite วิเคราะห์เงื่อนไข ON DELETE และ ON UPDATE แต่ไม่บังคับใช้เงื่อนไขเหล่านั้น

คำถามที่พบบ่อย

ใช่แล้ว เมื่อกำหนดคอลัมน์เดียวเป็น INTEGER PRIMARY KEY คอลัมน์นั้นจะกลายเป็นชื่อแทน rowid ในตัวของตาราง SQLite ไม่มีการสร้างดัชนีแยกต่างหากสำหรับคีย์นั้น ดังนั้นการค้นหาด้วยคีย์นั้นจึงรวดเร็วและไม่ใช้พื้นที่จัดเก็บเพิ่มเติม

โดยค่าเริ่มต้น การบังคับใช้คีย์ต่างประเทศจะถูกปิดใช้งาน เพื่อรักษาความเข้ากันได้กับฐานข้อมูลและสคริปต์รุ่นเก่าที่เขียนขึ้นก่อนเวอร์ชัน 3.6.19 การเชื่อมต่อฐานข้อมูลแต่ละครั้งจะต้องเรียกใช้คำสั่ง PRAGMA foreign_keys = ON ก่อน SQLite เริ่มตรวจสอบข้อจำกัดคีย์ต่างประเทศ

SQLite ระบบจะสร้างดัชนีให้กับคีย์หลักและคอลัมน์ UNIQUE โดยอัตโนมัติ แต่จะไม่สร้างดัชนีให้กับคอลัมน์คีย์ต่างประเทศ เนื่องจากมีการอ่านคอลัมน์ลูกทุกครั้งที่มีการตรวจสอบข้อจำกัด จึงแนะนำให้สร้างดัชนีของคุณเองบนคอลัมน์คีย์ต่างประเทศแต่ละคอลัมน์เพื่อประสิทธิภาพที่ดีขึ้น

ไม่ ALTER TABLE ใน SQLite ไม่สามารถเพิ่มคีย์หลักหรือคีย์รองลงในตารางที่มีอยู่แล้วได้ คุณต้องเปลี่ยนชื่อตารางเดิม สร้างตารางใหม่โดยกำหนดคีย์ จากนั้นคัดลอกแถวด้วยคำสั่ง INSERT SELECT แล้วจึงลบตารางเดิมทิ้ง

คีย์หลักแบบจำนวนเต็มธรรมดาจะกำหนด ID ถัดไปเป็นค่าที่สูงกว่า rowid ที่ใหญ่ที่สุดที่มีอยู่ และสามารถนำ ID กลับมาใช้ใหม่ได้หลังจากลบข้อมูลแล้ว (เพิ่มค่าอัตโนมัติ) tracks คือรหัสประจำตัวสูงสุดที่เคยใช้ใน sqlite_sequence และจะไม่นำค่าเดิมกลับมาใช้ซ้ำอีก โดยมีผลกระทบต่อประสิทธิภาพการทำงานเพียงเล็กน้อย

ข้อผิดพลาดนี้จะปรากฏขึ้นเมื่อคุณแทรกหรืออัปเดตแถวข้อมูลลูกที่มีค่าคีย์ต่างประเทศไม่ตรงกับแถวในตารางหลัก หรือเมื่อคุณลบแถวข้อมูลหลักที่ยังมีแถวข้อมูลลูกอยู่ โปรดแทรกข้อมูลหลักก่อน

ใช่แล้ว ระบบ AI แปลงข้อความเป็น SQL จะแปลงคำอธิบายตารางของคุณที่เป็นภาษาอังกฤษธรรมดาให้เป็นคำสั่ง CREATE TABLE พร้อมด้วยเงื่อนไข PRIMARY KEY และ FOREIGN KEY การให้ข้อมูลโครงสร้างตารางที่มีอยู่จะช่วยเพิ่มความแม่นยำ และควรตรวจสอบ SQL ที่สร้างขึ้นก่อนนำไปใช้กับข้อมูลจริงเสมอ

ใช่. นักบิน GitHub แนะนำให้ใส่โค้ด CREATE TABLE ที่มี PRIMARY KEY, FOREIGN KEY และข้อจำกัดอื่นๆ ไว้ในบรรทัดเดียวกันในโปรแกรมแก้ไขข้อความ เช่น VS Codeโปรแกรมจะอ่านโครงสร้างฐานข้อมูลและไฟล์การย้ายข้อมูลที่มีอยู่ของคุณ ดังนั้นการเติมข้อมูลอัตโนมัติจึงใช้ชื่อตารางและชื่อคอลัมน์จริงของคุณ

สรุปโพสต์นี้ด้วย: