Dockerized Primitive Pictures – Reproducing images with vector-based geometric primitives

มีโปรเจคบน github ที่ใช้สร้างรูปภาพด้วย geometric primitives สำหรับใครที่ชอบรูปภาพแบบนี้จะรู้สึกแบบฟินมากที่มีโปรเจคนี้ขึ้นมา ปรบมือให้เลยหล่ะกัน 👏 👏 👏 👏 👏
ภาพ geometric primitives คือ ? จะอธิบายไงดีให้ภาพมันอธิบายตัวเองหล่ะกัน

รูปใหญ่ ๆ ก็จะประมาณนี้ สวยใช่ไหมล่ะ ^_^

ใครอยากตามไป Fork ก็ตามนี้เลย https://github.com/fogleman/primitive  ส่วนเราก็มาลองสร้าง Docker กัน

  1. เราใช้ Image จาก Go (golang) is a general purpose, higher-level, imperative programming language
FROM golang:alpine
MAINTAINER M
LABEL version="latest"

RUN apk add --no-cache git && \
mkdir -p /opt && cd /opt && \
go get -u github.com/fogleman/primitive

VOLUME /opt
WORKDIR /opt

CMD ["/bin/sh"]
  • มาลองใช้งานกัน
    docker run -it --rm -v /path/data:/opt primative:alpine primitive -i input.png -o output.png -n 100
  • มาดูผลลัพธ์กัน
  • ชอบ ๆ ๆ 😍😍😍😍

Dockerized (SQLiv) massive SQL injection

SQLiv
Massive SQL injection scanner

FROM alpine:latest
MAINTAINER M
LABEL version="latest"

