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

ทำตามนี้:

  1. ยืนยัน Error Code 1048
  2. จด Table
  3. จด Column
  4. หา Resource ที่ Query
  5. ดู Parameter ตรง Column
  6. เช็กว่า Variable เป็น nil หรือไม่
  7. ตรวจ Parameter Order
  8. ตรวจ SELECT/Callback ก่อนหน้า
  9. SHOW CREATE TABLE
  10. ตรวจ NOT NULL
  11. ตรวจ DEFAULT
  12. ตรวจ Migration
  13. ตรวจ Framework API
  14. แก้ Source Value
  15. 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

ตรวจทั้งหมดนี้:

  1. Error เป็น 1048 จริงหรือไม่
  2. SQLSTATE 23000 หรือไม่
  3. Table ไหน
  4. Column ไหน
  5. Resource ไหน
  6. Query อะไร
  7. Parameter ไหนตรง Column
  8. Parameter เป็น nil หรือไม่
  9. Parameter Order ถูกหรือไม่
  10. SELECT ก่อนหน้าพบ Row หรือไม่
  11. Callback คืนค่าหรือไม่
  12. Player ยัง Connected หรือไม่
  13. Framework Object มีหรือไม่
  14. Identifier มีหรือไม่
  15. Character ID มีหรือไม่
  16. Config มีค่าหรือไม่
  17. JSON Field มีหรือไม่
  18. Resource Version ตรงไหม
  19. Framework Version ตรงไหม
  20. Migration ครบไหม
  21. Column เป็น NOT NULL หรือไม่
  22. Column มี Default หรือไม่
  23. Default ควรใช้จริงหรือไม่
  24. Column ควร Nullable จริงหรือไม่
  25. Primary Key หรือไม่
  26. AUTO_INCREMENT หรือไม่
  27. Foreign Key หรือไม่
  28. มี Existing NULL Rows หรือไม่
  29. Resource Start Order ถูกหรือไม่
  30. oxmysql Start ก่อน Resource หรือไม่
  31. Async Flow มี Race หรือไม่
  32. Player Disconnect ระหว่าง Query หรือไม่
  33. Transaction เหมาะหรือไม่
  34. ใช้ INSERT IGNORE อยู่หรือไม่
  35. Backup ก่อน Schema Change แล้วหรือไม่

ตาราง Error ที่ควรแยกให้ออก

Errorความหมาย
1048Column ไม่อนุญาต NULL
1054Unknown Column
1062Duplicate Entry
1264Out of Range
1265Data Truncated
1292Truncated Incorrect Value
1364Field ไม่มี Default Value
1366Incorrect Value for Column
1406Data Too Long
1452Foreign 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

Popular posts from this blog

FiveM ยังน่าเล่นไหม? Enhanced เปลี่ยน FiveM แค่ไหน

FiveM คืออะไร เล่นอย่างไร สำหรับมือใหม่ เริ่มต้นตั้งแต่ศูนย์

วิธีตั้ง Admin Permission ด้วย add_ace และ add_principal FiveM แบบละเอียด