ป้ายกำกับ: String

WordPress: แทรก tag IDWordPress: แทรก tag ID

จากที่เคยเขียน MySQL: แทรก id ที่ว่างอยู่ จะเขียน advance ขี้น โดยจะเอา string list มา insert รายการที่ id ถูกข้ามไป หรือลบไปในการเขียนบทความ SQL ทคนิคการจัดการฐานข้อมูลที่น่าสนใจอย่างหนึ่งคือการ “เติมเต็มช่องว่าง” (Fill the Gaps) ของ Primary Key ที่หายไป บทความนี้จะอธิบายการทำงานของ SQL Script ซึ่งใช้สำหรับเพิ่มข้อมูลลงในตารางของ WordPress (wp_terms) โดยฉลาดพอที่จะหา ID ที่ว่างอยู่มาใช้งานครับ Tag (ป้ายกำกับ) และ Category (หมวดหมู่) ของ WordPress


💡 แนวคิดการ Insert ข้อมูลลงใน Gap ID

ปกติแล้วเวลาเรา INSERT ข้อมูลที่มีคุณสมบัติ AUTO_INCREMENT ตัวเลขจะรันต่อไปเรื่อย ๆ แม้ว่าเราจะลบข้อมูลเก่าออกไปแล้วทำให้เกิดช่องว่าง (Gap) เช่น 1, 2, 5, 6 (เลข 3 และ 4 หายไป)

Script นี้ถูกออกแบบมาเพื่อ นำเลข 3 และ 4 กลับมาใช้ใหม่ ก่อนที่จะไปใช้เลขใหม่ล่าสุดครับ

🛠 เจาะลึกการทำงานของ SQL

โครงสร้างของ Query นี้ใช้ CTE (Common Table Expressions) แบ่งการทำงานเป็น 4 ขั้นตอนหลัก

  1. เตรียมข้อมูล (RawData)
    ใช้ JSON_TABLE เพื่อแปลงรายการคำที่ต้องการ (Tags) จากรูปแบบ JSON ให้กลายเป็นตารางข้อมูลเสมือน เพื่อความสะดวกในการเปรียบเทียบกับฐานข้อมูลเดิม
  2. ตรวจสอบข้อมูลซ้ำ (TagStatus)
    ทำการ LEFT JOIN กับตารางจริงเพื่อเช็คว่า Tag ไหนมีอยู่แล้วบ้าง เพื่อป้องกันการเพิ่มข้อมูลซ้ำ (Duplication)
  3. ค้นหาช่องว่าง (AvailableIDs)
    นี่คือหัวใจของบทความนี้ครับ Script จะมองหาเลข ID ที่ “แหว่ง” ไป โดยใช้ตรรกะ
    1. หา term_id + 1 ที่ไม่มีอยู่ในตารางปัจจุบัน
    2. จำกัดขอบเขตไม่ให้เกิน MAX (term_id) เพื่อไม่ให้ไปทับกับเลขที่รันต่อตามปกติ
  4. จับคู่และ Insert (Final Select)
    นำ Tag ใหม่ที่ยังไม่มีในระบบ มาจับคู่กับ gap_id ที่หาได้แบบ 1 ต่อ 1 ผ่านแถวลำดับ (ROW_NUMBER) แล้วทำการ INSERT เข้าสู่ตาราง wp_terms พร้อมสร้าง slug ให้อัตโนมัติ

⚠️ ข้อควรระวังในการใช้งาน

การดึง ID ที่ว่างกลับมาใช้ใหม่มีข้อดีคือทำให้เลขเรียงสวยงาม แต่มีสิ่งที่ต้องพิจารณา ดังนี้

  • Data Integrity: หากมีตารางอื่นอ้างอิง (Foreign Key) ถึง ID เก่าที่เคยลบไป การนำ ID นั้นมาใช้ใหม่อาจทำให้เกิดความสับสนของข้อมูลได้
  • Performance: ในฐานข้อมูลที่มีขนาดใหญ่มาก การรัน Query เพื่อหา Gap ทุกครั้งอาจใช้ทรัพยากรสูงกว่าการปล่อยให้ Auto Increment ทำงานไปตามปกติ
  • Collation: ในตัวอย่างมีการใช้ utf8mb4_unicode_520_ci เพื่อรองรับภาษาไทยและอักขระพิเศษ ต้องตรวจสอบให้แน่ใจว่า Collation นี้ตรงกับโครงสร้างตารางจริงของคุณ

add ID in wp_terms gap script

