ป้ายกำกับ: สคีมา

MySql ต่างกับ sql serverMySql ต่างกับ sql server

อ่านเจอคำถามนี้ใน facebook
อยากทราบว่าถ้าเราเปลี่ยน database จาก mysql เป็น sql server 2008 นอกจากส่วน connect แล้ว โค๊ดเก่าจากmysql จะสามารถใช้ได้เหมือนเดิมไหมครับ ( ผมใช้ codeigniter เขียนครับ )
เลยลองยกตัวอย่างดู โดยใช้ PDO แทน function ของแต่ละ database จะได้เห็นได้ชัดเจน
schema_mysql.php สำหรับ mysql
schema_mysql.php

<?php
$database = 'yii2advanced';
 
try {
 $dbh = new PDO(
  'mysql:host=localhost;dbname=' . $database,
  'root',
  ''
 );
} 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(
  'sqlsrv:Server=MAGI\SQLEXPRESS;Database=' . $database
 );
} 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 การทำงาน โครงสร้างเหมือนกัน แต่เขียนไม่เหมือนกัน แทนกันไม่ได้ (: