SQL-4.3 Join Type Mismatch
นี่คือ THE TRAP — query รันผ่าน ไม่มี error แต่ผลลัพธ์ผิดหมด เพราะ data type ของ column ที่ JOIN ไม่ตรงกัน คุณจะไม่รู้ตัวจนกว่าจะสังเกตว่า “ทำไมได้แค่ 0 แถว?”
สถานการณ์จริง
Section titled “สถานการณ์จริง”สมมติมีคนออกแบบตาราง 2 ตารางโดยคนละคน:
-- คนแรก: student_id เป็น VARCHARCREATE TABLE students ( student_id VARCHAR(6), -- 'STD001' name VARCHAR(100));
-- คนที่สอง: student_id เป็น INTEGERCREATE TABLE scores ( score_id SERIAL, student_id INTEGER, -- 1, 2, 3 score NUMERIC(5,2));ปัญหา: Silent Failure
Section titled “ปัญหา: Silent Failure”-- ใส่ข้อมูลINSERT INTO students VALUES ('1', 'สมชาย');INSERT INTO students VALUES ('2', 'สมหญิง');INSERT INTO scores VALUES (1, 1, 85.50);INSERT INTO scores VALUES (2, 2, 92.00);
-- JOIN: VARCHAR '1' กับ INTEGER 1SELECT s.name, sc.scoreFROM students sINNER JOIN scores sc ON s.student_id = sc.student_id;-- PostgreSQL: อาจ implicit cast → ได้ผล (แต่ช้า!)-- MySQL: implicit cast → ได้ผล (แต่ไม่ใช้ index!)-- SQLite: type affinity → อาจได้ผลหรือไม่ปัญหาที่ร้ายกว่า — CHAR padding:
-- CHAR(10) จะ pad ด้วย spacesCREATE TABLE t1 (id CHAR(10)); -- เก็บ 'STD001 ' (มี spaces ต่อท้าย)CREATE TABLE t2 (id VARCHAR(10)); -- เก็บ 'STD001' (ไม่มี spaces)
-- JOIN นี้อาจล้มเหลว!SELECT * FROM t1INNER JOIN t2 ON t1.id = t2.id;-- 'STD001 ' ≠ 'STD001' → ได้ 0 แถว!Sheets มีปัญหาเดียวกัน:
เซลล์ A1: 001 (ถ้า format เป็น Number จะกลายเป็น 1)เซลล์ B1: 001 (ถ้า format เป็น Text จะเป็น "001")
=A1=B1 → FALSE! (1 ≠ "001")นี่คือเหตุผลที่ VLOOKUP หาไม่เจอ ทั้งที่ดูเหมือนข้อมูลเหมือนกัน
import pandas as pd
students = pd.DataFrame({'student_id': ['1', '2'], 'name': ['สมชาย', 'สมหญิง']})scores = pd.DataFrame({'student_id': [1, 2], 'score': [85.5, 92.0]})
# merge จะ match type ไหม?result = students.merge(scores, on='student_id')print(len(result)) # 0 แถว! string '1' ≠ int 1
# แก้: แปลง type ก่อน mergestudents['student_id'] = students['student_id'].astype(int)result = students.merge(scores, on='student_id')print(len(result)) # 2 แถว ✅#include <stdio.h>#include <string.h>#include <stdlib.h>
int main() { // C แสดงปัญหาชัดเจน: char *str_id = "1"; int int_id = 1;
// เปรียบเทียบตรงไม่ได้ — คนละ type! // str_id คือ pointer ไปยัง char array {'1', '\0'} // int_id คือ 4 bytes เก็บค่า 1
// ต้อง convert ก่อน int converted = atoi(str_id); // string → int if (converted == int_id) { printf("Match! %d == %d\n", converted, int_id); }
// CHAR padding problem: char padded[10] = "STD001 "; // CHAR(10) char unpadded[] = "STD001"; // VARCHAR
printf("strcmp: %d\n", strcmp(padded, unpadded)); // ≠ 0 → ไม่เท่ากัน! return 0;}วิธีแก้: CAST / TRIM
Section titled “วิธีแก้: CAST / TRIM”-- แก้ type mismatch: CAST ให้เป็น type เดียวกันSELECT s.name, sc.scoreFROM students sINNER JOIN scores sc ON CAST(s.student_id AS INTEGER) = sc.student_id;
-- หรือแปลงฝั่ง INTEGER เป็น VARCHARSELECT s.name, sc.scoreFROM students sINNER JOIN scores sc ON s.student_id = CAST(sc.student_id AS VARCHAR);
-- แก้ CHAR padding: ใช้ TRIMSELECT *FROM t1INNER JOIN t2 ON TRIM(t1.id) = t2.id;=VLOOKUP(TEXT(A2, "000"), range, 2, FALSE)ใช้ TEXT() เพื่อให้ format ตรงกัน — หรือ VALUE() เพื่อแปลงเป็นตัวเลข
# แปลง type ก่อน merge เสมอdf1['id'] = df1['id'].astype(str).str.strip()df2['id'] = df2['id'].astype(str).str.strip()result = df1.merge(df2, on='id')// C บังคับให้คุณ convert เอง — ไม่มี implicit cast// atoi() → string to int// sprintf() → int to string// ข้อดี: คุณรู้ตัวเสมอว่ากำลัง convertChecklist ก่อน JOIN
Section titled “Checklist ก่อน JOIN”- ตรวจ type ของทั้งสองคอลัมน์ด้วย
\d table_name(psql) หรือDESCRIBE table_name(MySQL) - ถ้า type ไม่ตรง →
CASTก่อน JOIN - ถ้าใช้
CHAR→TRIMtrailing spaces - ทดสอบด้วย
SELECT COUNT(*)ก่อน — ถ้าได้ 0 แถว น่าสงสัย