-- =====================================================================
-- 1. สร้าง Temporary Table สำหรับพักคำศัพท์ใหม่จาก JSON เท่านั้น
-- =====================================================================
CREATE TEMPORARY TABLE temp_next_tags (

id INT AUTO_INCREMENT PRIMARY KEY,

tag_name VARCHAR(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci
) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci;

-- =====================================================================
-- 2. ดึงเฉพาะ Tag ที่ยังไม่มีในระบบเข้ามาพักไว้ (กรองตัวซ้ำออกปกติ)
-- =====================================================================
INSERT INTO temp_next_tags (tag_name)
SELECT DISTINCT TRIM(j.tag)
FROM JSON_TABLE(

'["htaccess","apache","Apache","Apache PHP Module","CGI","CSS)","FastCGI Manager","High Concurrency ","HTML,","httpd.conf","Interpreter","Memory Hog","mod_php","Module","Nginx","Permissions","PHP","PHP-FPM","Process","Processor","RAM","Request","Security","Server","Static","Static files","User","Web","www-data","คอนฟิกง่าย","โค้ด","จัดสรรสิทธิ์","โดยตรง","ตัวแปรภาษา","นทรัพยากร","ประมวลผล","ปิด","เปิด","มปลอดภัย","รูปภาพ,","สคริปต์","สถาปัตยกรรม","เสร็จ","หน่วยความจำ","โหลด","อดีต","แฮก"]', -- เปลี่ยนชุดคำศัพท์ใหม่ของพี่ตรงนี้ได้เลย

'$[*]' COLUMNS(tag VARCHAR(200) PATH '$')
) AS j
WHERE NOT EXISTS (

SELECT 1 FROM wp_terms t

WHERE TRIM(t.name) COLLATE utf8mb4_unicode_520_ci = TRIM(j.tag) COLLATE utf8mb4_unicode_520_ci
);

-- =====================================================================
-- 3. Procedure ถมรูรั่วแบบ Real-time (เขียนลงตารางทันทีในลูปเพื่อไม่ให้เลขกระโดด)
-- =====================================================================
DROP PROCEDURE IF EXISTS RealtimeFillGaps;
DELIMITER $$

CREATE PROCEDURE RealtimeFillGaps()
BEGIN

DECLARE done INT DEFAULT FALSE;

DECLARE current_tag_name VARCHAR(200);

DECLARE current_gap_id INT;


-- ดึงรายชื่อคำศัพท์ใหม่มารันทีละคำ

DECLARE cur CURSOR FOR SELECT tag_name FROM temp_next_tags;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;


OPEN cur;

read_loop: LOOP


FETCH cur INTO current_tag_name;


IF done THEN



LEAVE read_loop;


END IF;



-- 1. ค้นหา ID รูรั่วที่ต่ำที่สุดและว่างอยู่จริง ๆ ณ วินาทีนั้น


SELECT MIN(gap.available_id) INTO current_gap_id


FROM (



SELECT (t1.term_id + 1) AS available_id



FROM wp_terms t1



LEFT JOIN wp_terms t2 ON t1.term_id + 1 = t2.term_id



WHERE t2.term_id IS NULL




UNION




SELECT 1 AS available_id



WHERE NOT EXISTS (SELECT 1 FROM wp_terms WHERE term_id = 1)


) AS gap;



-- 2. บังคับ INSERT ลงตารางหลักทันที! (ทำให้ลูปถัดไปรู้ว่าไอดีนี้ไม่ว่างแล้ว)


INSERT INTO wp_terms (term_id, name, slug, term_group)


VALUES (



current_gap_id,



current_tag_name,



LOWER(REGEXP_REPLACE(REPLACE(current_tag_name, ' ', '-'), '[^a-zA-Z0-9\\x{0E00}-\\x{0E7F}-]', '')),



0


);



-- 3. ผูกข้อมูลเข้าตาราง Taxonomy ทันทีคู่กัน


INSERT INTO wp_term_taxonomy (term_id, taxonomy, description, parent, count)


VALUES (current_gap_id, 'post_tag', '', 0, 0);


END LOOP;

CLOSE cur;
END$$
DELIMITER ;

-- เรียกใช้งานเพื่อเริ่มการถมรูรั่วที่ถูกต้อง
CALL RealtimeFillGaps();
DROP PROCEDURE IF EXISTS RealtimeFillGaps;

-- =====================================================================
-- 4. รีเซ็ต AUTO_INCREMENT ของระบบให้ไปรอที่จุดสูงสุดหลังจบงาน
-- =====================================================================
SET @max_id := (SELECT MAX(term_id) FROM wp_terms);
SET @sql_cmd := CONCAT('ALTER TABLE wp_terms AUTO_INCREMENT = ', @max_id + 1);
PREPARE stmt FROM @sql_cmd;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

-- ลบตารางชั่วคราว
DROP TEMPORARY TABLE temp_next_tags;

สรุป

Script นี้เป็นตัวอย่างที่ดีของการใช้ Advanced SQL ในการจัดการพื้นที่ของ Primary Key อย่างคุ้มค่า เหมาะสำหรับงานที่ต้องการจัดระเบียบข้อมูลให้เรียบร้อยและไม่มีช่องว่างในลำดับตัวเลขครับ


อ่านเพิ่มเติม