FiveM MariaDB Column Cannot Be Null แก้อย่างไร? วิธีแก้ Error 1048 เมื่อ Resource ส่ง NULL ลง Column ที่ห้ามว่าง
FiveM MariaDB Error 1048 Column cannot be null เกิดเมื่อ Resource พยายาม INSERT หรือ UPDATE ค่า NULL ลงใน Column ที่ Database กำหนดเป็น NOT NULL โดย MariaDB กำหนด Error นี้เป็น 1048, SQLSTATE 23000 และชื่อ ER_BAD_NULL_ERROR.
ตัวอย่าง:
ERROR 1048 (23000): Column 'identifier' cannot be null
หรือ:
Column 'character_id' cannot be null Column 'owner' cannot be null Column 'name' cannot be null
สำหรับ FiveM ปัญหานี้มักไม่ได้หมายความว่า MariaDB เสีย แต่หมายความว่า ข้อมูลที่ Resource คิดว่าจะมีค่า กลับกลายเป็น nil/NULL ก่อนถึง Database
แนวทางตรวจที่ถูกต้องคือ:
Error 1048 ↓ ดู Column ที่เป็น NULL ↓ ดู Resource ที่ยิง Query ↓ ดู Parameter จริง ↓ หาเหตุผลว่าทำไมค่าเป็น nil ↓ SHOW CREATE TABLE ↓ ตรวจ NOT NULL / DEFAULT ↓ ตัดสินว่า ต้องมีค่าจริง? หรือควรอนุญาต NULL? ↓ แก้ Root Cause
① Error 1048 คืออะไร
MariaDB ระบุ Error นี้ว่า:
1048 23000 ER_BAD_NULL_ERROR
พร้อมข้อความ:
Column '%s' cannot be null
ตัวอย่าง Table:
CREATE TABLE `characters` ( `id` INT NOT NULL, `identifier` VARCHAR(100) NOT NULL );
หาก Resource ส่ง:
INSERT INTO `characters` ( `id`, `identifier` ) VALUES ( 10, NULL );
MariaDB จะปฏิเสธ เพราะ identifier ถูกกำหนดเป็น NOT NULL.
② NULL คืออะไร
ใน MariaDB:
NULL
หมายถึงไม่มีค่า หรือค่าที่ไม่ทราบ
มันไม่ใช่:
0
ไม่ใช่:
''
และไม่ใช่:
false
MariaDB จัดการ NULL เป็นค่าพิเศษแยกจากค่าปกติของ Data Type.
ดังนั้นต้องแยกให้ออกระหว่าง:
NULL
กับ:
Empty String ''
③ NOT NULL คืออะไร
ถ้า Schema กำหนด:
`identifier` VARCHAR(100) NOT NULL
หมายความว่า Row นี้ต้องมีค่า identifier
ห้าม:
NULL
MariaDB จึงคืน Error 1048 หาก Explicitly Insert NULL ลง Column ลักษณะนี้.
④ FiveM ทำไมถึงส่ง NULL ได้
สาเหตุที่พบบ่อย:
① Lua Variable เป็น nil ② Query Parameter ผิดลำดับ ③ SELECT ก่อนหน้าไม่พบ Player ④ Identifier หาไม่เจอ ⑤ Character Data ยังโหลดไม่เสร็จ ⑥ Resource Start Order ผิด ⑦ Config ไม่มีค่า ⑧ JSON Decode แล้ว Field หาย ⑨ Framework API เปลี่ยน ⑩ Script Update แต่ Database/Code คนละ Version ⑪ Player Disconnect ระหว่าง Workflow ⑫ Callback คืน nil
นี่คือเหตุผลที่ Error 1048 ควรเริ่ม Debug จาก ค่าใน Resource ก่อน ALTER Database
⑤ ตัวอย่าง Lua Variable เป็น nil
สมมติ:
local identifier = player.identifier
แต่:
player.identifier = nil
แล้ว Resource ทำ:
MySQL.insert.await([[ INSERT INTO `characters` (`identifier`, `name`) VALUES (?, ?) ]], { identifier, characterName })
หาก Database Driver ส่งค่าดังกล่าวเป็น SQL NULL และ Column identifier เป็น NOT NULL ก็จะชน Error 1048 ตาม Constraint ของ MariaDB.
⑥ อย่าแก้ nil เป็น Empty String ทุกครั้ง
Developer บางคนแก้แบบ:
local identifier = player.identifier or ''
Error 1048 อาจหาย เพราะ:
''
ไม่ใช่ NULL
แต่ข้อมูลจะกลายเป็น:
identifier = ''
ซึ่งอาจผิดหนักกว่าเดิม
ถ้า identifier เป็น Key สำคัญ Resource ควรหยุด Operation เมื่อไม่มี Identifier ไม่ใช่สร้าง Character ที่ Owner เป็น Empty String
⑦ อย่าแก้ nil เป็น 0 ทุกครั้ง
เช่น:
local characterId = data.characterId or 0
ถ้าค่าเดิมหาย คุณเปลี่ยน:
NULL Error
เป็น:
character_id = 0
จากนั้นอาจเจอ:
Foreign Key Error Player หาไม่เจอ ข้อมูลผูก Owner ผิด
แทน
ดังนั้น:
nil → 0
ไม่ใช่วิธีแก้ทั่วไป
⑧ nil ควรจัดการตาม Business Rule
ถามว่า Field นี้หมายถึงอะไร
ตัวอย่าง:
identifier
ส่วนใหญ่ควร:
ไม่มี → หยุด Operation
แต่:
deleted_at
อาจออกแบบให้:
ไม่มี → NULL
ได้
ดังนั้นการอนุญาต NULL ต้องมาจาก Data Model ไม่ใช่จากความต้องการให้ Console ไม่มี Error
⑨ วิธีดูว่า Column เป็น NOT NULL หรือไม่
ใช้:
SHOW CREATE TABLE `characters`;
แล้วหา:
`identifier` varchar(100) NOT NULL
หรือ:
`deleted_at` datetime DEFAULT NULL
SHOW CREATE TABLE เป็นวิธีตรงในการตรวจ Table Definition จริงที่ Database กำลังใช้งาน.
⑩ อย่าดู install.sql อย่างเดียว
ไฟล์ Resource อาจมี:
`owner` VARCHAR(100) NULL
แต่ Production Database จริงอาจเป็น:
`owner` VARCHAR(100) NOT NULL
เพราะ Migration คนละ Version
ดังนั้นต้องตรวจ:
SHOW CREATE TABLE `table_name`;
จาก Database จริงก่อนแก้
⑪ Error หลัง Update Script
ถ้า FiveM ใช้งานได้ก่อน Update แต่หลัง Update เริ่ม:
Column 'x' cannot be null
ให้ตรวจ:
Resource Version Migration SQL Framework Version API Return Values Schema ปัจจุบัน
Resource Version ใหม่อาจต้องการข้อมูลเพิ่มเติม หรือ API เดิมที่เคยคืนค่าอาจเปลี่ยน Behavior
⑫ Error หลังเปลี่ยน Framework
สมมติ Script เก่าใช้:
Player.identifier
แต่ Framework ใหม่ใช้:
Player.PlayerData.citizenid
Custom Resource ยังเรียก API เดิม
ผล:
identifier = nil
แล้ว Query:
INSERT ↓ NULL ↓ Error 1048
ตรงนี้ Schema อาจถูกต้องทั้งหมด แต่ Application Layer ผิด
⑬ Parameter Order ผิดทำ NULL ไปผิด Column ได้
ตัวอย่าง:
MySQL.insert.await([[ INSERT INTO `characters` (`identifier`, `name`, `job`) VALUES (?, ?, ?) ]], { identifier, job, name })
ถ้า:
job = nil
Database จะได้รับ:
name = NULL
แทนที่จะเป็น:
job = NULL
ดังนั้น Error อาจบอก:
Column 'name' cannot be null
ทั้งที่ต้นเหตุจริงคือ Parameter Mapping
⑭ ตรวจ Parameter ทั้งชุด ไม่ใช่เฉพาะตัวที่ Error
เมื่อ Error บอก:
Column 'name' cannot be null
อย่าตรวจเพียง Variable name
ต้องเทียบ:
SQL Placeholder 1 SQL Placeholder 2 SQL Placeholder 3
กับ:
Value 1 Value 2 Value 3
ทั้งหมด
เพราะ Parameter ที่สลับลำดับสามารถทำให้ NULL ไปลง Column คนละตัว
⑮ oxmysql Placeholder
oxmysql prepare รองรับ ? เป็น Value Placeholder ตาม Documentation ปัจจุบัน.
ตัวอย่าง:
MySQL.prepare.await( 'SELECT * FROM `characters` WHERE `identifier` = ?', { identifier } )
ดังนั้นเมื่อใช้:
?
หลายตำแหน่ง ต้องให้ Values ตรงลำดับอย่างเคร่งครัด
⑯ SELECT ไม่พบ Row เป็นสาเหตุสำคัญ
สมมติ:
local player = MySQL.single.await( 'SELECT `id`, `identifier` FROM `players` WHERE `license` = ?', { license } )
oxmysql single ถูกออกแบบให้คืนข้อมูลของ Row เดียวเมื่อมีผลลัพธ์.
Resource ต้องจัดการกรณี:
ไม่พบ Row
ก่อนทำ:
local id = player.id
แล้วส่งไป Query ต่อ
⑰ ตรวจผล SELECT ก่อนใช้งาน
Pattern ที่ปลอดภัยกว่า:
local player = MySQL.single.await( 'SELECT `id`, `identifier` FROM `players` WHERE `license` = ?', { license } ) if not player then return end if not player.id then return end
จากนั้นจึงทำ INSERT/UPDATE ต่อ
อย่าคิดว่า:
SELECT = ต้องเจอ Row เสมอ
⑱ Query คืน nil ไม่ได้แปลว่า Database เสีย
อาจเกิดเพราะ:
WHERE ผิด identifier ผิด Player ยังไม่มี Data ถูกลบ Database คนละตัว Migration ไม่ครบ
ดังนั้นเมื่อค่าจาก SELECT กลายเป็น nil ต้องหาเหตุผลว่า Query ไม่พบข้อมูลก่อน
⑲ วิธีเช็ก NULL ใน SQL
MariaDB ใช้:
IS NULL
และ:
IS NOT NULL
สำหรับตรวจ NULL โดยตรง.
ตัวอย่าง:
SELECT * FROM `characters` WHERE `owner` IS NULL;
ไม่ควรใช้:
WHERE `owner` = NULL
เพื่อตรวจ NULL
⑳ หา Existing NULL Records
ถ้ากำลังเตรียม Migration Column เป็น NOT NULL ให้ตรวจ:
SELECT * FROM `characters` WHERE `identifier` IS NULL;
หากพบ Records จำนวนมาก ต้องตัดสินใจก่อนว่า:
ข้อมูลหายเพราะอะไร? สามารถ Recovery ได้ไหม? ควร Delete ไหม? ควร Fill ค่าไหม?
อย่า ALTER ก่อนรู้ Existing Data
㉑ DEFAULT ต่างจาก NULL อย่างไร
MariaDB รองรับ DEFAULT สำหรับกำหนดค่าที่ใช้เมื่อ Statement ไม่ได้ส่งค่าให้ Column ตามเงื่อนไขของ Column Definition.
ตัวอย่าง:
`status` VARCHAR(20) NOT NULL DEFAULT 'active'
ถ้า INSERT ไม่ระบุ Column status Database สามารถใช้ Default ตาม Definition ได้.
แต่เรื่องสำคัญคือ:
ไม่ส่ง Column
กับ:
ส่ง NULL ให้ Column
ไม่ใช่กรณีเดียวกันเสมอไป
㉒ Explicit NULL ไม่เท่ากับละ Column ออก
ตัวอย่าง:
INSERT INTO `users` ( `name` ) VALUES ( 'John' );
กับ:
INSERT INTO `users` ( `name`, `status` ) VALUES ( 'John', NULL );
Database ต้องตีความต่างกันตาม Column Definition
ดังนั้นอย่าคิดว่า:
ส่ง NULL = ให้ Database ใช้ DEFAULT
โดยอัตโนมัติ
㉓ ถ้าต้องการ Default ให้ใช้ Logic ให้ถูก
สมมติ:
`status` VARCHAR(20) NOT NULL DEFAULT 'active'
ถ้าต้องการ Default จริง สามารถออกแบบ Query ให้ไม่ส่ง status ในกรณีที่ไม่มีค่า หรือใช้ DEFAULT ตาม SQL Semantics ที่เหมาะสม.
อย่าใช้:
nil
โดยหวังว่า MariaDB จะเลือก Default ให้ทุกกรณี
㉔ Error 1048 กับ Error 1364 ต่างกัน
Error:
1048 Column cannot be null
หมายถึงมีความพยายามใช้ NULL กับ Column ที่ไม่อนุญาต.
ส่วน Error:
1364 Field doesn't have a default value
มักเกี่ยวข้องกับ Required Column ที่ไม่ได้รับค่าและไม่มี Default ตาม Context ของ Statement.
ดังนั้นต้องอ่าน Error Code จริงก่อนแก้
㉕ Error 1048 กับ Error 1366 ต่างกัน
จากบทความก่อน:
1366 Incorrect value for column
เช่น:
INT ← "abc"
แต่:
1048
คือ:
NOT NULL Column ← NULL
หนึ่งคือชนิดข้อมูลไม่ถูกต้อง
อีกหนึ่งคือไม่มีค่าเลย
㉖ Error 1048 กับ Error 1452 ต่างกัน
1048
หมายถึง Key/Column ไม่มีค่า:
character_id = NULL
ส่วน Foreign Key Error เช่น 1452 หมายถึง:
character_id = 999
มีค่าแล้ว แต่ Parent Row 999 ไม่มี
ดังนั้น:
NULL
กับ:
Invalid Foreign Key
เป็นคนละ Root Cause
㉗ Error 1048 กับ Error 1054
1054 Unknown Column
คือ Column ไม่มีหรือชื่อผิด
แต่:
1048
คือ Column มีอยู่และ Database รู้ว่า Column นั้นไม่ยอมรับ NULL
จึงไม่ควรสร้าง Column ใหม่เมื่อ Error เป็น 1048
㉘ Error 1048 กับ Empty String
ถ้า Column:
`identifier` VARCHAR(100) NOT NULL
MariaDB อาจยอมรับ:
''
เพราะ Empty String ไม่ใช่ NULL
แต่นั่นไม่ได้หมายความว่า Empty String ถูกต้องสำหรับ FiveM Business Logic
Database Constraint:
NOT NULL
เพียงบอกว่า:
ห้ามไม่มีค่า
ไม่ได้บอกว่า:
ห้าม String ว่าง
เสมอไป
㉙ NOT NULL ไม่แทน Application Validation
ตัวอย่าง:
character_name
อาจถูกกำหนด:
VARCHAR(50) NOT NULL
Database ป้องกัน NULL
แต่ยังอาจรับ:
''
ได้ตาม Schema/Rules
ดังนั้น Resource ยังต้อง Validate:
ชื่อว่างไหม ยาวเกินไหม Format ถูกไหม
ก่อน Query
㉚ Client Input ต้อง Validate
ถ้า Client ส่ง:
characterName job garageId targetId
Server ไม่ควรเชื่อว่าทุก Field มีค่า
ควรตรวจ:
if not characterName then return end
หรือ Validation ที่เหมาะสมตาม Type/Business Rule
ก่อน Database
㉛ ค่า nil จาก Client Event ต้องระวัง
เช่น:
RegisterNetEvent('character:create', function(data) local name = data.name end)
ถ้า Client ส่ง:
data.name = nil
Resource ที่ไม่ Validate จะพา NULL ไปถึง Database
Server-side Validation จึงสำคัญกว่าพึ่ง Error 1048 เป็นด่านแรก
㉜ Client ไม่ควรกำหนด Owner เอง
Fields เช่น:
owner identifier character_id account_id
ควรดึงหรือยืนยันฝั่ง Server ตาม Architecture ของ Framework
ไม่ควรเชื่อ:
Client ส่ง owner มา
โดยตรง
นอกจากปัญหา NULL ยังเกี่ยวกับ Authorization/Data Integrity ด้วย
㉝ Identifier ควรหาให้เสร็จก่อน Transaction
Pattern:
Get Player ↓ Validate Identifier ↓ Validate Character ↓ เริ่ม Database Operation
ดีกว่า:
เริ่ม Queries ↓ ระหว่างทางค่อยหา Identifier ↓ ได้ nil ↓ 1048
ลดโอกาส Partial Workflow
㉞ Transaction ช่วยอะไร
oxmysql ระบุว่า Transaction จะ Commit เมื่อ Queries ทั้งหมดสำเร็จ และถ้ามี Query ใดล้มเหลวจะไม่มี Queries ในชุดถูก Commit.
ดังนั้นถ้า Workflow เป็น:
Create Character Create Inventory Create Settings
แล้ว Query Settings ชน Error 1048
Transaction สามารถช่วยไม่ให้ Character/Inventory ถูก Commit ครึ่งชุด หากทั้งสาม Operation ต้อง Atomic
㉟ แต่ Transaction ไม่แก้ NULL
ถ้า:
identifier = nil
การครอบ:
MySQL.transaction
ไม่ได้สร้าง Identifier ให้
ยังต้องแก้:
Data Retrieval Validation Parameter Mapping Framework Logic
ก่อน
㊱ ตรวจ Default ก่อน ALTER NULL
ก่อนเปลี่ยน:
NOT NULL
เป็น:
NULL
ให้ดู:
DEFAULT PRIMARY/UNIQUE Foreign Key Application Queries
ทั้งหมด
ถ้า Field เป็น:
identifier
การอนุญาต NULL อาจทำให้ Records ที่ไม่มี Owner ถูกสร้างขึ้น
㊲ อย่า ALTER NOT NULL เป็น NULL เพื่อให้ Error หาย
ตัวอย่าง:
ALTER TABLE `characters` MODIFY COLUMN `identifier` VARCHAR(100) NULL;
อาจทำให้ 1048 หาย
แต่ถ้า Resource ต้องการ Identifier ทุก Character จริง คุณกำลังลบ Safety Constraint ของ Database
ควรแก้ Resource ที่ส่ง nil แทน
㊳ เมื่อไหร่ควรอนุญาต NULL
ตัวอย่าง Field ที่อาจมีเหตุผล:
deleted_at last_vehicle_id optional_note expires_at
หาก Business Rule บอกว่า:
ยังไม่มีค่า
เป็นสถานะที่ถูกต้อง
Column อาจออกแบบ Nullable ได้
แต่ต้องเป็นการตัดสินใจ Data Model ไม่ใช่ Debug Shortcut
㊴ PRIMARY KEY เป็น NULL ได้ไหม
MariaDB ระบุว่า Primary Key Columns ถูกบังคับเป็น NOT NULL โดยธรรมชาติของ Primary Key Constraint.
ดังนั้นถ้า:
id
เป็น Primary Key
ไม่ควรออกแบบให้ NULL
㊵ AUTO_INCREMENT เป็นกรณีพิเศษ
MariaDB ระบุว่า Numeric AUTO_INCREMENT Column มีพฤติกรรมพิเศษเมื่อ Insert NULL: Database สามารถสร้างเลขถัดไปจาก Auto-increment Sequence ให้.
ตัวอย่าง:
CREATE TABLE `characters` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(100) NOT NULL );
โดยปกติ Application สามารถละ id ออกจาก INSERT และปล่อย Database จัดการ ID
㊶ อย่าสับสน AUTO_INCREMENT NULL กับ Column ปกติ
ถ้า:
id AUTO_INCREMENT
รับ NULL แล้วสร้างเลขใหม่ได้
ไม่ได้หมายความว่า:
identifier NOT NULL
จะทำแบบเดียวกัน
MariaDB ระบุพฤติกรรมพิเศษนี้เฉพาะกรณีอย่าง Auto-increment/Timestamp/Virtual Columns ตาม Context.
㊷ INSERT ID ควรให้ Database สร้างเมื่อ Schema ออกแบบแบบนั้น
oxmysql MySQL.insert ใช้เพิ่ม Row และคืน Insert ID เมื่อมีค่าที่เหมาะสม.
ตัวอย่าง:
local id = MySQL.insert.await([[ INSERT INTO `characters` (`identifier`, `name`) VALUES (?, ?) ]], { identifier, characterName })
ถ้า id เป็น AUTO_INCREMENT ก็ไม่จำเป็นต้องสร้าง ID เองใน Resource
㊸ Error 1048 หลัง Player Disconnect
Flow อาจเป็น:
Player Connect ↓ เริ่ม Async Operation ↓ Player Disconnect ↓ Player Object ถูกล้าง ↓ Callback ทำงานต่อ ↓ identifier = nil ↓ INSERT ↓ 1048
ดังนั้น Async Workflow ต้องตรวจว่า Context ยัง Valid ก่อนบันทึก
㊹ Error เกิดเฉพาะบางครั้ง
ถ้า 1048 ไม่ได้เกิดทุกครั้ง แต่เกิดแบบ:
วันหนึ่ง 2–3 ครั้ง
ให้สงสัย:
Race Condition Async Timing Player Disconnect Resource Restart Missing Callback Result
มากกว่า Schema ผิดทั้งระบบ
เพราะถ้า Column Schemaผิดกับ Resourceตลอด มักเกิด Errorซ้ำใน Flowเดียวกันอย่างสม่ำเสมอ
㊺ Error เกิดกับทุก Player
ถ้าหลัง Update แล้วทุก Playerเจอ:
Column 'identifier' cannot be null
ให้ตรวจ:
Framework API เปลี่ยน Variable Name เปลี่ยน Migration Resource Dependency Initialization
ก่อนตรวจ Player Record ทีละคน
㊻ Resource Start Order เกี่ยวได้
สมมติ Custom Resourceต้องใช้ Framework Object หรือ Database-loaded Player Data
แต่ Resource เริ่มทำงานก่อน Dependency พร้อม
ค่าที่ควรมีอาจเป็น:
nil
ดังนั้นควรใช้ Dependency/Initialization Flow ของ Framework/Resource ตามที่ออกแบบไว้
อย่าแก้ Database ให้ยอม NULL เพื่อหลบ Startup Race
㊼ oxmysql ต้องพร้อมก่อน Resource ที่ใช้ Database
Official oxmysql Setup ระบุให้ตั้ง Connection String และ Start oxmysql ก่อน Resources ที่ต้องใช้งาน Database.
หาก Architecture Start Order ผิด ควรแก้ Dependency/Configuration ให้ตรง ไม่ใช่เพิ่ม Retry แบบสุ่มทุก Query
㊽ mysql_debug ช่วยหา Resource ได้
oxmysql ระบุว่า Query Speeds/Debug Information สามารถดูใน Debug UI และ Server Console เมื่อเปิด mysql_debug.
เมื่อ Error 1048 เกิด ให้จับ:
Timestamp Resource Query Column
จากนั้นไปดู Parameter ก่อน Query
㊾ Log nil ก่อน Query
ตัวอย่าง:
print( 'identifier:', identifier, 'characterId:', characterId, 'name:', characterName )
หรือดีกว่าให้ Validate:
if not identifier then print('Missing identifier') return end
เพื่อหยุดก่อน Database Error
㊿ อย่า Log Sensitive Data เกินจำเป็น
ถ้าต้อง Debug Identifier อาจ Log:
Resource Player source Field missing Character ID
โดยไม่จำเป็นต้อง Dump:
Tokens Passwords Connection String Private Data ทั้ง Record
ลง Console
51. ใช้ IFNULL แก้ได้ไหม
MariaDB มี:
IFNULL(expr1, expr2)
ซึ่งจะคืน Argument แรกเมื่อไม่เป็น NULL และใช้ Argument ที่สองเมื่อ Argument แรกเป็น NULL.
ตัวอย่าง:
SELECT IFNULL(`nickname`, 'Unknown') FROM `players`;
แต่ IFNULL() เหมาะกับ SQL Logic บางกรณี ไม่ใช่คำตอบทั่วไปสำหรับ Required Identifier ที่หาย
52. อย่าใช้ IFNULL เพื่อซ่อน Required Data
ตัวอย่างไม่ควรทำแบบสุ่ม:
INSERT INTO `characters` ( `identifier` ) VALUES ( IFNULL(?, 'unknown') );
เพราะถ้า Identifier หายจริง Database จะเต็มไปด้วย:
unknown
หลาย Records
Error 1048 เดิมมีประโยชน์มากกว่า เพราะช่วยบอกว่า Required Dataหาย
53. INSERT IGNORE ช่วยไหม
MariaDB IGNORE สามารถเปลี่ยน Errors หลายประเภทเป็น Warnings และรายการที่รองรับรวม Error 1048 ER_BAD_NULL_ERROR.
ดังนั้น:
INSERT IGNORE ...
อาจทำให้ Behavior ต่างจาก Statement ปกติ
แต่ ไม่ควรใช้เป็น Root-cause Fix
54. ทำไม INSERT IGNORE อันตรายกับ Error 1048
ถ้า Resource ต้องการ:
owner = license:abc
แต่จริงๆ ส่ง:
owner = NULL
การใช้ IGNORE เพื่อให้ Queryไม่หยุดไม่ได้สร้าง Owner ที่ถูกต้องให้
คุณอาจได้:
Query ดูเหมือนผ่าน แต่ข้อมูลไม่ตรงกับ Resource
MariaDB เองระบุว่า IGNORE ใช้เปลี่ยน Errors หลายประเภทให้เป็น Warnings.
55. DEFAULT ช่วยไหม
ช่วยเฉพาะเมื่อ Default นั้นเป็น Business Value ที่ถูกต้อง
ตัวอย่าง:
`status` VARCHAR(20) NOT NULL DEFAULT 'active'
เหมาะกว่า:
identifier DEFAULT 'unknown'
ในหลาย Data Models
ดังนั้น Default ต้องสะท้อนความหมายของ Field จริง
56. Required Field ไม่ควรมี Fake Default
Field เช่น:
owner account_id character_id identifier
มักมีความสัมพันธ์กับ Entity จริง
การกำหนด:
DEFAULT 0 DEFAULT 'unknown'
เพียงเพื่อป้องกัน 1048 อาจสร้าง Orphan/Invalid Records
ให้แก้ Source Value ก่อน
57. Error หลัง Import Database
ถ้า Database เดิม Column:
owner NULL
แต่ Schema ใหม่:
owner NOT NULL
และ Existing Data มี NULL Records
Migration หรือ Write Operations อาจเริ่มเจอปัญหา
ก่อนเพิ่ม NOT NULL ให้ตรวจ:
SELECT * FROM `table_name` WHERE `owner` IS NULL;
ก่อนเสมอ
58. Error หลัง Restore Backup
Backup เก่าอาจมี:
NULL
ใน Fields ที่ Schemaใหม่กำหนด Required
ถ้า Restore แล้ว Apply Migrationไม่ครบ:
Old Data + New Resource + Mixed Schema
สามารถสร้าง Error ต่อเนื่องได้
ควร Migration Data/Schema ตาม Version ไม่ใช่ลบ NULLแบบสุ่ม
59. NULL Cleanup ต้อง Backup ก่อน
ถ้าพบ:
10,000 rows owner IS NULL
อย่าทำทันที:
DELETE FROM ... WHERE owner IS NULL;
ต้องรู้ก่อนว่า:
ข้อมูล Recover ได้ไหม? สัมพันธ์กับ Tables อื่นไหม? เกิดจาก Migration หรือ Bug?
Bulk Cleanup ใน Production ต้องมี Backup
60. วิธีแก้ Error 1048 แบบ 5 นาที
เมื่อ Console ขึ้น:
Column 'identifier' cannot be null
ทำตามนี้:
-
ยืนยัน Error Code
1048 - จด Table
- จด Column
- หา Resource ที่ Query
- ดู Parameter ตรง Column
-
เช็กว่า Variable เป็น
nilหรือไม่ - ตรวจ Parameter Order
- ตรวจ SELECT/Callback ก่อนหน้า
-
SHOW CREATE TABLE -
ตรวจ
NOT NULL -
ตรวจ
DEFAULT - ตรวจ Migration
- ตรวจ Framework API
- แก้ Source Value
- Test Flow เดิม
61. ตัวอย่าง Debug Identifier
Error:
Column 'identifier' cannot be null
Code:
local identifier = Player.identifier MySQL.insert.await([[ INSERT INTO `characters` (`identifier`, `name`) VALUES (?, ?) ]], { identifier, name })
Debug:
identifier = nil
ตรงนี้ไม่ต้อง ALTER Database
ต้องหาว่า:
Player.identifier
ยังเป็น API ที่ถูกต้องของ Framework Version ปัจจุบันหรือไม่
62. ตัวอย่าง SELECT ไม่พบ
local player = MySQL.single.await( 'SELECT * FROM `players` WHERE `license` = ?', { license } )
ถ้า:
player = nil
แล้ว Resourceทำ:
local playerId = player and player.id
ผล:
playerId = nil
จากนั้น INSERTลง Required Column ก็ชน 1048
Root Cause คือ:
Player Row ไม่พบ
ไม่ใช่ Column Definition
63. ตัวอย่าง Optional Field
สมมติ:
deleted_at
หมายถึงเวลาที่ Record ถูกลบ
ก่อนถูกลบ:
deleted_at = NULL
เป็น State ที่มีเหตุผล
Column จึงอาจออกแบบ:
`deleted_at` DATETIME NULL
ได้ตาม Business Rule
นี่คือตัวอย่างที่ Nullable Column มีความหมายจริง
64. ตัวอย่าง Required Field
character.owner
หาก Character ทุกตัวต้องมี Owner
ควร:
NOT NULL
และ Resource ต้องหา Owner ให้ได้ก่อน Insert
Error 1048 ในกรณีนี้เป็น Protection ที่ควรเก็บไว้ ไม่ใช่ Constraint ที่ควรลบ
65. Checklist FiveM Error 1048
ตรวจทั้งหมดนี้:
- Error เป็น 1048 จริงหรือไม่
- SQLSTATE 23000 หรือไม่
- Table ไหน
- Column ไหน
- Resource ไหน
- Query อะไร
- Parameter ไหนตรง Column
-
Parameter เป็น
nilหรือไม่ - Parameter Order ถูกหรือไม่
- SELECT ก่อนหน้าพบ Row หรือไม่
- Callback คืนค่าหรือไม่
- Player ยัง Connected หรือไม่
- Framework Object มีหรือไม่
- Identifier มีหรือไม่
- Character ID มีหรือไม่
- Config มีค่าหรือไม่
- JSON Field มีหรือไม่
- Resource Version ตรงไหม
- Framework Version ตรงไหม
- Migration ครบไหม
-
Column เป็น
NOT NULLหรือไม่ - Column มี Default หรือไม่
- Default ควรใช้จริงหรือไม่
- Column ควร Nullable จริงหรือไม่
- Primary Key หรือไม่
- AUTO_INCREMENT หรือไม่
- Foreign Key หรือไม่
- มี Existing NULL Rows หรือไม่
- Resource Start Order ถูกหรือไม่
- oxmysql Start ก่อน Resource หรือไม่
- Async Flow มี Race หรือไม่
- Player Disconnect ระหว่าง Query หรือไม่
- Transaction เหมาะหรือไม่
-
ใช้
INSERT IGNOREอยู่หรือไม่ - Backup ก่อน Schema Change แล้วหรือไม่
ตาราง Error ที่ควรแยกให้ออก
| Error | ความหมาย |
|---|---|
1048 | Column ไม่อนุญาต NULL |
1054 | Unknown Column |
1062 | Duplicate Entry |
1264 | Out of Range |
1265 | Data Truncated |
1292 | Truncated Incorrect Value |
1364 | Field ไม่มี Default Value |
1366 | Incorrect Value for Column |
1406 | Data Too Long |
1452 | Foreign Key Constraint Fail |
MariaDB Error Reference ระบุ 1048 เป็น ER_BAD_NULL_ERROR โดยตรง.
FiveM Column Cannot Be Null แก้อย่างไร
เริ่มจากดูค่าที่ Resource ส่ง:
Column = identifier Parameter = ? Actual value = nil
จากนั้นดู Schema:
SHOW CREATE TABLE `characters`;
ถ้า Column เป็น:
`identifier` VARCHAR(100) NOT NULL
ให้หาว่าทำไม Identifier หายก่อน ไม่ควรรีบเปลี่ยนให้ Nullable
FiveM Error 1048 คืออะไร
MariaDB Error 1048 คือ:
ER_BAD_NULL_ERROR
SQLSTATE:
23000
พร้อมข้อความ:
Column '...' cannot be null
FiveM Identifier Cannot Be Null แก้อย่างไร
ตรวจ:
Player Object Framework API Identifier Function Parameter Order Player Disconnect
ถ้า Identifier เป็น Required Value ควรหยุด Operation เมื่อหา Identifier ไม่ได้
ไม่ควรใช้:
'' 0 unknown
เป็น Fake Identifier
FiveM Character ID Cannot Be Null แก้อย่างไร
ตรวจว่า Character ถูกสร้างหรือ Load สำเร็จก่อน Query ต่อหรือไม่
Flow ควรเป็น:
Create / Load Character ↓ ได้ Character ID ↓ ตรวจ ID ↓ ทำ Query ที่ต้องใช้ ID
ไม่ใช่ Query Child Data ขณะที่ Character ID ยังไม่มี
FiveM Owner Cannot Be Null แก้อย่างไร
หา Owner จาก Server-side Identity ที่เชื่อถือได้ก่อน
ถ้า Field เป็น Required Ownership Key ไม่ควรแก้ด้วยการให้ Columnรับ NULL เพียงเพื่อให้ Insertผ่าน
FiveM เปลี่ยน NOT NULL เป็น NULL ได้ไหม
ทำได้เมื่อ Business Rule ระบุว่า Field สามารถไม่มีค่าได้จริง
แต่ไม่ควรทำเพียงเพราะ Resourceส่ง nil
ถ้า Column เป็น Identifier, Owner หรือ Required Key การอนุญาต NULL อาจลด Data Integrity
FiveM ใช้ DEFAULT แทน NULL ได้ไหม
ได้เฉพาะ Field ที่มี Default ที่มีความหมาย เช่น:
status = active
MariaDB รองรับ Default Values ตาม Column Definition.
แต่ Required Identity Fields ไม่ควรมี Fake Default
FiveM NULL กับ Empty String เหมือนกันไหม
ไม่
NULL ≠ ''
MariaDB จัดการ NULL เป็น Missing/Unknown Value แยกต่างหาก.
ดังนั้นการเปลี่ยน NULL เป็น Empty Stringเพียงเพื่อให้ Errorหายไม่ได้แปลว่าข้อมูลถูกต้อง
FiveM NULL กับ 0 เหมือนกันไหม
ไม่
NULL
หมายถึงไม่มีค่า
0
เป็น Numeric Value จริง
อย่าใช้ศูนย์เป็นตัวแทน Missing ID หาก Data Model ไม่ได้กำหนดแบบนั้น
FiveM INSERT IGNORE แก้ 1048 ได้ไหม
MariaDB ระบุ Error 1048 อยู่ในกลุ่ม Errors ที่ IGNORE สามารถเปลี่ยน Behavior ให้เป็น Warning ได้.
แต่ไม่ควรใช้เพื่อซ่อน Required Data ที่หาย เพราะไม่ได้แก้ต้นเหตุว่า Resourceส่ง NULL ทำไม
FiveM Transaction ช่วย Error 1048 ได้ไหม
Transaction ไม่แก้ NULL แต่ช่วยรักษา Atomicity
หากหนึ่ง Queryชน 1048 และ Workflowต้องสำเร็จทั้งหมด oxmysql Transaction จะไม่ Commit Queries ในชุดเมื่อหนึ่ง Queryล้มเหลว.
FiveM AUTO_INCREMENT ใส่ NULL ได้ไหม
MariaDB มีพฤติกรรมพิเศษสำหรับ Numeric AUTO_INCREMENT Column โดยการ Insert NULL สามารถทำให้ Databaseใช้ค่าถัดไปจาก Auto-increment Sequence.
แต่ Behavior นี้ไม่ใช้กับ NOT NULL Columns ทั่วไป
FiveM ดู NULL Rows ยังไง
ใช้:
SELECT * FROM `characters` WHERE `owner` IS NULL;
MariaDB ใช้ IS NULL สำหรับตรวจ NULL.
และ:
SELECT * FROM `characters` WHERE `owner` IS NOT NULL;
สำหรับ Rows ที่มีค่า.
FiveM mysql_debug ช่วยได้ไหม
ได้ oxmysql ระบุว่า Real Query Speeds/Debug Information สามารถดูใน Server Console หรือ Debug UI เมื่อเปิด mysql_debug.
ใช้หา:
Resource Query เวลาที่ Error เกิด
แล้วตรวจ Parameters ใน Resource Code
FAQ FiveM MariaDB Error 1048
Error 1048 คืออะไร?
คือ MariaDB ER_BAD_NULL_ERROR เมื่อ Column ที่ไม่อนุญาต NULL ได้รับค่า NULL.
SQLSTATE 23000 คืออะไร?
MariaDB ใช้ SQLSTATE 23000 กับ Error 1048 ใน Error Reference.
NOT NULL คืออะไร?
หมายถึง Column ต้องมีค่าตาม Constraint และไม่รับ NULL ใน Operation ปกติที่เกี่ยวข้อง.
NULL กับ Empty String เหมือนกันไหม?
ไม่ NULL คือ Missing/Unknown Value ส่วน Empty String เป็น String Value จริง.
ใช้ Empty String แทน NULL ได้ไหม?
ทำได้ทาง Syntax ใน String Column บางแบบ แต่ไม่ควรใช้หาก Business Data ต้องมีค่าจริง เช่น Identifier หรือ Owner
ใช้ 0 แทน NULL ได้ไหม?
ควรทำเฉพาะเมื่อ 0 เป็นค่าที่ถูกต้องตาม Data Model ไม่ควรใช้เพื่อซ่อน Missing ID
เปลี่ยน Column เป็น NULLABLE ดีไหม?
ดีเฉพาะเมื่อ Field เป็น Optional จริง ไม่ควรเปลี่ยน Required Identifier/Owner เพียงเพราะ Resourceมี Bug
DEFAULT ใช้แทนได้ไหม?
ได้เมื่อ Default เป็นค่าที่มีความหมายและ Columnถูกออกแบบไว้แบบนั้น.
AUTO_INCREMENT รับ NULL ได้ไหม?
Numeric AUTO_INCREMENT Column มีพฤติกรรมพิเศษที่ MariaDBสามารถสร้างค่าถัดไปให้เมื่อ Insert NULL.
Error หลัง Update Script เกิดจากอะไร?
ควรตรวจ Framework API, Resource Version, Parameter Mapping และ Database Migration ก่อน เพราะค่าที่เคยมีอาจกลายเป็น nil หลัง Code/API เปลี่ยน
Transaction แก้ได้ไหม?
ไม่แก้ Missing Value แต่ช่วยให้หลาย Queries ไม่ถูก Commit ครึ่งชุดเมื่อ Query หนึ่งล้มเหลว.
INSERT IGNORE ควรใช้ไหม?
ไม่ควรใช้เป็นวิธีแก้ Root Cause แม้ MariaDB จะสามารถเปลี่ยน Error 1048 เป็น Warning ภายใต้ IGNORE ได้.
ประเด็นสำคัญ
เมื่อ FiveM ขึ้น:
ERROR 1048 Column '...' cannot be null
ให้จำว่า จุดแรกที่ควรตรวจไม่ใช่ ALTER TABLE แต่คือค่าที่ Resource ส่ง
ใช้ Flow นี้:
1048 ↓ Column ไหน ↓ Parameter ไหน ↓ ค่าเป็น nil จริงไหม ↓ SELECT/Callback ก่อนหน้าสำเร็จไหม ↓ Parameter Order ถูกไหม ↓ Framework API ถูกไหม ↓ SHOW CREATE TABLE ↓ Field ควร Required หรือ Optional ↓ แก้ Root Cause
MariaDB กำหนด Error 1048 โดยตรงสำหรับ Column cannot be null และ NULL เป็นค่าพิเศษที่ต่างจาก 0 และ Empty String. ดังนั้นการเปลี่ยน nil เป็น '', 0 หรือ 'unknown' อาจทำให้ Error หาย แต่ไม่ได้หมายความว่าข้อมูลถูกต้อง
หาก Column เป็น Optional จริงจึงค่อยพิจารณา Nullable Schema หรือ Default ที่มีความหมาย แต่หากเป็น identifier, owner, character_id หรือ Required Relationship ควรรักษา NOT NULL ไว้และแก้ Resource ให้หา Value ให้ได้ก่อน Query
สำหรับผู้อ่าน comsiam ให้จำสูตร “1048 = ตามหา nil ก่อนแก้ Schema” และ comsiam แนะนำให้ตรวจ 4 จุดพร้อมกันคือ Variable → Parameter → Query → Column Definition เพราะ Error Column cannot be null จำนวนมากเกิดจากค่าหายระหว่าง Lua/Framework Workflow มากกว่าปัญหาที่ MariaDB เอง
Comments
Post a Comment