RUN apk add --no-cache python py-pip openssl git && pip install --upgrade pip && \
rm -rf /var/cache/apk/* && \
mkdir -p /opt && cd /opt && git clone https://github.com/Hadesy2k/sqlivulscan.git && \
cd /opt/sqlivulscan && \
chmod 755 /opt/sqlivulscan/setup.py && \
python2 setup.py -i

RUN rm -rf /opt && chmod 755 /usr/share/sqliv/sqliv.py

WORKDIR /usr/share/sqliv

ENTRYPOINT ["python", "sqliv.py"]
CMD ["--help"]

ป.ล.

  • ไว้ใช้สำหรับหาข้อผิดพลาดเพื่อป้องกัน ไม่แนะนำให้ใช้มีดแทงตัวเอง นะจ๊ะ นะจ๊ะ
  • อยู่ในแลปช่วงหัดเขียน Dockerfile
  • ข้อมูลเพิ่มเติมที่ https://en.kali.tools/all/?tool=1334
  • build เอาหล่ะกันนะจ๊ะ นะจ๊ะ

 

การติดตั้ง Server สำหรับ JHCIS ด้วย Linux Ubuntu 17.04

**บล็อกนี้ยาวเลยทีเดียว เอาเป็นว่าตัดแบ่งออกเป็น 4 ตอนหล่ะกันนะ จะพยายามเขียนให้จบเร็วที่สุด ^_^
I. เกริ่นหน่อย
II. การติดตั้ง(รวมถึงการย้ายข้อมูลจากระบบเดิม)
III. การปรับแต่งให้ระบบ (Server, MySQL) ให้ได้ประสิทธิภาพที่ดีขึ้น
IV. การติดตั้งระบบอื่นเพื่อการสนับสนุนระบบการทำงานของหน่วยบริการ

ที่มาและเหตุผล ….

ดูเป็นทางการกันเลยทีเดียว แต่ความเป็นจริง ๆ แล้วมันก็มาจากเหตุผลบ้าน ๆ นั่นแหล่ะว่าเพราะมันมีปัญหา แล้วปัญหาก็คือ

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

    เครื่องแม่ข่าย (Server) ก็ควรทำหน้าที่ให้บริการในระบบเครือข่ายแก่เครื่องลูกข่าย (Client) ถึงแม้เดิมทีทรัพยากรในหน่วยบริการจะมีจำกัด จนต้องทำเครื่องเป็น Server ในโหมด Developer  มานานนมละจนหลายคนเข้าเข้าใจว่าเครื่องที่ลงโปรแกรม JHCIS Server คือ Server จริง ๆ ในรูปแบบ Client – Server
  • พฤติกรรมใช้งาน พบว่าระบบปฏิบัติการ (Windows) เจ๊ง ติดไวรัส ไฟล์ถูกเข้ารหัส โปรแกรมติดหนอน ระบบทำงานช้า ส่วนหนึ่งมาจากพฤติกรรมใช้งานของผู้ใช้งานที่ไม่ระมัดระวังเอง ยิ่งเครื่องถูกใช้จากมากหน้าหลายตา ความเสี่ยงก็ยิ่งเพิ่มขึ้นมากเท่านั้น คุณแสกนไวรัสก่อนเปิดแฟลชไดร์ฟรึยัง ?
  • ข้อจำกัดของระบบปฏิบัติการที่ใช้งานอยู่ เชื่อแน่ว่าเกิน 90 % เครื่องทำงานบนระบบปฏิบัติการวินโดวส์ (ตอนนี้เวอร์ชั่น 10 อัพเดทกันรึยัง) สำหรับวินโดวส์เองมีมีรุ่นที่ใช้งานเป็น Server แต่ด้วยราคาและความยากในการสรรหา ดูราคาในท้องตลาดกัน

    ส่วนใหญ่ที่ใช้งานก็เป็นกลุ่ม Desktop Edition มันก็เหมาะเป็น Desktop นั่นแหล่ะ เราขืนใจระบบมากไป
  • อยากได้ Server ที่เสถียร (เหงาใช่ไหมจะไปหา ♪♪ จะไปเช็ดน้ำตาให้ตอนนี้
    เคยเป็นเพื่อนมาอย่างไร ก็ยังเป็นทุกนาที ♪♪ ตึ่งโป๊ะ) ส่วนใหญ่แล้วระบบปฏิบัติการที่ใช้ในกลุ่ม Server ก็จะเป็น *nix (Linux UNIX บลาาาา) สรุปคือมันดี อึด ถึก ทน เหมาะ สำหรับการประมวลผลและให้บริการในเครือข่าย #ทำไมมันดีจัง แต่… มันก็ต้องแลกมาด้วยความยากและระยะเวลาการเรียนรู้ ระบบปฏิบัติการนี้ก็เลยจำกัดอยู่ในกลุ่มเล็ก ๆ กลุ่มที่ทำงานด้านคอมพิวเตอร์ แต่…ทุกอย่างก็ง่ายขึ้นเมื่อมี Ubuntu

Ubunu คืออะไร

อูบุนตู (Ubuntu) เป็นระบบปฏิบัติการคอมพิวเตอร์ที่เป็นระบบปฏิบัติการแบบเปิดซึ่งมีพื้นฐานบนลินุกซ์ดิสทริบิวชันที่พัฒนาต่อมาจากเดเบียน การพัฒนาสนับสนุนโดยบริษัท Canonical Ltd ซึ่งเป็นบริษัทของนายมาร์ก ชัทเทิลเวิร์ธ ชื่อของดิสทริบิวชันนั้นมาจากคำในภาษาซูลู และภาษาโคซา (ภาษาในแอฟริกาใต้) ว่า Ubuntu ซึ่งมีความหมายในภาษาอังกฤษคือ “humanity towards others”


Ubuntu เป็น Linux ที่ถูกหลอมลวมจากความเสถียรและความง่ายในการใช้งานเข้าด้วยกัน (เรากำลังพูดถึง Desktop Edition นะ ส่วน Server Edition ก็ละไว้สำหรับกลุ่มแอดมินเค้าเหอะ ส่วนเรื่องการปรับแต่งประสิทธิภาพบางส่วนเพื่อทำให้เครื่องที่ใช้ Ubuntu เหมาะสำหรับ Server อยู่ท้าย ๆ นะ)

ช่วงรอตอนที่ 2 ก็โหลดไฟล์ติดตั้งรอเลยนะ ดาวน์โหลด Ubuntu Desktop (ใช้ Ubuntu GNOME หล่ะกัน) เวอร์ชั่น ณ ปัจจุบันจะเป็น 17.04 (Zesty Zapus Support until 2018-01)

การติดตั้ง Ubuntu GNOME 17.04

  1. หลังจากดาวน์โหลดไฟล์ติดตั้งมาแล้วก็ทำการสร้างตัวติดตั้งจาก USB ได้เลย ในที่นี้จะใช้โปรแกรมชื่อ Rufus (ปัจจุบัน Version 2.17) ขั้นตอนก็ไม่ซับซ้อนเลือกไฟล์ ubuntu-gnome-17.04-desktop-amd64.iso แล้วก็กดปุ่ม start เลย (ภาพ screen shot จากเว็บอ่ะนะ)
  2. เรียบร้อยจากขั้นตอนที่ 1 ก็เริ่มติดตั้งกัน หน้าจอแรกจะขึ้นมาให้เราเลือก
    – Try Ubuntu GNOME กรณีอยากเล่นเนตชิล ๆ ไปด้วยก็เลือกตัวนี้ได้แล้วค่อยกด Install ต่อได้เหมือนกัน
    – Install Ubuntu GNOME
  3. ขึ้นหน้าจอเตรียมการติดตั้ง กรณีเนตแรงและต้องการลดระยะเวลาการติดตั้งก็ติ๊ก Download ตามภาพ
  4. พอกด Continue จะขึ้นหน้าจอเตรียมฮาร์ดดิสก์สำหรับติดตั้ง มีตัวเลือก
    – Erase disk and install Ubuntu GNOME ตัวเลือกนี้ระบบติดตั้งจะเตรียมดิสก์แบบฉันคิดให้นะ นายไม่ต้องทำไร
    – Something else  ส่วนตัวนี้ก็ตรงข้ามกับข้างบน นายทำเองอยากได้แบบไหนก็จัดเลย

    เราก็เลือกแบบที่ 2 สิ 555 คือต้องบอกเบื้องต้นก่อนว่าเครื่องมีฮาร์ดดิสก์ 2 ลูก
    – ลูกแรก ขนาด 10 GB ไว้ติดตั้งตัว OS (Ubuntu)
    – ลูกที่สอง ขนาด 1 GB ไว้เก็บไฟล์สำรองจากระบบสำรอง (เดี๋ยวจะกล่าวถึงในตอนที่ 4 แต่ก็เตรียมไว้เบื้องต้นตามนี้)
  5. เริ่มทำการแบ่งพาร์ติชั่น ปกติเราจะแบ่งออกเป็น
    – /boot ขนาด 1 GB
    – swap ขนาด 1 GB
    -/ (root)
    มีเพิ่มคือเราแยกพาร์ติชั่น /var และสร้างพาร์ติชั่น /data ในฮาร์ดดิสก์อีกลูก ส่วนใครสงสัยว่าจะใช้ขนาดเท่าไหร่ในแต่ละพาร์ติชั่นก็ไปอ่านได้ตามนี้
    ส่วนตัวเลือกตรงคอมโบบ็อกซ์ Device for boot loader installation ก็ให้เลือกฮาร์ดดิสก์ตัวแรกไป
  6. กด Install Now จะขึ้นหน้าจอให้เลือก Location เราคนไทยก็เลือก Bangkok ไป
  7. กด Continue ก็เลือก Keyboard Layout ซึ่งจะสัมพันธ์กับข้อที่แล้ว ฉลาดเน๊อะ
  8. กด Continue จะให้ใส่ข้อมูลชื่อผู้เข้าใช้งาน รหัสผ่านและชื่อเครื่อง ส่วนจะใส่อะไรไปก็จำให้ดี ๆ ส่วนชื่อเครื่องเองก็มีผลกับเรื่องของ Host name ในระบบเครือข่ายด้วย
  9. พอกด Continue ไปก็จะเริ่มการติดตั้งตัว Ubuntu GNOME ง่ายไหม ^_^ ก็รอ สำหรับใครที่เลือก Try Ubuntu GNOME ในข้อแรกก็สามารถเล่นอินเตอร์เนตชิล ๆ รอได้เลย
  10. เมื่อทำการติดตั้งเสร็จก็จะแสดงหน้าจอแบบนี้ ยินดีด้วยทุกอย่างกำลังไปได้สวย

    กด Restart ได้เลย

    พร้อม ๆ กับที่ระบบให้เราถอด USB ตัวติดตั้งออกและกด ENTER ต่อเพื่อเริ่มต้นระบบใหม่
  11. ช่วงระหว่างการรอการบูตมีประเด็นที่ทำไมต้องเลือก Ubuntu GNOME 17.04
    – แรกเลยคือต้องการความสด ณ ปัจจุบันเวอร์ชั่นนี้คือเวอร์ชั่นล่าสุดที่ Ubuntu สร้างออกมาสิ่งที่จะได้คือเคอร์เนล 4.10 แหล่ะ อันนี้ใหม่ชัวร์รวมทั้งแพคเกจ/โปรแกรม ต่าง ๆ (ส่วนเราเองก็ใช้ 17.10 แบบ Daily build อยู่เลย)
    – เวอร์ชั่นนี้ไม่ใช่ Long term support (LTS) releases are for 5 years. นั่นหมายความว่าเราจะได้รับการซัพพอร์ตแค่ 9 เดือน สำหรับรุ่น Regular ซึ่งก็คือหมดในเดือนมกราคม 2018 นั่นเอง สำหรับใครที่ต้องการการซัพพอร์ตยาว ๆ ก็สามารถเลือกเวอร์ชั่น 16.04 ซึ่งตอนนี้ปรับปรุงเป็น 16.04.3 แล้ว ตัวนี้เป็น LTS
    – ทำไมไม่ใช้ Server Edition ถ้าจะทำ Server ประเด็นนี้ก้ำกึ่งเราอธิบายแบบนี้หล่ะกัน ประเด็นแรก ด้วยความที่ JHCIS ถูกใช้ในหน่วยบริการปฐมภูมิ (รพ.สต.) เป็นส่วนใหญ่ ผู้ที่ใช้งานก็เป็นพยาบาล นักวิชาการสาธารณสุข ทันตาภิบาล พนักงานบันทึกข้อมูล คนงาน ในพื้นที่ห่างไกล ไม่มีหรอกนักคอมพิวเตอร์หรือกลุ่มคนด้านนี้เฉพาะ อาจจะมีบ้างที่เป็น Power User ที่สนใจเรื่องนี้ แต่ความคุ้นชินกับระบบการติดต่อแบบคอมมานไลน์นี่คงยากและลำบากเกินไป (อันนี้ขอระบายหน่อย รพ.สต ในอำเภอเราไกลสุด ~38 กิโลเมตร การสนับสนุนมันทำได้จำกัด จำกัดมาก ๆ T_T) ภาพนี้เป็นวันที่เราออกไปช่วยติดตั้งระบบนี้แหล่ะ ไม่ใช่ รพ.สต.ที่ไกลสุดนะ แต่ไปเส้นทางนี้แหล่ะ หมอกเต็มเลย

    ประเด็นที่สอง ถ้าเราอยากให้ผู้ใช้งาน/คนใช้ไม่ต่อต้านมากไป อย่าทำให้มันยากเกินไปสำหรับการเรียนรู้ วันนึงข้างหน้าเราอาจะเห็น รพ.สต.ใช้ LibreOffice แทน Microsoft Office ใช้ Openshot ตัดต่อวิดีโอออกเยี่ยมผู้ป่วย ก็ได้ ตอนนั้นถนนในประเทศเราคงปูด้วยทองคำไปละ
    – ถ้าไม่อยากใช้ Server Edition แบบคอมมานด์ไลน์ก็มี Cent OS มี Debian มี Open SUSE  บลา ๆ ที่จริงมันมีมากกว่าความชอบนะ ถ้าสังเกตจากความนิยมแล้ว Debian Base จะได้รับความนิยมสูงสุด
  12. พอเริ่มต้นระบบใหม่อีกครั้งจะขึ้นหน้าจอแบบนี้ก็เริ่มใช้งานได้เลย ชื่อผู้ใช้และรหัสผ่านก็ที่ตั้งไว้จากก่อนหน้านี้
  13. ถึงขั้นนี้ก็ยังต้องทำเพิ่มนิดหน่อย ถ้าเปรียบเหมือน Windows นี่ก็แค่เพิ่งติดตั้ง OS เสร็จแค่นั้น ยังไม่มีแพคเกจ/โปรแกรมที่เราจำเป็นต้องใช้สำหรับทำเป็น JHCIS Server เลย ซึ่งแพคเกจที่เราจะทำการติดตั้งและจำเป็นต้องใช้มีดังนี้
    – MySQL Server ตัวนี้เป็น RDBMS  สำหรับเก็บข้อมูลจากโปรแกรม JHCIS
    – MySQL Workbench สำหรับติดต่อกับ MySQL Server แบบ GUI
    – TeamViewer สำหรับทำ Remote Desktop กรณีที่ต้องขอความช่วยเหลือจากคนใจดี
    – แพคเกจอื่น ๆ ที่จำเป็น
    โดยเริ่มต้นก็ทำการเปิดโปรแกรม Terminal ขึ้นมา (เลี่ยงไม่ได้นะ ยังไงก็ต้องได้ใช้คอมมานด์ไลน์บ้าง แต่ก็จะพยายามให้น้อยที่สุดหล่ะกัน)


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

    sudo apt update && sudo apt upgrade -y

    ติดตั้ง MySQL Server ในที่นี้เราจะใช้เวอร์ชั่น 5.7 (นี่ก็ใหม่ เราอยากได้ของสดอยู่แล้วหนิ ^_^) การติดตั้งเพื่อให้ง่ายเราจะใช้ตัวช่วยนั่นก็คือ tasksel

    sudo apt install tasksel
    sudo tasksel

    จะขึ้นหน้าจอสำหรับเลือกแพคเกจ/โปรแกรม

    ให้เลือกเลือกแพคเกจ/โปรแกรม ตามนี้ (เดี๋ยวจะได้ใช้นะครับ จะอธิบายทีหลัง)
    – LAMP Server
    – Samba File Server
    – Ubuntu GNOME Desktop (อันนี้เลือกอยู่ก่อนหน้าแล้ว)
    – OpenSSH Server
    – Basic Ubuntu Server
    การเลือก/ยกเลิก ก็กด Space Bar นะ แล้วก็กด Tab มาที่ <ok>

  14. จะขึ้นหน้าจอการติดตั้งแพคเกจ/โปรแกรมที่เราเลือก

    พอถึงขั้นตอนการติดตั้ง MySQL Server ก็ให้ระบุ Password ของผู้ใช้งาน root (คนที่ใหญ่สุดในโปรแกรม MySQL)

    แล้วก็ยืนยัน Password เดิม

    ** ประเด็นเรื่อง Password ของ root นี่ ขอพูดนิดนึงนะ ส่วนจะทำตามหรือไม่ก็คงอีกเรื่อง ผลกระทบมันก็เรื่องความเสี่ยง/ความปลอดภัยของข้อมูลเป็นหลัก โดยปกติในฐานะของผู้ดูแลระบบฐานข้อมูล (Database Administrator) Password ของ root จะต้องเดายาก เข้าถึงได้เฉพาะผู้ดูแล ส่วนโปรแกรมอื่น/ระบบอื่น/ผู้ใช้งานอื่น ก็สร้าง User ให้พร้อมกำหนดสิทธิ์/ระดับการใช้งาน ให้ทีหลัง User root แทบที่จะไม่ถูกนำมาใช้ในระดับอื่นเลยนอกจาก Administrator อย่างเดียว ปกติระบบจริง ๆ ที่เน้นความปลอดภัยก็ทำกันในลักษณะนี้นะ เอาเป็นว่าได้พูดแล้วนะแล้วแต่หล่ะกันระบบใครระบบมัน ^_^
  15. เมื่อติดตั้งแพคเกจ/โปรแกรม เสร็จเรียบร้อยลองมาตรวจดูว่า MySQL Server ซึ่งเป็นตัวเอกของบทความนี้ถูกติดตั้งไปรึยังและทำงานได้ไหม
    sudo systemctl status mysql

    กรณีที่ไม่มีอะไรผิดพลาดจะขึ้นหน้าจอนี้ เป็นอันว่าใช้ได้

  16. ที่นี้ก็ติดตั้งโปรแกรม MySQL Workbench ต่อได้เลย (ควรมีนะถ้าอยากเลี่ยงคอมมานด์ไลน์) โดยการกดที่ Software และค้นหาตามภาพ เจอก็กด Install

    เสร็จแล้วก็ลองเปิดเข้าใช้งานหน้าตาคร่าว ก็ตามรูป เป็น MySQL Client อีกตัวหนึ่ง (Official จาก MySQL)
  17. ทำการติดตั้งแพคเกจอื่น ๆ ที่จำเป็น
    sudo apt install pv gdebi

  18. ทำการติดตั้ง TeamViewer เพื่อใช้สำหรับ Remote Desktop กรณีต้องการความช่วยเหลือ (คาดหวังให้ทำ DDNS หรือ VPN ไว้นี่คงยากหน่อย T_T)
    โดยให้ Download โปรแกรมจากเว็บไซต์ ปัจจุบันเวอร์ชั่น v12.0.85001 (deb 32-Bit / 64-Bit Multiarch)

    sudo dpkg --add-architecture i386
    sudo apt update
    sudo dpkg -i teamviewer_i386.deb
    


    เรียกใช้งานก็จะขึ้นหน้าจอแบบนี้ (License ก็จะเป็น Non-Commercial มันก็จำกัดแหล่ะ ถ้าอยากใช้ระยะยาวก็ซื้อนะ )

  19. ทีนี้ก็เหลือการย้ายข้อมูลจากระบบเดิมขึ้นระบบใหม่
    ช่วงรอตอนที่ 2/2 ก็ลองติดตั้งกันดูนะครับ ติดปัญหาอะไรก็ลอง ๆ Discus กันได้ หรือมีคำแนะนำอื่น ๆ เพิ่มเติมก็ยินดี ^_^
  20. ก่อนย้ายข้อมูลจาก JHCIS เครื่องเดิม เรามาดูโครงสร้างฐานข้อมูล jhcisdb กันก่อน จะเห็นว่าฐานข้อมูลประกอบไปด้วย ตาราง (Tables), Stored Procedures, Functions เพราะฉะนั้นขั้นตอนการส่งออก/นำเข้า ก็ต้องให้สิ่งเหล่านี้ออกไปด้วยและนำเข้าให้ครบถ้วน

    เมื่อพร้อมก็เริ่มกันเลย Tool ที่ใช้เราจะใช้ mysqldump

    mysqldump --user=<USER NAME> -p --host=<HOST NAME/IP Address> --port=<PORT> --add-drop-database --add-drop-table --max_allowed_packet=1G --default-character-set=utf8 --skip-lock-tables --routines --events --triggers --single-transaction --databases "jhcisdb" &gt; jhcisdb.sql

    ก็ให้ระบุ ค่าที่ถูกต้องแทนตัวแปรในคำสั่ง
    <USER NAME> : ถ้าเดิม ๆ ก็จะเป็น root นั่นแหล่ะ
    <HOST NAME> : ชื่อเครื่อง JHCIS Server เดิมหรืออาจระบุเป็น IP Address ก็ได้เช่นกัน
    <PORT> : เดิม ๆ เป็น 3333 ในกรณีที่ไม่เปลี่ยนแปลงมาก่อน
    รันคำสั่งเสร็จก็รอ รอ ^_^  ส่วนพารามิเตอร์ที่ใช้สามารถอ่านเพิ่มเติมได้ที่นี่

  21. เมื่อได้ไฟล์ส่งออกมาเรียบร้อยแล้ว ก็เริ่มขั้นตอนการจัดการ JHCIS Server เครื่องใหม่ ปกติแล้วเราก็มักจะสร้าง User และจัดการเรื่องสิทธิ์การใช้งาน ก่อน ทั้งนี้ทั้งนั้นจำเป็นต้องรันคำสั่ง เพื่อกำหนดค่าความปลอดภัยเบื้องต้นของ MySQL Server
    sudo mysql_secure_installation

    ถัดมาก็สร้างฐานข้อมูล (คำสั่ง ของ mysqldumpด้านบนจะเพิ่มการสร้างฐานข้อมูลด้วย ถ้ามันไม่มีอยู่นะ แต่เราสร้างเองก็ได้)

    CREATE SCHEMA `jhcisdb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

    ตามด้วยการกำหนดสิทธิ์การเข้าใช้งานฐานข้อมูล

    CREATE USER 'user_name'@'localhost' IDENTIFIED BY 'password';
    CREATE USER 'user_name'@'%' IDENTIFIED BY 'password';
    GRANT ALL PRIVILEGES ON jhcisdb.* TO 'user_name'@'localhost';
    GRANT ALL PRIVILEGES ON jhcisdb.* TO 'user_name'@'%';
    FLUSH PRIVILEGES;

    แล้วเราก็นำเริ่มเข้าฐานข้อมูล jhcisdb กัน

    mysql -u<user_name> -p jhcisdb < jhcisdb.sql

    ถ้าไม่มีอะไรผิดพลาดก็ลองเช็ค ตาราง (Tables), Stored Procedures, Functions ดูครบถ้วน JHCIS Server เครื่องใหม่ก็พร้อมใช้งาน

  22. ถัดมาก็ลองเปิดโปรแกรม JHCIS Client แล้วกำหนดค่าการเชื่อมต่อฐานข้อมูลใหม่ เป็นเครื่องที่เราสร้างใหม่ตะกี้ ถ้าสามารถใช้งานได้
    ** ปกติพอร์ตมาตรฐานของ MySQL จะเป็นพอร์ต 3306 กรณีเราไม่ได้เปลี่ยนแปลงค่าคอนฟิกใด ๆ
    ** มีบางเครื่องที่เข้าใช้งานแล้ว JHCIS แจ้งเตือนหน้าจอแบบนี้

    ก็ไม่ต้องตกใจไปนะ ให้เช็คเบื้องต้นดังนี้คือ
    – ในฐานข้อมูล jhcisdb มีตาราง _tmpicd10% หรือไม่ ถ้ามีก็ไม่มีอะไรให้ตกใจ

    – ให้ทำการสร้างตาราง p เปล่า ๆ ขึ้นมาเพื่อแก้บัคก่อน (ตารางนี้ไม่มีผลกับการบันทึกอะไร เพียงแต่ทำให้ Code ไม่หลุดเข้า try-catch เฉย ๆ)
    – ให้ทำการ Disable strict mode ใน MySQL Server เพื่อให้ compatible กับ MySQLเวอร์ชั่นเก่า ตามลิงค์นี้
    – เบื้องต้นก็ได้รายงาน/สอบถามไปทางอาจารย์สัมฤทธิ์แล้วนะครับ ^_^

การปรับแต่งให้ระบบ (Server, MySQL) ให้ได้ประสิทธิภาพที่ดีขึ้น

เดิม ๆ แล้ว Ubuntu หรือ Linux ดิสโทรอื่น ๆ เองเป็นระบบปฏิบัติการที่ถูกสร้างมาแบบ “out-of-box”  หมายความว่ามันเพียงพอสำหรับการใช้งาน แต่ถ้าต้องการรีดประสิทธิภาพให้ได้ออกมาเต็มที่ก็จำเป็นต้องปรับแต่งเพิ่มเติม

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

 

Sysctl Tweaks

ไฟล์ sysctl.conf เป็นไฟล์ที่เกี่ยวข้องกับเคอร์เนลโดยตรงฉะนั้น อยากให้กลับไปอ่านย่อหน้าตะกี้อีกรอบนะ เราสามารถแก้ไข้ไฟล์ sysctl.conf ได้ โดยการเปิดด้วย Text Editor ทั่ว ๆ ไป เอาที่ถนัดนั่นแหล่ะ

sudo gedit /etc/sysctl.conf

หน้าตาตอนจะแก้ไข ก็ประมาณนี้

และทำการเพิ่มรายการต่อไปนี้ลงท้ายสุดของไฟล์

### IMPROVE SYSTEM MEMORY MANAGEMENT ###

# Increase size of file handles and inode cache
fs.file-max = 2097152

# Do less swapping
vm.swappiness = 10
vm.dirty_ratio = 50
vm.dirty_background_ratio = 2

### GENERAL NETWORK SECURITY OPTIONS ###

# Number of times SYNACKs for passive TCP connection.
net.ipv4.tcp_synack_retries = 2

# Allowed local port range
net.ipv4.ip_local_port_range = 2000 65535

# Protect Against TCP Time-Wait
net.ipv4.tcp_rfc1337 = 1

# Decrease the time default value for tcp_fin_timeout connection
net.ipv4.tcp_fin_timeout = 15

# Decrease the time default value for connections to keep alive
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 15

### TUNING NETWORK PERFORMANCE ###

# Default Socket Receive Buffer
net.core.rmem_default = 31457280

# Maximum Socket Receive Buffer
net.core.rmem_max = 12582912

# Default Socket Send Buffer
net.core.wmem_default = 31457280

# Maximum Socket Send Buffer
net.core.wmem_max = 12582912

# Increase number of incoming connections
net.core.somaxconn = 4096

# Increase number of incoming connections backlog
net.core.netdev_max_backlog = 65536

# Increase the maximum amount of option memory buffers
net.core.optmem_max = 25165824

# Increase the maximum total buffer-space allocatable
# This is measured in units of pages (4096 bytes)
net.ipv4.tcp_mem = 65536 131072 262144
net.ipv4.udp_mem = 65536 131072 262144

# Increase the read-buffer space allocatable
net.ipv4.tcp_rmem = 8192 87380 16777216
net.ipv4.udp_rmem_min = 16384

# Increase the write-buffer-space allocatable
net.ipv4.tcp_wmem = 8192 65536 16777216
net.ipv4.udp_wmem_min = 16384

# Increase the tcp-time-wait buckets pool size to prevent simple DOS attacks
net.ipv4.tcp_max_tw_buckets = 1440000
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1

กรณีที่ต้องการแก้ไขอื่นเพิ่มเติมหรืออยากรู้แหล่ะมันคืออะไร ผลจากบรรทัดนั้นจะได้อะไรตามไปอ่านได้ที่นี่

แล้วก็เริ่มใช้ค่าใหม่ได้เลยโดยใช้คำสั่ง sysctl -p หรือถ้าอยากลองว่ามันรอดไหมออกหมู่หรือจ่าก็สั่ง Reboot เครื่องได้เลย

MySQL Performance Tuning and Optimization

เครื่องนี้เป็น Database Server การจะไม่ปรับความสามารถของ MySQL ดูจะเป็นเรื่องที่บาปพอสมควร -*- แต่ก็เตือนไว้อีกนั่นแหล่ะ ไม่ระวังก็มีผลทำให้ MySQL Server Start ไม่ขึ้นกันเลยทีเดียว ถ้าอยากได้เอกสาร/บทความอ่านก่อนหน้าปรับจริงก็ตามไปอ่านได้ที่นี่ อื่น ๆ เพิ่มเติม ก็ไปทำลิงค์ข้างล่างได้เลย

การปรับแต่งความปลอดภัยและ Firewall

Firewall คือ ระบบรักษาความปลอดภัยของเครื่องคอมพิวเตอร์ (อ่านว่า ไฟร์วอลล์) ไม่ให้ถูกโจมตีจากผู้ไม่หวังดีหรือการสื่อสารที่ไม่ได้รับอนุญาต ซึ่งส่วนใหญ่จะมาจากระบบเครือข่ายอินเตอร์เน็ต รวมถึงเครือข่าย LAN ด้วย ซึ่งในปัจจุบัน Firewall มีทั้งอุปกรณ์ที่เป็น Hardware และ Software

ในที่นี้เราจะใช้ Software ที่ติดมากับ Linux/Ubuntu แต่ใช้ Tool จัดการที่มันง่ายขึ้น เริ่มต้นก็ติดตั้งแพคเกจ gufw

sudo apt install gufw
sudo gufw

สิ่งที่เราควรทำคือเปิดเฉพาะสิ่งที่ต้องใช้ ง่ายไหม ^_^  โดยการคลิกที่ Rules > Add (+) ในที่นี้เราอนุญาตเฉพาะบริการ MySQL และ SSH

ในกรณีที่ใครคุ้นชินกับ iptableก็ทำได้เฉกเช่นเดียวกัน ^_^

Automatically backup MySQL database to Google Drive

ประเด็นหลัก ๆ ของบล็อกนี้ก็เรื่องของการสำรองฐานข้อมูลนั่นแหล่ะ ต่างกันนิดหน่อยกับคำว่าตัวสำรอง เราสำรองเพราะเห็นว่าสิ่งนั้นสำคัญแต่ตัวสำรองคือยังไม่สำคัญนะให้รอ ก็ได้แค่นั้นแค่ตัวสำรอง

เดี๋ยวลองไล่ลำดับ ขั้นตอนในกระบวนการนี้ด้วยกัน

  1. เริ่มสำรองข้อมูล ในที่นี้คือฐานข้อมูลของ MySQL ด้วย Tool มาตรฐานคือ mysqldump (ส่วนเรื่องพารามิเตอร์ในคำสั่ง อะไรยังไง จะเอาอะไร ไม่เอาอะไร อ่านต่อได้ที่นี่)
  2. บีบอัดไฟล์ให้ขนาดเล็กลง
  3. เก็บไฟล์ไว้ที่เครื่องโลคอลนิดหน่อยอีก 30 วันค่อยมาลบหล่ะกัน (ทั้งนี้ทั้งนั้นก็ขึ้นกับความต้องการด้วยนะว่าเหมาะสมแค่ไหน)
  4. ทำการอัพโหลดข้อมูลที่สำรองได้ขึ้น Google Drive ผ่าน Google Drive CLI Client ตัวนึงที่ชื่อว่า gdrive (จุดประสงค์หลักคือเพื่อให้มีแหล่งเก็บอื่นเพิ่ม) ก่อนการใช้งานจำเป็นต้องอนุญาตให้ gdrive สามารถเข้าถึง Google Drive ของเราได้ก่อน
    1. อนุญาตสิจ๊ะ
    2. คัดลอก Token ที่ได้ เพื่อมาใช้ในโปรแกรม
  5. ทั้งหมดทั้งมวลให้ทำงานอัตโนมัติ โดยการใช้ crontab (สงสัยวิธีใช้งานก็ตามอ่านกันที่นี่นะ #เหมือนจะขี้เกียจ #55555)

โดยขั้นตอนข้างต้นเราเขียนเชลล์สคริปท์สั้น ๆ สำหรับทำงานแบบรูทีนตามนี้

ผลลัพธ์ที่ได้ก็ตามนี้

ป.ล. 1
การสำรองข้อมูลเป็นเรื่องที่สำคัญพอ ๆ กับการทดสอบไฟล์ที่สำรองได้นั้นสามารถใช้งานได้หรือไม่

ป.ล 2
gdrive – gdrive is a command line utility for interacting with Google Drive.
pv – monitor the progress of data through a pipe.

 

Smart Card Reader เสียรึเปล่าเนี่ย ?

Smart Card Reader เสียรึเปล่าเนี่ย ?

คำถามแรกเลยเวลาที่เปิดใช้งานโปรแกรมที่จำเป็นต้องติดต่อกับ Smart Card (สำหรับหน่วยงานราชการเกี่ยวกับเงิน ๆ ทอง ๆ นี่หลายโปรแกรมกันเลยทีเดียวเชียว) แล้วผลปรากฏว่า นิ่ง นิ่ง โปรแกรมไม่อ่านการ์ด/บัตร แล้วก็จะเกิดคำถามต่อ ๆ มา

  • Driver เครื่องอ่านติดตั้งรึยัง ติดตั้งแล้วใช้ได้ไหม
  • โปรแกรมต้องการคอมโพเนนท์/ไลบรารี่อะไรเพิ่มเติมอีกไหม
  • การ์ด/บัตร ยังอ่านได้ไหม มันเลือนไปอ่านไม่ได้เหมือนหัวใจใครบางคนรึเปล่า
  • แล้วเครื่องนี่ยังใช้ได้ไหม (วะ) เนี่ยยยยย

ปกติเราก็มักจะจำกัดขอบเขตของปัญหาใช่ไหม ถ้าเครื่อง Smart Card Reader เจ๊งจริงก็จะได้รู้ไง โดยฝั่ง Linux ก็สามารถใช้ pcsc_scan ตรวจสอบ ผลที่ได้ก็จะประมาณนี้ถ้าทุกอย่างโอเค

ในฝั่ง Windows เองมักใช้โปรแกรมที่ติดมากับ Smart Card Reader ซึ่งปกติก็มักหายไปกับแผ่น Driver เรียบร้อยแล้วหรือใครเพียรพยายามเก็บไว้ก็ดีไป ส่วนเราจะอิ๊อ๊ะอยู่ใย ก็ทำเองเลย โดยความต้องการพื้นฐานสำหรับรันโปรแกรมนี้ คือ

  • .NET Framework 2.0 ขึ้นไป
  • Smart Card Reader
  • การ์ด/บัตร ประชาชนคนไทย 😛

โปรแกรมชื่อ Reader Checker สามารถตรวจสอบว่าเครื่องอ่านหรือบัตรใช้งานได้จริงหรือไม่ วิธีง่าย ๆ ก็ให้โปรแกรมอ่านการ์ด/บัตรนั่นแหล่ะ กรณีที่มีการติดตั้งเครื่องอ่านสมาร์ทการ์ดมากกว่าหนึ่งเครื่องก็สามารถเลือกได้จากลิสต์ ดังรูป

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

ป.ล.

  • โปรแกรมสามารถส่งออก/Export รูปที่อ่านได้ ถ้าต้องการ
  • ไลบรารี่ที่เกี่ยวข้อง กรณีต้องการพัฒนาโปรแกรมที่เกี่ยวกับ บัตรประชาชนคนไทยก็ ตามไปที่ GitHub ของคุณ Chakphanu Komasathit หรือในกลุ่มของ HOSXP
  • Specification ของ PC/SC
  • Windows PC/SC 1.0 (Smart Card)
  • สามารถสนับสนุนค่ากาแฟเราได้นะ Bitcoin Wallet Address :
    3DchASXQrisoqmJfxU6uRsbC5NV3Wsspyb

 

 

 

HDC & Smart Card On Ubuntu

จากที่ระบบ HDC ของกระทรวงสาธารณสุขปรับปรุงจนถึงเวอร์ชั่น 4.0 และก็มีการปรับปรุงเรื่องการตรวจสอบสิทธิ์การเข้าถึงข้อมูลด้วย Smart Card ซึ่งมันก็เป็นเรื่องที่น่ายินดีเลย (เราเองก็เพิ่งได้อบรมเชิงปฏิบัติการจากจังหวัดไปเมื่อวันนี้ สด ๆ ร้อน ๆ)

ด้วยความที่เครื่องทำงานหลัก ๆ อยู่บน Ubuntu งั้นเราก็มาลองใช้ Smart Card ตรวจสอบเพื่อเข้าระบบ HDC ผ่าน Ubuntu กัน (สำหรับดิสโทรอื่นก็คงไม่ต่างกันมากนัก) และ Smart Card Agent ก็ถูกพัฒนาขึ้นโดยใช้ Java เพราะฉะนั้นก็การันตีในระดับนึงว่าแพลตฟอร์มอื่นก็รันได้เช่นกัน

  1. เดิม ๆ เครื่องไม่รู้จัก Smart Card รัน Agent จะขึ้นไดอะล็อกแบบนี้ ไม่ต้องตกใจ มันแจ้งเตือนถูกแล้ว
  2. เพราะฉะนั้นก็ทำให้เครื่องเรารู้จัก Smart Card ซะ มีแพคเกจที่จำเป็นสำหรับติดต่อ Smart Card ก็ติดตั้งได้เลยตามนี้
    sudo apt install pcscd pcsc-tools
  3. ตรวจสอบอีกทีว่าติดต่อ Smart Card ได้แล้ว ด้วย pcsc_scan


    เจอข้อความตามภาพก็เป็นอันว่าเครื่องรู้จัก Smart Card Reader และสามารถอ่านบัตรประชาชนชาวไทยได้เรียบร้อยแล้ว

  4. ขั้นตอนต่อไปก็รัน Smart Card Agent ได้เลย (ข้ามเรื่องติดตั้ง JRE ไปเลยนะ ถ้าไม่มีก็ติดตั้งซะ)
    java -Dsun.security.smartcardio.library=/lib/x86_64-linux-gnu/libpcsclite.so.1 -jar javadaemon.jar 8080

    **มีเรื่องที่ต้องตรวจสอบ 2 เรื่องคือ
    – Port 8080 ไม่ควรถูกใช้ถ้าใช้ก็ปิด Service ที่ใช้ชั่วคราว
    – เพื่อให้ไลบรารี่ smartcardio ของ java ทำงานได้ ก็ใช้คำสั่งตามข้างบน อ้างอิง

  5. เปิดหน้า Login ของ HDC ก็เป็นอันสามารถเข้าใช้งานได้ เคลียร์ !!!

เหมือนเพิ่งผ่านไปเมื่อวาน

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

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

รักและคิดถึงเสมอ…

การหาปีงบประมาณแบบไทยสำหรับ MySQL

ปีงบประมาณ หรือ ปีงบการเงิน (อังกฤษ: fiscal year, financial year หรือ budget year) เป็นช่วงเวลาที่ใช้สำหรับคำนวณงบการเงินประจำปีในธุรกิจและองค์กรอื่น ๆ ในหลายเขตอำนาจตามกฎหมาย กฎข้อบังคับเกี่ยวกับการบัญชีและการเก็บภาษี จะต้องอาศัยรายงานเหล่านี้อย่างน้อยครั้งหนึ่งต่อสิบสองเดือน แต่ไม่จำเป็นว่าช่วงเวลาที่รายงานนี้จะต้องตรงกับปีตามปฏิทิน ซึงปีงบประมาณของไทยเริ่มตั้งแต่เดือนตุลาคมถึงเดือนกันยายนของปีถัดไป

เราสามารถเขียนฟังก์ชั่น (Function) เพื่อคำนวณหาปีงบประมาณจากฐานข้อมูล MySQL ตามนี้

DELIMITER $$

DROP FUNCTION IF EXISTS THGOVYEAR$$
CREATE FUNCTION THGOVYEAR(
    xdate DATETIME,
    th BIT)
RETURNS INT 
DETERMINISTIC
BEGIN
    RETURN IF(MONTH(xdate) < 10, YEAR(xdate), YEAR(DATE_ADD(xdate, INTERVAL 1 YEAR))) + (543*th);
END$$

DELIMITER ;

โดยตัวแปรที่รับในฟังก์ชั่นเองจะมี 2 ตัว คือ

  • xdate : วันที่ที่ต้องการคำนวณ
  • th : ต้องการแสดงผลแบบปี พ.ศ หรือไม่ (1 = ใช่, 0 = ไม่)

ที่นี้มาลองทดสอบดู โดยการสร้างตารางเก็บวันที่กัน

DROP TABLE IF EXISTS DemoDate;
CREATE TABLE DemoDate (
    fielddate DATETIME NOT NULL
);
INSERT INTO DemoDate (fielddate) VALUES
    ('2008-09-01 00:00:00'),
    ('2008-04-04 00:00:00'),
    ('2009-05-25 00:00:00'),
    ('2010-06-30 00:00:00'),
    ('2011-07-01 00:00:00'), 
    ('2010-10-01 00:00:00'),
    ('2011-10-01 00:00:00'), 
    ('2012-09-30 00:00:00'), 
    ('2012-10-01 00:00:00'),
    ('2013-09-30 00:00:00'),
    ('2012-10-01 00:00:00'),
    ('2013-09-30 00:00:00'),
    ('2013-10-01 00:00:00'),
    ('2014-09-30 00:00:00'),
    ('2014-10-01 00:00:00'),
    ('2015-09-30 00:00:00'),
    ('2015-10-01 00:00:00'),
    ('2016-09-30 00:00:00'),
    ('2016-10-01 00:00:00'),
    (NOW()),
    ('0000-00-00 00:00:00');

แล้วก็มาทดสอบกัน

ขอให้มีความสุขกับการทำงานกัน แด่วันแรงานนนนนนน

**ช่วงนี้ไม่ค่อยได้เขียนบล็อคเลย แต่เขียน ๆ หน่อยเหอะ เดือนละเรื่องก็ยังดี T_T …
**งานช่วงนี้เหรอ ถามว่าท้อไหมตอบเลยว่ามากกกกก (แต่ไม่เคยถอยนะ หันหลังแม่มมเลย 555)

ไตรมาสใน MySQL แบบปีงบประมาณของไทย

ไตรมาส เป็นช่วงระยะเวลาสามเดือน ซึ่งแบ่งช่วงเวลา หนึ่งปี ออกเป็น สี่ ไตรมาส ในเชิงธุรกิจการพิจารณาผลประกอบการนิยมใช้ช่วงเวลาไตรมาส ในการประเมินผล กรณีที่เป็นตามปีปฏิทินจะแบ่งได้

  • ไตรมาสที่ 1 หมายถึงช่วงเดือนมกราคมถึงมีนาคม
  • ไตรมาสที่ 2 หมายถึงช่วงเดือนเมษายนถึงมิถุนายน
  • ไตรมาสที่ 3 หมายถึงช่วงเดือนกรกฎาคมถึงกันยายน
  • ไตรมาสที่ 4 หมายถึงช่วงเดือนตุลาคมถึงธันวาคม

แต่ระบบราชการของไทย ระบบรายงานส่วนใหญ่ขึ้นกับปีงบประมาณ ^_^

ปีงบประมาณ หรือ ปีงบการเงิน (อังกฤษ: fiscal year, financial year หรือ budget year) เป็นช่วงเวลาที่ใช้สำหรับคำนวณงบการเงินประจำปีในธุรกิจและองค์กรอื่น ๆ ในหลายเขตอำนาจตามกฎหมาย กฎข้อบังคับเกี่ยวกับการบัญชีและการเก็บภาษี จะต้องอาศัยรายงานเหล่านี้อย่างน้อยครั้งหนึ่งต่อสิบสองเดือน แต่ไม่จำเป็นว่าช่วงเวลาที่รายงานนี้จะต้องตรงกับปีตามปฏิทิน ซึงปีงบประมาณของไทยเริ่มตั้งแต่เดือนตุลาคมถึงเดือนกันยายนของปีถัดไป

ดังนั้นระบบไตรมาสจึงแบ่งออกเป็น

  • ไตรมาสที่ 1 หมายถึงช่วงเดือนตุลาคมถึงธันวาคม
  • ไตรมาสที่ 2 หมายถึงช่วงเดือนมกราคมถึงมีนาคม
  • ไตรมาสที่ 3 หมายถึงช่วงเดือนเมษายนถึงมิถุนายน
  • ไตรมาสที่ 4 หมายถึงช่วงเดือนกรกฎาคมถึงกันยายน

ซึ่งใน MySQL เองก็มีฟังก์ชั่นที่คำนวณหาไตรมาสชื่อ QUARTER อยู่แล้วซึ่งอิงจากปีปฏิทิน

QUARTER(date) : Returns the quarter of the year for date, in the range 1 to 4.

mysql> SELECT QUARTER('2016-10-18');
+-----------------------+
| QUARTER('2016-10-18') |
+-----------------------+
|                     4 | 
+-----------------------+

ผลอิงจากปีปฏิทินก็ตามนั้น ^_^ อ้าวว งั้นเรามาสร้างฟังก์ชั่นหาไตรมาสจากปีงบประมาณกัน

CREATE DEFINER=`root`@`localhost` FUNCTION `THQUARTER`(
    xdate DATETIME,
    th BIT) RETURNS int(11)
DETERMINISTIC
BEGIN
    DECLARE qt INT;
    
    SET qt = QUARTER(xdate) + th;
    
    RETURN IF(qt > 4, qt - 4, qt);
END

-- Test
mysql> SELECT THQUARTER('2016-10-18');
+-----------------------+
| THQUARTER('2016-10-18') |
+-----------------------+
|                     1 | 
+-----------------------+

 

มาลองเรียกใช้งานกัน สมมุติโจทย์ต้องการหารายงานการรับบริการของผู้ป่วยในสถานบริการแยกรายไตรมาส (ครั้ง)

-- Generate dummy data
CREATE TABLE `visit` (
  `visitno` mediumint(8) unsigned NOT NULL auto_increment,
  `visitdate` varchar(255),
  `pid` varchar(255) default NULL,
  `pcucode` varchar(255) default NULL,
  PRIMARY KEY (`visitno`)
) AUTO_INCREMENT=1;

INSERT INTO `visit` (`visitdate`,`pid`,`pcucode`) VALUES ("2017-01-09","5","yellow"),("2017-06-11","9","orange"),("2016-11-28","9","yellow"),("2017-06-02","2","red"),("2017-01-09","10","orange"),("2017-05-03","10","orange"),("2017-07-06","8","red"),("2017-06-25","10","yellow"),("2017-04-19","3","orange"),("2017-06-12","3","yellow");
INSERT INTO `visit` (`visitdate`,`pid`,`pcucode`) VALUES ("2016-11-12","10","orange"),("2017-06-18","5","red"),("2017-05-20","9","yellow"),("2017-04-01","2","red"),("2016-12-31","6","red"),("2017-02-05","8","orange"),("2017-02-19","3","red"),("2017-03-13","5","red"),("2017-03-27","3","yellow"),("2017-06-22","8","yellow");
INSERT INTO `visit` (`visitdate`,`pid`,`pcucode`) VALUES ("2017-01-17","6","red"),("2016-10-15","5","yellow"),("2017-05-30","8","orange"),("2017-04-29","5","red"),("2017-01-02","3","orange"),("2017-09-04","4","red"),("2017-01-09","3","orange"),("2016-12-15","7","yellow"),("2017-01-31","8","orange"),("2016-11-08","6","yellow");
INSERT INTO `visit` (`visitdate`,`pid`,`pcucode`) VALUES ("2017-01-10","5","orange"),("2016-11-20","3","yellow"),("2017-07-09","8","red"),("2017-01-20","8","red"),("2017-05-17","8","red"),("2017-08-05","5","yellow"),("2017-07-19","7","red"),("2017-05-06","10","yellow"),("2017-06-01","6","orange"),("2016-11-06","9","red");
INSERT INTO `visit` (`visitdate`,`pid`,`pcucode`) VALUES ("2017-09-20","5","orange"),("2017-01-28","8","yellow"),("2017-02-20","7","red"),("2016-11-24","5","orange"),("2016-12-27","5","orange"),("2017-05-20","6","yellow"),("2017-07-03","1","red"),("2017-09-09","8","yellow"),("2017-06-04","9","red"),("2017-03-04","9","orange");
INSERT INTO `visit` (`visitdate`,`pid`,`pcucode`) VALUES ("2017-09-12","6","orange"),("2017-07-24","1","yellow"),("2017-02-27","5","red"),("2017-08-21","3","yellow"),("2017-01-26","2","orange"),("2017-05-08","8","orange"),("2016-12-26","2","red"),("2017-06-24","7","red"),("2017-02-20","6","red"),("2017-04-18","10","yellow");
INSERT INTO `visit` (`visitdate`,`pid`,`pcucode`) VALUES ("2017-03-01","6","yellow"),("2017-07-15","1","yellow"),("2016-11-11","4","yellow"),("2017-06-27","10","orange"),("2017-01-02","10","orange"),("2017-05-08","7","orange"),("2017-03-16","2","red"),("2017-02-27","4","orange"),("2017-02-14","4","orange"),("2017-04-23","9","yellow");
INSERT INTO `visit` (`visitdate`,`pid`,`pcucode`) VALUES ("2016-12-02","1","orange"),("2017-04-15","9","yellow"),("2017-01-25","6","yellow"),("2017-05-06","7","yellow"),("2017-07-31","8","orange"),("2017-07-23","4","yellow"),("2017-06-02","7","red"),("2017-02-06","7","yellow"),("2017-02-14","6","red"),("2017-07-27","3","yellow");
INSERT INTO `visit` (`visitdate`,`pid`,`pcucode`) VALUES ("2016-10-21","1","red"),("2017-01-13","5","red"),("2017-06-06","1","red"),("2017-01-16","7","yellow"),("2017-01-29","9","orange"),("2016-11-06","7","red"),("2017-01-06","2","red"),("2017-01-12","6","yellow"),("2017-06-29","5","red"),("2017-04-04","10","yellow");
INSERT INTO `visit` (`visitdate`,`pid`,`pcucode`) VALUES ("2017-03-11","10","red"),("2017-05-22","2","red"),("2017-03-21","2","yellow"),("2017-02-19","3","orange"),("2016-11-30","3","red"),("2017-06-30","2","yellow"),("2017-09-17","2","red"),("2017-04-21","7","orange"),("2017-02-12","1","yellow"),("2017-05-12","7","red");

ผลลัพธ์

mysql> SELECT
    ->     pcucode,
    ->     SUM(IF(THQUARTER(visitdate, 1) = 1, 1, 0)) AS Q1,
    ->     SUM(IF(THQUARTER(visitdate, 1) = 2, 1, 0)) AS Q2,
    ->     SUM(IF(THQUARTER(visitdate, 1) = 3, 1, 0)) AS Q3,
    ->     SUM(IF(THQUARTER(visitdate, 1) = 4, 1, 0)) AS Q4,
    ->     COUNT(visitno) AS Total
    -> FROM visit
    -> GROUP BY pcucode
    -> WITH ROLLUP;
+---------+------+------+------+------+-------+
| pcucode | Q1   | Q2   | Q3   | Q4   | Total |
+---------+------+------+------+------+-------+
| orange  |    4 |   13 |    9 |    3 |    29 |
| red     |    6 |   12 |   12 |    6 |    36 |
| yellow  |    6 |   10 |   12 |    7 |    35 |
| NULL    |   16 |   35 |   33 |   16 |   100 |
+---------+------+------+------+------+-------+
4 rows in set (0.02 sec)

ปั่นรายงานกันต่อ T_T

 

 

Last record in each group

ใน MySQL กรณีเราต้องการหาค่าสูงสุด ตำสุด ในชุดข้อมูลนั้น ๆ จะหาได้จากการใช้ฟังก์ชั่น MIN() ซึ่งจะคืนค่าตำสุดและ MAX() จะคืนค่าสูงสุดในฟิลด์ที่ระบุ เช่น

SELECT MIN(column_name) FROM TABLE_NAME

กรณีที่หาค่าต่ำสุด/สูงสุด แยกตาม กลุ่มใด ๆ ก็ตามเพียงแค่ใช้ GROUP BY ต่อแค่นั้น

จบแล้วเหรอ เด๋วก่อนนนนนน !!! ชีวิตมันไม่ง่ายขนาดนั้น มันจะมีความต้องการอีกกรณีนึงคือ

อยากได้ค่า X ในเรคคอร์ดที่มีค่าสูงสุดในฟิลด์ที่ระบุ (Y) แต่ไม่ใช่ค่า Y นะ แยกตามกลุ่ม Z

ดูตัวอย่างข้อมูลดีกว่า

ค่า X คือ LABRESULT
ค่า Y คือ DATE_SERV
ค่า Z คือ CID

เพราะฉะนั้นผลลัพธ์ที่ได้ควรจะเป็นเช่นนี้ ที่เธอต้องการ

เราสามารถเขียนคำสั่งได้หลายแบบ อาทิ

แบบที่ 1

SELECT * FROM (
    SELECT HOSPCODE,CID,DATE_SERV,LABTEST,LABRESULT FROM demolasteachgroup ORDER BY DATE_SERV DESC
) t1 GROUP BY CID;

แบบที่ 2

SELECT *
FROM demolasteachgroup
WHERE DATE_SERV IN (
    SELECT MAX(DATE_SERV)
    FROM demolasteachgroup
    GROUP BY CID
);

แบบที่ 3

SELECT
    t1.*
FROM demolasteachgroup t1 
    LEFT JOIN demolasteachgroup t2 ON (t1.CID = t2.CID AND t1.DATE_SERV < t2.DATE_SERV)
WHERE t2.CID IS NULL;

ปล 1. จากการทดสอบพบว่า

MySQL Version แบบที่ 1 แบบที่ 2 แบบที่ 3
5.5
5.6
5.7 ×
10.2.2 (MariaDB) ×

√  ผลลัพธ์ถูกต้อง
× ผลลัพธ์ผิด

ปล. 2 ตัดเงื่อนไขเรื่อง Big O นะ มองถึงผลลัพธ์ที่ถูกต้องอย่างเดียว

ปล. 3 มีประเด็นสงสัยจากเพื่อนในวงการ(สุขภาพ) ถามมาที่จับใจความได้ก็ (ถ้ามีเพิ่มเติมก็ discuss กันได้นะครับ ยินดี)
Q : ยกตัวอย่างที่เป็นรูปธรรมเห็นได้หน่อยที่บอกว่าความต้องการอีกกรณีนึง
A : เช่น ต้องการหาค่าน้ำตาลล่าสุดxxของผู้ป่วยหรือผลแลป HbA1C ล่าสุดของผู้ป่วย เป็นต้น กรณีหากได้ค่าที่ผิดพลาดออกมามีผลอย่างมาก เพราะ 2 รายการข้างต้นเป็นหนึ่งในเงื่อนไขที่บอกถึงการควบคุมน้ำตาลได้ดีของผู้ป่วย ซึ่งอยู่ใน KPI ทุก ๆ ปีของคนทำงานด้านสุขภาพ (คนไทยเป็นเบาหวานเยอะมากนะ อันนี้เป็นเรื่องน่ากังวลเหมือนกัน) KPI เกือบผ่านหรือเกือบไม่ผ่านความรุนแรงในการตำหนิต่างกันเยอะ ^_^

Q : ทดสอบกับ MySQL คนละ Version ให้ผลไม่เหมือนกัน อะไร ยังไง
A : ที่ให้ผลลัพธ์ไม่ถูกต้องนั้น เฉพาะแบบที่ 1 นะ ตามปล. 1 คือตัวนี้

SELECT * FROM (
    SELECT HOSPCODE,CID,DATE_SERV,LABTEST,LABRESULT FROM demolasteachgroup ORDER BY DATE_SERV DESC
) t1 GROUP BY CID;

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

แต่ผลลัพธ์จะผิดทันทีถ้าใช้ MySQL Version 5.7 เป็นต้นไป (ปัจจุบันเวอร์ชั่น 5.7.17)

** ไม่ได้หาสาเหตุนะว่าผิดเพราะอะไร ใครจะลองไปทดสอบเวอร์ชั่นอื่น ๆ คำสั่งที่ใช้ทดสอบก็ตามนี้
MySQL 5.5 – http://sqlfiddle.com/#!2/38ef1b/2
MySQL 5.6 – http://sqlfiddle.com/#!9/38ef1b/4
MySQL 5.7 – http://rextester.com/JALDD35756