อ่านเจอคำถามนี้ใน facebook
อยากทราบว่าถ้าเราเปลี่ยน database จาก mysql เป็น sql server 2008 นอกจากส่วน connect แล้ว โค๊ดเก่าจากmysql จะสามารถใช้ได้เหมือนเดิมไหมครับ
เลยลองยกตัวอย่างดู โดยใช้ PDO แทน function ของแต่ละ database จะได้เห็นได้ชัดเจน
schema_mysql.php สำหรับ mysql
schema_mysql.php
<?php
$database = 'yii2advanced'; try { $dbh = new PDO;
} catch (PDOException $e) { exit ('Error!: ' . $e->getMessage ()) ;
}
$dbh->query ('SET NAMES utf8') ; switch ($_GET['op']) { case 'columns':{ $table = $_GET['table']; $sql = "SELECT `COLUMN_NAME` AS name ,`DATA_TYPE` AS type ,IFNULL (`CHARACTER_MAXIMUM_LENGTH`, 0) AS maxlength
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = '" . $table . "';"; $sth = $dbh->prepare ($sql) ; $sth->execute () ; $results = []; if ($sth->rowCount () > 0) { while ($row = $sth->fetch (PDO::FETCH_ASSOC)) { array_push ($results, $row) ; } echo json_encode ($results, JSON_NUMERIC_CHECK) ; } }break; case 'tables':{ $sql = 'SHOW TABLES IN ' . $database . ';'; $sth = $dbh->prepare ($sql) ; $sth->execute () ; $results = []; if ($sth->rowCount () > 0) { while ($row = $sth->fetch (PDO::FETCH_COLUMN)) { array_push ($results, $row) ; } } echo json_encode ($results) ; }break;
}
และ schema_sqlsrv.php สำหรับ Microsoft sql server
schema_sqlsrv.php
<?php
$database = 'TPA'; try { $dbh = new PDO;
} catch (PDOException $e) { exit ('Error!: ' . $e->getMessage ()) ;
}
$dbh->query ('SET CHARACTER_SET utf8_unicode_ci') ;
$dbh->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION) ; switch ($_GET['op']) { case 'columns':{ $table = $_GET['table']; $sql = "SELECT [COLUMN_NAME] AS name ,[DATA_TYPE] AS type ,ISNULL ([CHARACTER_MAXIMUM_LENGTH], 0) AS maxlength
FROM TPA.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = '" . $table . "';"; $sth = $dbh->prepare ($sql, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]) ; $sth->execute () ; $results = []; if ($sth->rowCount () > 0) { while ($row = $sth->fetch (PDO::FETCH_ASSOC)) { array_push ($results, $row) ; } echo json_encode ($results, JSON_NUMERIC_CHECK) ; } }break; case 'tables':{ $sql = 'SELECT [TABLE_NAME] FROM ' . $database . '.INFORMATION_SCHEMA.Tables;'; $sth = $dbh->prepare ($sql, [PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL]) ; $sth->execute () ; $results = []; if ($sth->rowCount () > 0) { while ($row = $sth->fetch (PDO::FETCH_COLUMN)) { array_push ($results, $row) ; } echo json_encode ($results) ; } }break;
}
ถึงจะพยามออกแบบ extension ตัวนี้ให้ทำงานได้ทุก database แต่แค่การ connection ก็ต่างกันแล้วแต่ละตัวต่างก็มี ตัวเลือกเพิ่มเติมไม่เหมือนกัน อย่าง การเลือกชุดตัวอักษร SET NAMES utf8 และ SET CHARACTER_SET utf8_unicode_ci ใน sql server (ภาษาไทย ภาษาเดียวก็มีให้เลือกกันเหนื่อยแล้วว่าจะใช้ตัวไหน ลองอ่าน LAB TEST : ความแตกต่างของ SQL THAI Collation แต่ละแบบ) จุดนี้พอจะเข้าใจได้เพราะมาจากคนละบริษัทกัน มาจากคนละความคิด
จุดต่อมา mySql ใช้ ` ` แต่ sql server ใช้ [ ] ในการบอกว่านี่คือชื่อเฉพาะนะ วิธีแก้ก็ง่าย ๆ อย่าไปใส่มัน ยกเว้นว่าจะไปใช้ชื่อที่ตรงกับศัพท์สงวน (reserved words) เอาไว้ จำเป็นต้องใช้เพื่อให้ตัว database ไม่สับสน
ถ้าต้องต้องเปลี่ยนฐานข้อมูลก็หลีกเลี่ยงคำพวกนี้ไว้ก่อน
คำสั่งเกี่ยวกับโครงสร้างฐานข้อมูล ต่างเจ้าก็ต่างกัน ทั้งชื่อ type และ key บางครั้งชื่อเดียวกันแต่เก็บข้อมูลได้ไม่เท่ากัน การจะดึงข้อมูลโครงสร้างตารางออกมาก็ใช้คำสั่งต่างกัน ในตัวอย่าง switch case ทั้งสองตัวจะเป็นการ query ดูตารางทั้งหมดในฐานข้อมูลและชนิดของฟิลย์ในตารางทั้งหมด ซึ่งไม่ได้ไกล้เคียงกันเลย (นาน ๆ จะใช้ที ไม่ต้องไปจำมันก็ได้ ยกเว้นคุณจะเขียน CURD ใช้เอง)
การใช้ Abstraction Layers แทนที่จะใช้ Vendor Specific Database Extensions หรือที่เรียกกันว่า native driver ที่เป็นของฐานข้อมูลแต่ละตัว เพราะว่าต้องการที่จะใช้คำสั่งเหมือน ๆ กัน ไม่ต้องมาคิดว่าฐานข้อมูลแบบนี้ใช้ function ชื่อนี้ เวลาเปลี่ยน ชนิดฐานข้อมูลก็แค่เปลี่ยนตรง connection ก็พอแล้วไม่ต้องเขียนคำสั่งใหม่ แต่จริง ๆ แล้วยังไม่มี Abstraction Layers ตัวไหน หรือของ framework ไหน ไม่ว่าจะเป็น codeigniter, yii, laravel แม้แต่ .net หรือ java ที่แปลง sql query แล้วสามารถทำงานได้เหมือนกันกับทุก ๆ ตัว แค่ทำได้ 80% ของทั้งหมดในตัวอย่าง pdo ของ sql server ถ้าไม่ระบุ PDO::ATTR_CURSOR เพิ่มเข้าไป มันก็จะไม่รู้เลยว่า query ออกมามีผลลัพธ์ออกมารึเปล่า และถ้าสังเกตจะมีคำสั่งที่ใช้ตรวจสอบค่า NULL และแทนด้วยค่าอื่นใน MySQL ใช้ IFNULL แต่ SQL SERVER ใช้ ISNULL การทำงาน โครงสร้างเหมือนกัน แต่เขียนไม่เหมือนกัน แทนกันไม่ได้ (: