Author: worapot.k

  • การเรียกใช้งาน constructor จากอีก constructor ใน C#.NET

    constructor คืออะไร

    constructor ก็คือ ฟังก์ชันที่ถูกเรียกใช้งาน เมื่อ object ถูกสร้างขึ้นมา ซึ่งใน C#.NET  ก็คือฟังก์ชันที่ตั้งชื่อเป็นชื่อเดียวกับชื่อ class นั่นเอง

     

    constructor มีประโยชน์อย่างไร

    ในการสร้าง object ขึ้นมา บางครั้งต้องมีการระบุค่าเริ่มต้นบางอย่างให้กับ object นั้น ซึ่ง constructor ก็จะเป็นเครื่องมือหนึ่งที่เป็นตัวช่วยบังคับให้ต้องระบุค่าเริ่มต้นนี้ตอนสร้าง object นั่นเอง

     

    ยกตัวอย่าง เช่น

    class Student

    {

    public Student(string studentID)

    {

    คำสั่งดึงข้อมูลนักศึกษาด้วย Student ID โดยใช้ข้อมูล Student ID จาก argument studentID

    }

    }

    จากตัวอย่างนี้ ต้องการสร้าง object Student โดยใช้ Student ID เพื่อไปดึงข้อมูลเบื้องต้นของนักศึกษามาแสดง

    ดังนั้น object ใหม่ที่สร้างจาก class Student ก็จะต้องระบุค่า Student ID ให้กับ argument studentID ก่อน

    ตัวอย่างการเรียกใช้งานคือ

    Student student = new Student(12345);

    student ก็คือ object ที่ถูกสร้าง

    123456 คือ ข้อมูล Student ID ทีต้องระบุตอนที่ object นี้ถูกสร้างนั่นเอง

     

    ทำไมต้องเรียกใช้ constructor จากอีก constructor หนึ่ง

    ในบางครั้งเมื่อเราใช้งาน class ไประยะเวลาหนึ่ง อาจะเจอกรณีที่ constructor เดิม ยังไม่รองรับความต้องการที่เปลี่ยนไปหรือเพิ่มขึ้น   แต่ความต้องการใหม่นั้นยังคงต้องใช้ชุดคำสั่งและขั้นตอนการทำงานเหมือนกับที่มีอยู่เดิมด้วย และมีการเพิ่มเติมชุดคำสั่งใหม่เข้าไปเล็กน้อยเพื่อให้รองรับกับความต้องการใหม่ด้วย ซึ่งทางเลือกที่เป็นไปได้คือ

    1. ปรับแก้ constructor เดิมที่มีอยู่ให้รองรับความต้องการใหม่
    2. สร้าง constructor ใหม่ โดยทำการสำเนาชุดคำสั่งทั้งหมดใน constructor เดิมมา
    3. สร้าง constructor ใหม่ โดยเรียกใช้งาน constructor เดิม

    มาพิจารณาแต่ละทางเลือก

    ทางเลือกที่ 1 เป็นการปรับแก้ของเดิมที่มีอยู่แล้ว ซึ่งเป็นทางที่ควรเลี่ยงที่สุด เพราะอาจจะไปกระทบกับการทำงานเดิมที่ถูกต้องอยู่แล้ว และอาจจะกระทบเป็นลูกโซ่กับ object อื่นที่มาเรียกใช้

    ทางเลือกที่ 2 สำเนาคำสั่งทั้งหมดจาก constructor เดิม มาใส่ใน constructor ใหม่ แล้วเขียนคำสั่งเพิ่มเพื่อให้รองรับความต้องการใหม่ ซึ่งทางเลือกนี้ถือว่าดีกว่าทางเลือกแรก เพราะไม่กระทบกับการทำงานเดิมแน่นอน แต่จะเห็นว่าเกิดความซ้ำซ้อนกันของชุดคำสั่งของ constructor เดิม และใหม่ และจะพบปัญหาในกรณีที่มีความจำเป็นต้องปรับปรุงคำสั่งที่ใช้อยู่ใน constructor ทั้งสอง ผู้พัฒนาก็จะต้องมาแก้ทั้งสองที่ให้เหมือนกันอีก ซึ่งจะเป็นการเสียเวลา

    ทางเลือกที่ 3 เรียกใช้งาน constructor เดิม ซึ่งจะเห็นว่าเป็นวิธีการที่สะดวกรวดเร็วที่สุด หากต้องการปรับปรุงคำสั่ง ก็เพียงไปจัดการที่ constructor เดิมเท่านั้น

     

    วิธีการเรียกใช้งาน constructor เดิม จาก constructor ใหม่

    syntax ที่ใช้ใน C#.NET คือ  หลังจากส่วนประกาศ constructor ให้ใช้  : this() เพิ่มเข้าไป

    ยกตัวอย่าง

     

    class Student

    {

    public Student(string studentID) //constructor เดิม

    {

    คำสั่งดึงข้อมูลนักศึกษาด้วย Student ID โดยใช้ข้อมูล Student ID จาก argument studentID

    }

     

    public Student(string studentID, string citizenID) : this(studentID)  //constructor ใหม่

    {

    คำสั่งใหม่ที่เพิ่มเติม

    }

    }

  • การยกเลิก SMS ไม่พึงประสงค์/ SMS กวนใจ

    เชื่อว่าหลายท่านคงเคยประสบกับปัญหากวนใจเรื่อง SMS ไม่พึงประสงค์ ที่ส่งมาโดยที่เราไม่ต้องการ และบางครั้ง SMS เหล่านี้ก็ยังคิดค่าบริการ ทั้ง ๆ ที่เราไม่ได้สมัคร หรือบางครั้งอาจจะสมัครโดยไม่ตั้งใจหรือไม่รู้ตัว ดังนั้นในบทความนี้จะเสนอวิธีการหนึ่ง ที่จะช่วยให้เราสามารถยกเลิก SMS กวนใจเหล่านี้ออกไปบางส่วนได้ ถึงแม้จะไม่ทั้งหมด แต่ก็ช่วยบรรเทาความรำคาญลงไปได้บ้าง  โดยช่องทางที่จะแนะนำนี้เป็นการร่วมมือกันระหว่าง กสทช. และผู้ให้บริการเครือข่ายโทรศัพท์เคลื่อนที่ในการให้บริการยกเลิก SMS ดังกล่าว ซึ่งผู้ใช้บริการสามารถทำได้ด้วยตนเอง โดยไม่มีค่าใช้จ่าย ดังนี้

    1. กด *137 แล้วโทรออก
    2. ทำตามคำแนะนำจากเสียงตอบรับอัตโนมัติของแต่ละผู้ให้บริการเครือข่ายฯ
    3. รอรับ SMS แจ้งยกเลิก

     

    ตัวอย่าง SMS ไม่พึงประสงค์ และ SMS ตอบกลับ

     

    จะเห็นว่าหลังจากที่ใช้บริการยกเลิก SMS ผ่าน *137 แล้ว บรรดา SMS ไม่พึงประสงค์ก็ลดน้อยลง เหลือเพียง SMS ข่าวสารจากผู้ให้บริการเครือข่ายฯ เท่านั้น   และก็เป็นวิธีการที่ง่ายและรวดเร็ว เพียงไม่กี่ขั้นตอน แค่นี้ก็สามารถยกเลิก SMS กวนใจออกไปได้บางส่วนแล้ว

     

    สิ่งที่ควรรู้

    ถึงแม้ว่าเราจะได้ทำการยกเลิก SMS ไม่พึงประสงค์ดังกล่าวไปแล้ว แต่ก็อาจจะมี SMS ไม่พึงประสงค์ใหม่ ๆ เข้ามาได้อีก ทั้งนี้เพราะการใช้วิธีนี้ คือการยกเลิก SMS ปัจจุบันหรือ SMS ที่ถูกสมัครไปแล้ว ไม่ได้เป็นการป้องกัน SMS ใหม่ ๆ ที่จะเกิดขึ้นในอนาคต (เช่น อาจจะเผลอไปสมัครรับ SMS โดยไม่รู้ตัวอีก)  อย่างไรก็ตาม ถ้าเกิดปัญหานี้ซ้ำอีก ก็สามารถใช้การโทรไปยัง *137 เพื่อยกเลิก SMS ได้เป็นระยะ ๆ

     

    สำหรับรายละเอียดเพิ่มเติมว่า SMS เหล่านี้มาได้อย่างไร หรือมี SMS ประเภทไหนที่สามารถยกเลิกได้ด้วย *137 บ้าง และเราจะระมัดระวังอย่างไร ไม่ให้เผลอไปสมัครบริการ SMS เหล่านี้โดยไม่ตั้งใจ สามารถศึกษาเพิ่มเติมได้จาก   http://tcp.nbtc.go.th/website/home/detail/631/th

     

    ขอขอบคุณที่มาของเนื้อหาจากสำนักรับเรื่องร้องเรียนและคุ้มครองผู้บริโภคในกิจการโทรคมนาคม สำนักงานคณะกรรมการกิจการกระจายเสียง กิจการโทรทัศน์ และกิจการโทรคมนาคมแห่งชาติ

     

    แนะนำการยกเลิก SMS ไม่พึงประสงค์เพิ่มเติม สำหรับผู้ใช้งาน AIS

    นอกจากการยกเลิกบริการ SMS ไม่พึงประสงค์ผ่านทาง *137 แล้ว ผู้ให้บริการเครือข่ายฯ AIS ยังมีบริการให้ลูกค้าสามารถยกเลิก SMS เหล่านี้ได้ด้วยตนเองผ่านทางเว็บด้วย โดยทำตามขั้นตอนดังนี้

    1. เข้าไปที่  URL https://myais.ais.co.th
    2. เมื่อเข้ามาแล้วจะมีหน้าจอให้ login เข้าใช้งานระบบโดยการกรอกเบอร์โทรศัพท์มือถือ และรอรับ OTP เพื่อใช้ในการเข้าใช้งานระบบแต่ละครั้ง หรือจะใช้วิธีการสร้างบัญชีผู้ใช้และรหัสผ่านใหม่สำหรับการเข้าใช้งานครั้งต่อ ๆ ไปก็ได้
    3. เมื่อ login เข้าสู่ระบบแล้ว จะปรากฏเมนูด้านขวามือสำหรับการจัดการต่าง ๆ
    4. เลือกเมนู บริการ จะเห็นว่าว่ามีเมนู เลือกรับ / ยกเลิก SMS  ให้เลือกเมนูนี้เพื่อเข้าไปยกเลิกบริการ SMS ที่เราไม่ต้องการ
    5. เราสามารถเลือกว่าจะรับหรือไม่รับ SMS ทั้งที่มาจาก AIS และไม่ได้มาจาก SMS ได้ตามต้องการ
  • ปัญหาการเชื่อมต่อฐานข้อมูล Oracle ไม่ได้ เนื่องจาก Listener

    สำหรับผู้ดูแลระบบที่เคยทำงานดูแลฐานข้อมูล Oracle คงเคยเจอกับปัญหาการเชื่อมต่อไปยังฐานข้อมูลไม่ได้ ซึ่งเมื่อไล่เรียงหาสาเหตุแล้ว ก็มีมากมายหลายสาเหตุด้วยกัน เช่น ปัญหาที่ตัวฐานข้อมูลเอง หรือ ปัญหาทางด้านระบบเครือข่าย ฯลฯ ซึ่งในบทความนี้จะเล่าถึงประสบการณ์ที่ได้พบเจอปัญหานี้เช่นกัน โดยสาเหตุนั้นเกี่ยวกับตัว Listener

    เหตุการณ์ที่เกิดขึ้นช่วงที่พบปัญหา

    ได้รับแจ้งจากผู้ใช้ว่าไม่สามารถเข้าใช้งานระบบได้  ซึ่งเมื่อได้รับแจ้งจึงทำการตรวจสอบและพบว่าปัญหาเกิดจากการที่ระบบไม่สามารถเชื่อมต่อไปยังฐานข้อมูลที่พัฒนาด้วย Oracle ได้ โดยที่ระบบเครือข่ายยังใช้งานได้ปกติ ดังนั้นสิ่งที่ทำต่อมาคือการตรวจสอบเฉพาะฐานข้อมูลว่าเกิดปัญหาอะไรขึ้น โดยสิ่งที่ทำคือ

    • ทดลองเชื่อมต่อผ่าน SQL Developer ซึ่งเป็นเครื่องมือหนึ่งที่ใช้สำหรับบริหารจัดการฐานข้อมูล Oracle ผลลัพธ์คือ ไม่สามารถเชื่อมต่อได้ โดยมีข้อความแจ้งเตือนว่า socket timeout
    • ทดลองเชื่อมต่อผ่าน Enterprise Manager ซึ่งเป็นเครื่องมือสำหรับบริหารจัดการฐานข้อมูลอีกตัวซึ่งได้ติดตั้งมาพร้อมกับตอนที่สร้างฐานข้อมูล  ซึ่งก็ไม่สามารถเชื่อมต่อได้เช่นกัน และได้ลองสั่ง Startup DB ฐานข้อมูล จากเครื่องมือตัวนี้ อาการผิดปกติก็ยังคงเหมือนเดิม
    • ทดลองเชื่อมต่อผ่าน ผ่าน SQL Plus ซึ่งใช้งานผ่าน command prompt  ปราฏว่าสามารถเชื่อมต่อได้
    • ใช้คำสั่ง expdp เพื่อ dump ข้อมูลมาสำรองไว้ก่อน  สามารถทำได้เช่นกัน
    • แสดงว่าตัวฐานข้อมูลยังสามารถเข้าถึงได้อยู่ จึงพุ่งประเด็นไปที่ Listener เพราะเป็นตัวกลางที่จัดการให้ระบบหรือเครื่องมือภายนอกสามารถเชื่อมต่อมายังฐานข้อมูลได้
    • ทดลอง config Listener ใหม่ ด้วยเครื่องมือ Net Configuration Assistant พบว่าใช้เวลาตั้งค่านานมาก แต่ก็สามารถ config ได้
    • ลอง restart Listener และ Windows แล้ว อาการยังเหมือนเดิม
    • ใช้คำสั่งบน command prompt ที่เกี่ยวกับ Listener ได้แก่ lsnrctl และ tnsping เพื่อตรวจสอบ Listener และ TNS พบว่าใช้เวลานานมาก จึงสันนิษฐานว่า อาจจะเป็นปัญหาที่ Listener แน่นอน เพราะยังเข้าถึงฐานข้อมูลผ่านช่องทางบางช่องทางได้

    การแก้ไขปัญหา

    • เมื่อได้ข้อมูลจากการตรวจสอบแล้ว ว่ามีปัญหาจาก Listener จึงได้ค้นข้อมูลใน internet เกี่ยวกับการเชื่อมต่อ Listener ที่ใช้เวลานาน พบว่ามีผู้แนะนำให้ตรวจสอบที่ไฟล์ listener.log ใน \app\Administrator\diag\tnslsnr\Win-User\listener\trace (ตัวอย่างนี้จะเป็น path ที่เป็น oracle 11)
      ***หมายเหตุ โฟลเดอร์ Win-User เป็นโฟลเดอร์ที่ต้ังตามชื่อ user ใน Windows
    • ถ้าขนาดไฟล์ถึง 4 GB จะมีปัญหาได้ ให้ทำการหยุด service ของ Listener แล้ว rename ชื่อไฟล์ listener.log  ใหม่ เมื่อ start listener แล้ว ไฟล์ listener.log ก็จะถูกสร้างมาใหม่
    • เมื่อได้ทำการตรวจสอบพบว่าไฟล์มีขนาด 4 GB จริง และได้ทำการแก้ไขตามวิธีที่มีการแนะนำ พบว่าสามารถเชื่อมต่อกับฐานข้อมูล Oracle ได้เป็นปกติ
    • สำหรับกรณีศึกษาที่มีผู้นำเสนอไว้สามารถเข้าดูได้ผ่าน URL https://vjdba.wordpress.com/2013/09/24/93/
  • การเรียกดูรายการ object ในฐานข้อมูล Oracle

    คำสั่งที่ใช้ในการเรียกดู รายการ object ในฐานข้อมูล Oracle

    • การเรียกดูรายการ object ทั้งหมดในฐานข้อมูล Oracle (เช่น table, view ฯลฯ)  สามารถเรียกดูได้จาก view ที่ชื่อว่า ALL_OBJECTS  ตัวอย่างคำสั่งคือที่ใช้เรียกดูคือ

     

    SELECT * FROM ALL_OBJECTS;

     

    โดยคำสั่งนี้จะแสดงรายการ object ทั้งหมดที่มี

     

    • แต่ในการใช้งานส่วนใหญ่ อาจจะต้องการเจาะจงดูแค่บางเงื่อนไข เช่น ต้องการดูรายการ table ทั้งหมด โดยเจาะจงแค่ schema ใด schema  หนึ่งเท่านั้น  ซึ่งสามารถใช้เงื่อนไขจากฟีลด์ต่อไปนี้ คือ
      • OBJECT_TYPE เป็นการเรียกดูตามเงื่อนไขของประเภท object เช่น หากต้องการดูเฉพาะ table จะใช้เงื่อนไขเป็น  WHERE OBJECT_TYPE = ‘TABLE’
      • OWNER เป็นการเรียกดูเฉพาะเจาะจง schema ใด schema  หนึ่ง เช่น ต้องการเรียกดูข้อมูลจาก schema ชื่อ SCOTT จะใช้เงื่อนไขเป็น WHERE OWNER = ‘SCOTT’
      • ตัวอย่างคำสั่งเต็ม ๆ กรณีที่ต้องการเรียกดูเฉพาะ table ทั้งหมดที่อยู่ใน schema ที่ชื่อ SCOTT

    SELECT * FROM ALL_OBJECTS WHERE OBJECT_TYPE=’TABLE’ AND OWNER=’SCOTT’;

     

    ตัวอย่างการนำไปใช้ประโยชน์

    เพื่อให้เห็นภาพการนำไปใช้งานจริง จึงขอยกตัวอย่างที่เคยใช้งาน คือ การสร้างสคริปต์คำสั่ง sql ที่อ้างอิงชื่อ table ที่อยู่ใน schema ใด schema หนึ่ง โดยในที่นี้จะยกตัวอย่างการ grant สิทธิ์ในการเข้าถึงข้อมูลของ schema หนึ่งไปให้กับอีก schema หนึ่ง

    • ที่มาที่ไปคือ ในบางครั้ง เราต้องการ grant สิทธิ์ในการเข้าถึงข้อมูลของ schema หนึ่งไปให้กับอีก schema หนึ่ง เช่น ต้องการ grant สิทธิ์การเรียกดูข้อมูลใน table ชื่อ TABLE01 ของ schema ที่ชื่อ SCHEMA01 ให้ schema ที่ชื่อ SCHEMA02 สามารถเรียกดูข้อมูลได้ คำสั่งที่ใช้ในการ grant คือGRANT SELECT ON SCHEMA01.TABLE01 TO SCHEMA02;
    • แต่หากต้องการ grant หลาย ๆ  table ก็ต้องพิมพ์คำสั่งเหล่านี้ทีละคำสั่งซ้ำๆ ไปจนครบตามชื่อ talbe ที่ต้องการ grant ซึ่งถ้า table ที่ต้องการ grant มีเป็นจำนวนมากก็จะยิ่งใช้เวลามากยิ่งขึ้น และอีกปัญหาคือ มีโอกาสพิมพ์ชื่อ table ผิด
    • เทคนิคในการสร้างสคริปต์เพื่อช่วยให้การทำงานรวดเร็วขึ้นจะมีรูปแบบดังนี้คือSELECT ‘GRANT SELECT ON OWNER_SCHEMA.’ || OBJECT_NAME || ‘ TO OTHER_SCHEMA;’
      FROM ALL_OBJECTS
      WHERE OBJECT_TYPE = ‘TABLE’;

      เมื่อ

      • OWNER_SCHEMA คือชื่อของ schema ที่เป็นเจ้าของ table
      • OBJECT_NAME คือชื่อฟีลด์ที่อยู่ใน ALL_OBJECTS โดยเป็นข้อมูลของชื่อ object ซึ่งกรณีนี้คือชื่อของ table นั่นเอง
      • OTHER_SCHEMA คือชื่อของ schema ที่ได้รับการ grant สิทธิ์ให้เรียกดูข้อมูลใน table ของ OWNER_SCHEMA
      • WHERE OBJECT_TYPE = ‘TABLE’ เป็นการระบุเงื่อนไขว่าต้องการ object ที่เป็น table เท่านั้น

    ผลลัพธ์ที่ได้คือ

    GRANT SELECT ON OWNER_SCHEMA.TABLE01 TO OTHER_SCHEMA;

    GRANT SELECT ON OWNER_SCHEMA.TABLE02 TO OTHER_SCHEMA;

    GRANT SELECT ON OWNER_SCHEMA.TABLE03 TO OTHER_SCHEMA;

    GRANT SELECT ON OWNER_SCHEMA.TABLE04 TO OTHER_SCHEMA;

    …….

    …….

    …….

    GRANT SELECT ON OWNER_SCHEMA.TABLE99 TO OTHER_SCHEMA;

     

    โดยคำสั่งทั้งหมดจะเท่ากับจำนวน table ของ OWNER_SCHEMA นั่นเอง ซึ่งหากไม่ต้องการ grant table ไหนก็ลบคำสั่ง grant เฉพาะ table นั้นออกไปได้

    • จะเห็นว่าการใช้เทคนิคลักษณะนี้ จะทำให้สามารถสร้างสคริปต์คำสั่งที่มีลักษณะแบบเดียวกันได้ภายในเวลาอันรวดเร็ว และลดความผิดพลาดของการอ้างอิงชื่อ object ลงไปได้ด้วย
    • อ้างอิงข้อมูล https://docs.oracle.com/cd/B19306_01/server.102/b14237/statviews_2005.htm#i1583352

     

     

     

     

     

  • ไวรัส shortcut

    เหตุที่ตั้งชื่อบทความว่า ไวรัส shortcut ไม่ได้หมายความว่าไวรัสประเภทนี้ชื่อ shortcut แต่เป็นอาการทีเกิดขึ้นเมื่อไวรัสตัวนี้ทำงาน โดยสาเหตุและลักษณะอาการที่พบคือ เมื่อเรานำ flash drive หรืออุปกรณ์จำพวก removable drive (เช่น external hardisk) ไปใช้งานกับเครื่องคอมพิวเตอร์เครื่องใดเครื่องหนึ่ง ไฟล์ที่อยู่ใน flash drive หรือ removable drive จะหายไป และจะมีไฟล์ shortcut เกิดขึ้นแทนที่ โดย shortcut มักจะถูกตั้งชื่อเหมือนกับไฟล์ข้อมูลเดิมที่มีอยู่ ซึ่งหากเราเผลอเปิดไฟล์ shortcut ดังกล่าว ก็จะเป็นการไปเรียกไฟล์ไวรัสให้ทำงานนั่นเอง ส่วนไฟล์ข้อมูลเดิมนั้นไม่ได้หายไปไหน เพียงแต่เมื่อแรกเริ่มที่ติดไวรัสมานั้น ไฟล์เหล่านี้จะถูกซ่อนไว้ไม่ให้เห็นนั่นเอง

     

    ตัวอย่างไฟล์ shortcut ที่ไวรัสสร้างขึ้น ข้อสังเกตุคือจะมีไอคอนเป็นแบบ shortcut (ไอคอนรูปลูกศร)

     

    แนวทางการแก้ไข (ในบทความนี้จะยกตัวอย่างบน Windows 8.1)

    • อันดับแรกสิ่งที่ต้องเตรียมคือ เครื่องคอมพิวเตอร์ที่ไม่ติดไวรัส เพื่อใช้สำหรับกำจัดไวรัสและกู้ข้อมูลที่อยู่ใน flash drive หรือ removable drive โดยคอมพิวเตอร์ควรมีความพร้อมดังต่อไปนี้
      – ติดตั้งโปรแกรม antivirus ที่อัพเดตฐานข้อมูลไวรัสล่าสุด กรณี Windows 8.1 จะมี antivirus มาพร้อมอยู่แล้วคือ Windows Defender ซึ่งควรอัพเดตฐานข้อมูลไวรัสให้ล่าสุดก่อน
      – ปิด Autorun หรือ AutoPlay เพื่อป้องกันไม่ให้ไฟล์ใน  flash drive หรือ  removable drive ที่ติดไวรัส ถูกเปิดอ่านเมื่อมีการเชื่อมต่อกับเครื่องคอมพิวเตอร์ ซึ่งอาจจะเป็นสาเหตุให้ไวรัสแพร่กระจายต่อไปได้
    • เชื่อมต่อ flash drive หรือ removable drive ที่ติดไวรัสเข้ากับเครื่องคอมพิวเตอร์ จากนั้นทำการแสกนไวรัสด้วยโปแกรม antivirus ที่เตรียมไว้  และทำตามคำแนะนำของโปรแกรม antivirus  เพื่อกำจัดไฟล์ไวรัสและไฟล์ shortcut ที่ถูกไวรัสสร้างขึ้นมา   ซึ่งเมื่อเสร็จสิ้นขั้นตอนนี้แล้ว อาจจะพบว่า drive จะกลายเป็นพื้นที่ว่าง ๆ แต่หากดู properties ของ drive แล้วจะพบว่ามีเนื้อที่ส่วนหนึ่งถูกใช้ในการเก็บข้อมูล ซึ่งที่จริงแล้วก็คือไฟล์ข้อมูลที่ถูกไวรัสซ่อนไปนั่นเอง

    ตัวอย่าง falsh drive ที่ติดไวรัส หลังจากกำจัดไวรัสออกไปแล้ว จะเห็นเป็น drive ว่าง ๆ แต่เมื่อดู properties จะเห็นว่ามีเนื้อที่ส่วนหนึ่งที่มีการใช้เก็บข้อมูลอยู่

     

    • ส่วนของขั้นตอนการกู้ไฟล์ที่หายไปนั้น ก็คือการทำให้คอมพิวเตอร์ของเราเห็นไฟล์ที่ซ่อนไว้นั่นเอง
    • ซึ่งโดยปกตินั้น เราสามารถตั้งค่าการแสดงไฟล์ได้ในหน้าต่าง File Explorer โดยก่อนเข้าไปตั้งค่านี้ ให้เราเข้าไปที่ drive ที่ต้องการกู้ข้อมูลก่อน เพื่อจะได้เห็นผลจากการตั้งค่าได้เลย  จากนั้นเลือกเมนู View ที่อยู่ด้านบน แล้วเลือกเลือกเมนู Options แล้วเลือกคำสั่ง Change folder and search options เสร็จแล้วจะปรากฏหน้าต่างสำหรับตั้งค่า ต่อมาคือให้ไปที่แท็บ View จากนั้นให้ลองเลือกตัวเลือก ดังนี้
      • เลือก Show hidden files, folders, and drives จากนั้นกดปุ่ม Apply
      • หากไฟล์ที่ถูกซ่อนยังไม่ปรากฏ ให้เลือกตัวเลือก Hide protected operating system files (Recommended) แล้วกดปุ่ม Apply ซึ่งเมื่อถึงขั้นตอนนี้แล้ว ไฟล์ที่ถูกซ่อนไว้ก็น่าจะปรากฏขึ้นมาแล้ว
    • จะสังเกตเห็นว่าไฟล์ข้อมูลที่หายไปจะปรากฏขึ้นมา แต่ไอคอนจะเป็นสีจาง ๆ เนื่องจากถูกตั้งค่าให้เป็น Hidden โดยไวรัส และเมื่อดู properties ของไฟล์ จะพบว่าไม่สามารถเปลี่ยนค่าจาก Hidden เป็นปกติได้ เนื่องจากตัวเลือก Hidden ถูก disable อยู่
    • วิธีการแก้ไขเพื่อเอาค่า Hidden ออกทำได้ดังนี้คือ
      • อันดับแรก ให้กลับไปตัั้งค่าการแสดงผลไฟล์และโฟลเดอร์ให้เป็นเหมือนเดิมก่อน (ติ๊กเครื่องหมายถูกตัวเลือก Hide protected operating system files (Recommended) แล้วกดปุ่ม Apply) ไฟล์ก็จะถูกซ่อนไม่ให้เห็นเช่นเดิม  เพื่อจะได้ดูผลลัพธ์หลังจากแก้ปัญหาตามขั้นตอนแล้ว ว่าไฟล์ที่ซ่อนจะกลับมาแสดงให้เห็นเหมือนเดิมหรือไม่
      • เปิดหน้าต่าง command prompt แล้วพิมพ์ชื่อของ drive ที่ต้องการยกเลิกการซ่อนไฟล์
      • จากนั้นพิมพ์คำสั่ง attrib -s -h -r /S /D กดปุ่ม Enter
      • กลับไปตรวจสอบที่ drive ที่ต้องการกู้ข้อมูล ก็จะพบว่าไฟล์ที่ถูกซ่อนไว้กลับมาแสดงเช่นเดิม
      • อ้างอิงวิธีการจาก http://computertipeasy.blogspot.com/2014/03/hidden-file-and-folder-unlock-hidden.html

     

    สรุป

    แม้ไวรัสตัวนี้จะไม่ก่อความเสียหายมาก แต่ก็สร้างความรำคาญและทำให้เสียเวลาต้องมาแก้ไข ดังนั้น ข้อควรระวังก็คือ ไม่นำอุปกรณ์ประเภท removable drive ไปใช้งานกับคอมพิวเตอร์ที่มีความเสี่ยงที่จะเป็นแหล่งแพร่กระจายของไวรัส และข้อพึงระวังอีกอย่างคือ การสำรองข้อมูลที่อยู่ใน removable drive ควรมีเก็บสำรองไว้ที่อื่นด้วย เพราะถ้าโชคไม่ดี อาจจะเจอกับไวรัสที่มีผลทำลายรุนแรงถึงขั้นไม่สามารถกู้ข้อมูลกลับมาได้อีก

  • ฟังก์ชัน WMSYS.WM_CONCAT และการเปลี่ยนแปลงเมื่ออัพเกรดไปใช้ Oracle 12c

    ฟังก์ชัน WMSYS.WM_CONCAT

    นักพัฒนาบางท่านที่พัฒนาระบบบนฐานข้อมูล Oracle 10g หรือ 11g อาจจะผ่านตาหรือเคยใช้งานฟังก์ชัน  WMSYS.WM_CONCAT โดยฟังก์ชันนี้เป็นฟังก์ชันที่ใช้ในการนำข้อมูลในฟีลด์เดียวกัน แต่อยู่ต่างเร็คคอร์ดมาเชื่อมต่อกันเป็นข้อมูลเร็คคอร์ดเดียว

    ในที่นี้จะยกตัวอย่างจากตารางข้อมูลทดสอบ ชื่อว่าตาราง STATIONERY ซึ่งเก็บข้อมูลเครื่องเขียน โดยแยกเป็นสี และระบุจำนวนของเครื่องเขียนแต่และชนิดไว้ ดังนี้

    stationery

     

    ทดลองใช้คำสั่ง SELECT แบบปกติ ด้วยคำสั่ง

    SELECT WMSYS.WM_CONCAT(COLOR) COLOR_LIST

    FROM STATIONERY;

    ผลลัพธ์ที่ได้

    list04

     

    แต่ในเง่การใช้งานส่วนใหญ่ มักจะต้องการแสดงข้อมูลสรุปเป็นกลุ่ม เช่น จากตัวอย่างนี้ ถ้าต้องการแยกข้อมูลสรุปเป็นกลุ่มตามชนิดเครื่องเขียน ว่าเครื่องเขียนแต่ละชนิดมีสีอะไรบ้าง ซึ่งก็สามารถทำได้โดยการเพิ่มการ GROUP BY ตามฟีลด์ STATIONERY เข้าไป ดังนี้

    SELECT STATIONERY, WMSYS.WM_CONCAT(COLOR) COLOR_LIST

    FROM STATIONERY

    GROUP BY STATIONERY;

    ผลลัพธ์ที่ได้

    list05

     

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

    SELECT COLOR, WMSYS.WM_CONCAT(STATIONERY) STATIONERY_LIST

    FROM STATIONERY

    GROUP BY COLOR;

    ผลลัพธ์ที่ได้

    list06

     

    ที่กล่าวไปข้างต้นคือการใช้งานฟังก์ชัน WMSYS.WM_CONCAT บนฐานข้อมูล Oracle 10g หรือ 11g แต่ถ้านักพัฒนาท่านใดวางแผนที่จะอัพเกรตฐานข้อมูลไปเป็น Oracle 12c  ท่านก็จะเจอกับปัญหาเมื่อมีการเรียกใช้งานฟังก์ชันนี้ โดยจะมีข้อความ error แจ้งกลับมาว่า 

    ORA-00904: "WMSYS"."WM_CONCAT": invalid identifier 

    นั่นเป็นเพราะใน Oracle 12c จะไม่มีฟังก์ชันนี้ให้เรียกใช้งานอีกต่อไปแล้ว

    ดังนั้นในบทความนี้จะขอแนะนำฟังก์ชันอีกฟังก์ชันหนึ่งซึ่งทำงานคล้ายคลึงกัน และสามารถให้ผลลัพธ์แบบเดียวกันกับฟังก์ชัน WMSYS.WM_CONCAT ซึ่งฟังก์ชันที่ว่านี้คือ LISTAGG

     

    ฟังก์ชัน LISTAGG

    ฟังก์ชัน LISTAGG เป็นฟังก์ชันที่เริ่มมีให้ใช้งานใน Oracle 11g R2 ใช้งานในลักษณะเดียวกันกับ ฟังก์ชัน WMSYS.WM_CONCAT แต่ในส่วนของรายละเอียดนั้นจะมีบางจุดที่แตกต่างกันออกไป

    จากตัวอย่างข้อมูลที่นำเสนอไปข้างต้น จากที่ใช้งานกับฟังก์ชัน WMSYS.WM_CONCAT ลองเปลี่ยนมาใช้ฟังก์ชัน LISTAGG ได้ดังนี้

     

    ตัวอย่างแรกเป็นการทดลอง SELECT แบบปกติ

    SELECT LISTAGG(COLOR,’,’)

    WITHIN GROUP (ORDER BY COLOR) COLOR_LIST

    FROM STATIONERY;

    ผลลัพธ์ที่ได้

    list07

     

    อธิบายการใช้งานคำสั่ง

    • LISTAGG(COLOR,’,’)  ภายในวงเล็บเป็นฟีลด์ข้อมูลจากต่างเร็คคอร์ดกันแต่ต้องการให้แสดงเรียงต่อกัน ซึ่งในตัวอย่างนี้ก็คือฟีลด์ COLOR ส่วน ‘,’ ก็คือการระบุตัวคั่นระหว่างข้อมูล ซึ่งในทีนี้ใช้เป็นจุลภาคนั่นเอง
    • WITHIN GROUP (ORDER BY COLOR) เป็นการระบุรูปแบบการเรียงข้อมูล ซึ่งในที่นี้จะเรียงตามฟีลด์ COLOR

    จากตัวอย่างจะเห็นว่าสิ่งที่ฟังก์ชัน LISTAGG ทำได้แตกต่างจาก WMSYS.WM_CONCAT คือ การระบุตัวคั่นระหว่างข้อมูล และการระบุการเรียงลำดับของข้อมูลที่มาต่อกันนั่นเอง

     

    ตัวอย่างต่อมา จะให้แสดงผลลัพธ์แยกสรุปเป็นกลุ่มตามชนิดเครื่องเขียน ว่าเครื่องเขียนแต่ละชนิดมีสีอะไรบ้าง คำสั่งที่ใช้ก็จะใช้การ GROUP BY ด้วยฟีลด์ STATIONERY เช่นเดิม คือ

    SELECT STATIONERY, LISTAGG(COLOR,’,’)

    WITHIN GROUP (ORDER BY STATIONERY) COLOR_LIST

    FROM STATIONERY GROUP BY STATIONERY;

    ผลลัพธ์ที่ได้

    list01

     

    ส่วนตัวอย่างสุดท้าย ก็จะเป็นการให้แสดงผลลัพธ์สรุปตามสีของเครื่องเขียน ว่าแต่ละสีมีเครื่องเขียนชนิดใดอยู่บ้าง คำสั่งที่ใช้งานก็จะเป็น

    SELECT COLOR, LISTAGG(STATIONERY,’,’)

    WITHIN GROUP (ORDER BY STATIONERY) LIST_STATIONERY

    FROM STATIONERY GROUP BY COLOR;

    ผลลัพธ์ที่ได้

    list02

     

    ข้อมูลอ้างอิง :

    https://oracle-base.com/articles/misc/string-aggregation-techniques

    http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions089.htm#SQLRF30030

  • ข้อจำกัดและข้อควรระวังในการใช้เงื่อนไข IN ในคำสั่ง SELECT บนฐานข้อมูล Oracle

    สำหรับบทความนี้ จะนำเสนอข้อจำกัดและข้อควรระวังในการใช้งานคำสั่ง SELECT บนฐานข้อมูล Oracle ซึ่งประสบมาจากการใช้งานจริงสองเรื่องด้วยกัน

     

    เรื่องแรกจะเป็นข้อจำกัดในการใช้เงื่อนไข IN (value1,value2,value3,…) ในคำสั่ง SELECT  ส่วนอีกเรื่องจะเป็นเรื่องของข้อควรระวังในการใช้ IN ร่วมกับเงื่อนไขที่เป็น subquery ในคำสั่ง SELECT  เช่นกัน

     

    การใช้คำสั่ง SELECT และเงื่อนไข IN นั้น เป็นรูปแบบคำสั่งพื้นฐานแบบหนึ่งที่นักพัฒนาที่ทำงานคลุกคลีกับฐานข้อมูลส่วนใหญ่จะคุ้นเคยกันเป็นอย่างดี  โดยรูปแบบที่เรามักจะใช้งานกันบ่อย คือ

    รูปแบบที่ 1 รูปแบบ SELECT * FROM TABLE1 WHERE FIELD1 IN  (value1,value2,value3,…)  โดยผลลัพธ์จะเป็นรายการข้อมูลในตาราง TABLE1 ที่ค่าของข้อมูลใน FIELD1 มีอยู่ใน value1,value2,value3 ,…

    รูปแบบที่ 2 คล้ายกับรูปแบบที่ 1  นั่นเอง แต่จะเป็นการใช้ subquery แทนที่ (value1,value2,value3,…)   โดยมีรูปแบบ SELECT * FROM TABLE1 WHERE FIELD1 IN  (SELECT FIELD2 FROM TABLE2) สำหรับผลลัพธ์จะเป็นรายการข้อมูลในตาราง TABLE1 ที่ค่าของข้อมูลใน FIELD1 มีใน FIELD2 ซึ่งเป็นผลลัพธ์จากการ SELECT ข้อมูลจากตาราง TABLE2

     

    ข้อจำกัดในการใช้เงื่อนไข IN (value1,value2,value3,…)

    สำหรับใน Oracle นั้น list รายการที่อยู่ภายในเครื่องหมายวงเล็บ สามารถมีได้มากสุดไม่เกิน 1000 ค่า  ซึ่งบางท่านอาจจะสงสัยว่าในการ SELECT ข้อมูลตามปกตินั้น มีโอกาสน้อยมากที่เราจะพิมพ์ค่าของข้อมูลใน list จนถึง 1000  ค่า แต่ก็มีโอกาสที่จะพบได้คือ เมื่อมีการใช้งานคำสั่งนี้ผ่านโปรแกรมที่เขียนขึ้นนั่นเอง ตัวอย่างเช่น หน้าจอการทำงานของโปรแกรมที่มีลักษณะเป็นชุดของรายการข้อมูลที่ให้ผู้ใช้สามารถเลือกเองได้ จากนั้นรายการที่ถูกเลือกจะถูกส่งไปแปลงเป็นเงื่อนไขในคำสั่ง SELECT  อีกครั้ง ทำให้มีโอกาสที่จะเกิดกรณีที่มี list เกิน 1000 ค่า ได้นั่นเอง

    ในภาพด้านล่างจะเป็นตัวอย่างของเว็บสำหรับสืบค้นหนังสือของห้องสมุด ซึ่งผู้ใช้สามารถเลือกรายการผลลัพธ์จากการสืบค้นและเก็บรวบรวมไว้เพื่อทำการ export ไปใช้งานต่อได้ ซึ่งก็มีโอกาสที่จะเลือกผลลัพธ์ได้เกิน 1000  รายการเกิดขึ้นได้

    Capture

    ถือว่าเป็นจุดหนึ่งที่ผู้พัฒนาควรระมัดระวังในการเขียนโปรแกรมที่มีการใช้เงื่อนไข IN ลักษณะนี้ในคำสั่ง SELECT

     

    ข้อควรระวังในการใช้ IN ร่วมกับเงื่อนไขที่เป็น subquery

    ในที่นี้ขอยกตัวอย่างข้อมูลเพื่อให้เห็นภาพชัดเจน  โดยมีข้อมูลจากตารางสองตาราง คือ TABLE01 และ TABLE02

    สำหรับ TABLE01 เป็นข้อมูลที่ต้องการ SELECT เพื่อให้ได้ผลลัพธ์ออกมา ส่วนตาราง TABLE02 จะเป็นเงื่อนไขที่จะใช้ใน subquery  ข้อมูลในตารางทั้งสองจะเป็นดังนี้

     

    ข้อมูลใน  TABLE01

    t01

    ข้อมูลใน  TABLE02

    t02

     

    จะยกตัวอย่างกรณีการ SELECT ออกเป็น 2 กรณีดังนี้

    1. ต้องการข้อมูลใน TABLE01 ที่ข้อมูลในฟีลด์ F02 ของตารางนี้มีในฟีลด์ F02 ของ TABLE02 ด้วย

    คำสั่งที่ใช้คือ SELECT * FROM TABLE01 WHERE F02 IN (SELECT F02 FROM TABLE02);

    ผลลัพธ์ที่ได้คือ

    result1

    ซึ่งถูกต้อง

     

    1. ต้องการข้อมูลใน TABLE01 ที่ข้อมูลในฟีลด์ F02 ของตารางนี้ไม่มีในฟีลด์ F02 ของ TABLE02 โดยปรับคำสั่งจาก IN เป็น NOT IN

    คำสั่งที่ใช้คือ SELECT * FROM TABLE01 WHERE F02 NOT IN (SELECT F02 FROM TABLE02);

    ผลลัพธ์ที่ได้คือ

    result2

    ซึ่งถูกต้อง

     

    จะเห็นว่าทั้งสองกรณีทั้งการใช้ IN หรือ NOT IN ผลลัพธ์ที่ได้ก็ออกมาถูกต้อง

     

    ทดลองต่อไปโดยการเพิ่มข้อมูลในตาราง TABLE02 ดังนี้

    t02_2

    โดยข้อมูลที่เพิ่มจะมี 1 รายการที่ข้อมูลใน F02 มีค่าเป็น null

     

    จากนั้นลองทำการ SELECT แบบเดิมดังนี้

    1. ต้องการข้อมูลใน TABLE01 ที่ข้อมูลในฟีลด์ F02 ของตารางนี้มีในฟีลด์ F02 ของ TABLE02 ด้วย

    คำสั่งที่ใช้คือ SELECT * FROM TABLE01 WHERE F02 IN (SELECT F02 FROM TABLE02);

    ผลลัพธ์ที่ได้คือ

    result1

    จะเห็นว่าได้ผลลัพธ์แบบเดิม ซึ่งถูกต้อง

     

    1. ต้องการข้อมูลใน TABLE01 ที่ข้อมูลในฟีลด์ F02 ของตารางนี้ไม่มีในฟีลด์ F02 ของ TABLE02 โดยปรับคำสั่งจาก IN เป็น NOT IN

    คำสั่งที่ใช้คือ SELECT * FROM TABLE01 WHERE F02 NOT IN (SELECT F02 FROM TABLE02);

    ผลลัพธ์ที่ได้คือ

    result3

    ซึ่งไม่มีผลลัพธ์ใด ๆ ออกมาเลย

    ลองเพิ่มเงื่อนไขใน subquery โดยเอารายการที่ F02 มีค่าเป็น null ออกไป

    คำสั่งที่ใช้คือ SELECT * FROM TABLE01 WHERE F02 NOT IN (SELECT F02 FROM TABLE02 WHERE F02 IS NOT NULL);

    ผลลัพธ์ที่ได้คือ

    result2

    ซึ่งเป็นไปตามที่เราต้องการ

     

    สรุปได้ว่า กรณีที่เราต้องการใช้งานคำสั่ง SELECT ที่ใช้ร่วมกับเงื่อนไข NOT IN ตามด้วย subquery  ต้องระมัดระวังในเรื่องของผลลัพธ์ที่ได้จาก subquery มีค่าข้อมูลที่เป็น null อยู่ด้วย ซึ่งจะทำให้ได้ผลลัพธ์ไม่ตรงตามที่เราต้องการ

     

    ข้อมูลอ้างอิง 

    https://docs.oracle.com/cd/B19306_01/server.102/b14200/conditions013.htm

    https://docs.oracle.com/cd/B19306_01/server.102/b14200/expressions014.htm#i1033664