สถานการณ์
ต้องการ Select ข้อมูลจากตารางหนึ่ง แล้ว Insert เข้าไปในอีกตารางหนึ่ง หลายครั้ง (หลายชุดค่า) ในคำสั่งเดียว
วิธีแก้: INSERT INTO ... SELECT ... UNION ALL SELECT ...
ตัวอย่างการใช้งาน
1. สร้างตารางปลายทาง (DemoTable1)
mysql> CREATE TABLE DemoTable1 (
-> StudentName VARCHAR(20),
-> StudentMarks INT
-> );
Query OK, 0 rows affected (0.67 sec)
2. สร้างตารางต้นทาง (DemoTable2)
mysql> CREATE TABLE DemoTable2 (
-> Name VARCHAR(20)
-> );
Query OK, 0 rows affected (0.61 sec)
3. เพิ่มข้อมูลต้นทาง
mysql> INSERT INTO DemoTable2 VALUES('Chris');
Query OK, 1 row affected (0.12 sec)
4. Insert หลายชุดข้อมูลด้วย UNION ALL
mysql> INSERT INTO DemoTable1
-> SELECT Name, 89 FROM DemoTable2
-> UNION ALL
-> SELECT Name, 98 FROM DemoTable2;
Query OK, 2 rows affected (0.15 sec)
Records: 2 Duplicates: 0 Warnings: 0
5. ตรวจสอบผลลัพธ์
mysql> SELECT * FROM DemoTable1;
ผลลัพธ์:
+-------------+--------------+ | StudentName | StudentMarks | +-------------+--------------+ | Chris | 89 | | Chris | 98 | +-------------+--------------+ 2 rows in set (0.00 sec)
UNION vs UNION ALL
| คำสั่ง | Duplicate Rows | Performance |
|---|---|---|
| UNION | ลบซ้ำ (DISTINCT) | ช้ากว่า (ต้อง Sort/Hash) |
| UNION ALL | เก็บทุกแถว | เร็วกว่า |
รูปแบบทั่วไป
INSERT INTO TargetTable (Col1, Col2, Col3) SELECT ColA, ColB, 'StaticValue' FROM SourceTable1 UNION ALL SELECT ColX, ColY, 'AnotherValue' FROM SourceTable2 UNION ALL SELECT ColP, ColQ, ColR FROM SourceTable3 WHERE SomeCondition;
กรณีการใช้งานจริง
- ETL: รวมข้อมูลจากหลาย Source Table เข้า Data Warehouse
- Audit Log: Insert Event ประเภทต่างๆ จาก Table ต่างๆ เข้า Log Table เดียว
- Reporting: สร้าง Snapshot Table จากหลาย Fact Table
- Test Data Generation: สร้างข้อมูลทดสอบหลาย Pattern
ข้อควรระวัง
- Column Count และ Data Type ต้องตรงกันทุก SELECT ใน UNION
- Column Name ใช้จาก SELECT ตัวแรก
- ORDER BY ใน UNION ต้องอยู่ท้ายสุด และใช้ Position (ORDER BY 1, 2)
- LIMIT ใน UNION ต้องอยู่ท้ายสุด (ใช้กับ Parentheses)
Transaction Safety
START TRANSACTION; INSERT INTO TargetTable ... SELECT ... UNION ALL SELECT ...; -- Verify SELECT COUNT(*) FROM TargetTable WHERE ...; COMMIT; -- หรือ ROLLBACK