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 ก็ติดตั้งได้เลยตามนี้
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    sudo apt install pcscd pcsc-tools
    sudo apt install pcscd pcsc-tools
    sudo apt install pcscd pcsc-tools
  3. ตรวจสอบอีกทีว่าติดต่อ Smart Card ได้แล้ว ด้วย 
    pcsc_scan
    pcsc_scan


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

  4. ขั้นตอนต่อไปก็รัน Smart Card Agent ได้เลย (ข้ามเรื่องติดตั้ง JRE ไปเลยนะ ถ้าไม่มีก็ติดตั้งซะ)
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    java -Dsun.security.smartcardio.library=/lib/x86_64-linux-gnu/libpcsclite.so.1 -jar javadaemon.jar 8080
    java -Dsun.security.smartcardio.library=/lib/x86_64-linux-gnu/libpcsclite.so.1 -jar javadaemon.jar 8080
    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 ตามนี้

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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 ;
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 ;
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 = ไม่)

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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');
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');
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.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
mysql> SELECT QUARTER('2016-10-18');
+-----------------------+
| QUARTER('2016-10-18') |
+-----------------------+
| 4 |
+-----------------------+
mysql> SELECT QUARTER('2016-10-18'); +-----------------------+ | QUARTER('2016-10-18') | +-----------------------+ | 4 | +-----------------------+
mysql> SELECT QUARTER('2016-10-18');
+-----------------------+
| QUARTER('2016-10-18') |
+-----------------------+
|                     4 | 
+-----------------------+

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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 |
+-----------------------+
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 | +-----------------------+
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 | 
+-----------------------+

 

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
-- 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");
-- 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");
-- 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");

ผลลัพธ์

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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)
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)
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() จะคืนค่าสูงสุดในฟิลด์ที่ระบุ เช่น

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SELECT MIN(column_name) FROM TABLE_NAME
SELECT MIN(column_name) FROM TABLE_NAME
SELECT MIN(column_name) FROM TABLE_NAME

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

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

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

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

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

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

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

แบบที่ 1

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SELECT * FROM (
SELECT HOSPCODE,CID,DATE_SERV,LABTEST,LABRESULT FROM demolasteachgroup ORDER BY DATE_SERV DESC
) t1 GROUP BY CID;
SELECT * FROM ( SELECT HOSPCODE,CID,DATE_SERV,LABTEST,LABRESULT FROM demolasteachgroup ORDER BY DATE_SERV DESC ) t1 GROUP BY CID;
SELECT * FROM (
    SELECT HOSPCODE,CID,DATE_SERV,LABTEST,LABRESULT FROM demolasteachgroup ORDER BY DATE_SERV DESC
) t1 GROUP BY CID;

แบบที่ 2

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SELECT *
FROM demolasteachgroup
WHERE DATE_SERV IN (
SELECT MAX(DATE_SERV)
FROM demolasteachgroup
GROUP BY CID
);
SELECT * FROM demolasteachgroup WHERE DATE_SERV IN ( SELECT MAX(DATE_SERV) FROM demolasteachgroup GROUP BY CID );
SELECT *
FROM demolasteachgroup
WHERE DATE_SERV IN (
    SELECT MAX(DATE_SERV)
    FROM demolasteachgroup
    GROUP BY CID
);

แบบที่ 3

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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;
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;
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 คือตัวนี้

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
SELECT * FROM (
SELECT HOSPCODE,CID,DATE_SERV,LABTEST,LABRESULT FROM demolasteachgroup ORDER BY DATE_SERV DESC
) t1 GROUP BY CID;
SELECT * FROM ( SELECT HOSPCODE,CID,DATE_SERV,LABTEST,LABRESULT FROM demolasteachgroup ORDER BY DATE_SERV DESC ) t1 GROUP BY CID;
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

MySQL (Simple)Mask Function

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

** ส่วนตัวแล้วไม่แนะนำให้ใช้ (แล้วเขียนขึ้นมาทำไมฟระ 5555) คือถ้าจะใช้ก็มีให้ใช้ได้แต่ไม่แนะนำไง เป็นภาระการประมวลผลโดยใช่เหตุ ปล่อยให้เป็นหน้าที่ของฟรอนท์ไปหล่ะกัน
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
DELIMITER $$
DROP FUNCTION IF EXISTS SIMPLEMASK$$
CREATE FUNCTION SIMPLEMASK (
xvalue VARCHAR(32),
xformat VARCHAR(32)
)
RETURNS CHAR(32)
DETERMINISTIC
BEGIN
DECLARE input_len TINYINT;
DECLARE tc CHAR;
DECLARE idx TINYINT;
DECLARE yformat VARCHAR(32);
DECLARE posinsert TINYINT;
DECLARE newstring VARCHAR(32);
# Initialize variables
SET yformat = REPLACE(xformat, '#', '');
SET input_len = LENGTH(yformat);
SET idx = 1;
SET posinsert = 0;
# Construct formated string
WHILE ( idx <= input_len ) DO
SET tc = SUBSTR(yformat, idx, 1);
SET posinsert = LOCATE(tc, xformat, (idx + posinsert));
SET newstring = CONCAT(tc, SUBSTR(xvalue, posinsert, 1));
SET xvalue = INSERT(xvalue, posinsert, 1, newstring);
SET idx = idx + 1;
END WHILE;
RETURN xvalue;
END $$
DELIMITER ;
-- Test
SELECT SIMPLEMASK(1234567890123,'#-####-#####-##-#'); -- CID/1-2345-67890-12-3
DELIMITER $$ DROP FUNCTION IF EXISTS SIMPLEMASK$$ CREATE FUNCTION SIMPLEMASK ( xvalue VARCHAR(32), xformat VARCHAR(32) ) RETURNS CHAR(32) DETERMINISTIC BEGIN DECLARE input_len TINYINT; DECLARE tc CHAR; DECLARE idx TINYINT; DECLARE yformat VARCHAR(32); DECLARE posinsert TINYINT; DECLARE newstring VARCHAR(32); # Initialize variables SET yformat = REPLACE(xformat, '#', ''); SET input_len = LENGTH(yformat); SET idx = 1; SET posinsert = 0; # Construct formated string WHILE ( idx <= input_len ) DO SET tc = SUBSTR(yformat, idx, 1); SET posinsert = LOCATE(tc, xformat, (idx + posinsert)); SET newstring = CONCAT(tc, SUBSTR(xvalue, posinsert, 1)); SET xvalue = INSERT(xvalue, posinsert, 1, newstring); SET idx = idx + 1; END WHILE; RETURN xvalue; END $$ DELIMITER ; -- Test SELECT SIMPLEMASK(1234567890123,'#-####-#####-##-#'); -- CID/1-2345-67890-12-3
DELIMITER $$
DROP FUNCTION IF EXISTS SIMPLEMASK$$

CREATE FUNCTION SIMPLEMASK (
    xvalue VARCHAR(32), 
    xformat VARCHAR(32)
)
RETURNS CHAR(32) 
DETERMINISTIC
BEGIN

    DECLARE input_len TINYINT;
    DECLARE tc CHAR;
    DECLARE idx TINYINT;
    DECLARE yformat VARCHAR(32);
    DECLARE posinsert TINYINT;
    DECLARE newstring VARCHAR(32);
    
    # Initialize variables
    SET yformat = REPLACE(xformat, '#', '');
    SET input_len = LENGTH(yformat);
    SET idx = 1;
    SET posinsert = 0;
    
    # Construct formated string
    WHILE ( idx <= input_len ) DO
        SET tc = SUBSTR(yformat, idx, 1);
        SET posinsert = LOCATE(tc, xformat, (idx + posinsert));
        SET newstring = CONCAT(tc, SUBSTR(xvalue, posinsert, 1));
        SET xvalue = INSERT(xvalue, posinsert, 1, newstring);
        SET idx = idx + 1;
    END WHILE;
    
    RETURN xvalue;
    
END $$

DELIMITER ;

-- Test
SELECT SIMPLEMASK(1234567890123,'#-####-#####-##-#'); -- CID/1-2345-67890-12-3

ป.ล.

อ้ายผิดเอง ทีดูแลเจ้าบ่ดี…

 

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
กู่แคน School - เจ็บเติบนึง
คำร้อง/ ทำนอง ก้องศิลป์ ฟ้าล่วงบน
เรียบเรียบ กู่แคน School
อ้ายผิดเอง ทีดูแลเจ้าบ่ดี
ฮักเฮาบัดนี้ถึงที่อวสาน
ปานนั้นบ้อหัวใจเอ๋ย ใจที่เคยให้ความหวัง
มันคงบ่ยังแล้ว มันคงบ่เหลือแล้ว
เบิ๊ดคักเบิ๊ดแน่ เบิ๊ดจนบ่มี
กะพาหัวใจ ที่ฮักเจ้าไปกับความหวัง
อ้ายกะไปฮอดฝั่งแต่มันช้าเกินไป
ถามว่ามาหยังตอนนี้
คนดีเอ๊ย ข่อยหนิฮักเจ้าหลาย
มาแสดงความฮักเป็นเทื่อสุดท้าย
ก่อนสิกายเป็นแค่ ควมเก่า
อ้ายคงต้องเศร้า ต้องเหงาหลาย
กะคงซำตาย ทั้งเป็น ที่เจ้าบอกว่าบ่ได้ฮักกัน
มันจบลงแล้วหนอความสัมพันธ์
หัวใจมันกลั้น น้ำตาสิไหล
ใจเอ๋ยพออยากแลนไปกอด
ฮักเจ้าตลอด บ่อยากเสียเจ้าไป
สุดท้ายสองเฮากะคงต้องน้ำตาไหล
ฮ้องไห้ใส่กัน
ถามว่ามาหยังตอนนี้
คนดีเอ๊ย ข่อยหนิฮักเจ้าหลาย
มาแสดงความฮักเป็นเทื่อสุดท้าย
ก่อนสิกายเป็นแค่ ควมเก่า
อ้ายคงต้องเศร้า ต้องเหงาหลาย
กะคงซำตาย ทั้งเป็น ที่เจ้าบอกว่าบ่ได้ฮักกัน
มันจบลงแล้วหนอความสัมพันธ์
หัวใจมันกลั้น น้ำตาสิไหล
ใจเอ๋ยพออยากแลนไปกอด
ฮักเจ้าตลอด บ่อยากเสียเจ้าไป
สุดท้ายสองเฮากะคงต้องน้ำตาไหล
ฮ้องไห้ใส่กันก่อนเฮาสิจากหนี
สุดท้ายสองเฮากะคงต้องน้ำตาไหล
ฮ้องไห้ใส่กัน
กู่แคน School - เจ็บเติบนึง คำร้อง/ ทำนอง ก้องศิลป์ ฟ้าล่วงบน เรียบเรียบ กู่แคน School อ้ายผิดเอง ทีดูแลเจ้าบ่ดี ฮักเฮาบัดนี้ถึงที่อวสาน ปานนั้นบ้อหัวใจเอ๋ย ใจที่เคยให้ความหวัง มันคงบ่ยังแล้ว มันคงบ่เหลือแล้ว เบิ๊ดคักเบิ๊ดแน่ เบิ๊ดจนบ่มี กะพาหัวใจ ที่ฮักเจ้าไปกับความหวัง อ้ายกะไปฮอดฝั่งแต่มันช้าเกินไป ถามว่ามาหยังตอนนี้ คนดีเอ๊ย ข่อยหนิฮักเจ้าหลาย มาแสดงความฮักเป็นเทื่อสุดท้าย ก่อนสิกายเป็นแค่ ควมเก่า อ้ายคงต้องเศร้า ต้องเหงาหลาย กะคงซำตาย ทั้งเป็น ที่เจ้าบอกว่าบ่ได้ฮักกัน มันจบลงแล้วหนอความสัมพันธ์ หัวใจมันกลั้น น้ำตาสิไหล ใจเอ๋ยพออยากแลนไปกอด ฮักเจ้าตลอด บ่อยากเสียเจ้าไป สุดท้ายสองเฮากะคงต้องน้ำตาไหล ฮ้องไห้ใส่กัน ถามว่ามาหยังตอนนี้ คนดีเอ๊ย ข่อยหนิฮักเจ้าหลาย มาแสดงความฮักเป็นเทื่อสุดท้าย ก่อนสิกายเป็นแค่ ควมเก่า อ้ายคงต้องเศร้า ต้องเหงาหลาย กะคงซำตาย ทั้งเป็น ที่เจ้าบอกว่าบ่ได้ฮักกัน มันจบลงแล้วหนอความสัมพันธ์ หัวใจมันกลั้น น้ำตาสิไหล ใจเอ๋ยพออยากแลนไปกอด ฮักเจ้าตลอด บ่อยากเสียเจ้าไป สุดท้ายสองเฮากะคงต้องน้ำตาไหล ฮ้องไห้ใส่กันก่อนเฮาสิจากหนี สุดท้ายสองเฮากะคงต้องน้ำตาไหล ฮ้องไห้ใส่กัน
กู่แคน School - เจ็บเติบนึง
คำร้อง/ ทำนอง ก้องศิลป์ ฟ้าล่วงบน
เรียบเรียบ กู่แคน School

อ้ายผิดเอง ทีดูแลเจ้าบ่ดี
ฮักเฮาบัดนี้ถึงที่อวสาน
ปานนั้นบ้อหัวใจเอ๋ย ใจที่เคยให้ความหวัง
มันคงบ่ยังแล้ว มันคงบ่เหลือแล้ว
เบิ๊ดคักเบิ๊ดแน่ เบิ๊ดจนบ่มี

กะพาหัวใจ ที่ฮักเจ้าไปกับความหวัง
อ้ายกะไปฮอดฝั่งแต่มันช้าเกินไป
ถามว่ามาหยังตอนนี้
คนดีเอ๊ย ข่อยหนิฮักเจ้าหลาย
มาแสดงความฮักเป็นเทื่อสุดท้าย
ก่อนสิกายเป็นแค่ ควมเก่า
อ้ายคงต้องเศร้า ต้องเหงาหลาย

กะคงซำตาย ทั้งเป็น ที่เจ้าบอกว่าบ่ได้ฮักกัน
มันจบลงแล้วหนอความสัมพันธ์
หัวใจมันกลั้น น้ำตาสิไหล
ใจเอ๋ยพออยากแลนไปกอด
ฮักเจ้าตลอด บ่อยากเสียเจ้าไป
สุดท้ายสองเฮากะคงต้องน้ำตาไหล
ฮ้องไห้ใส่กัน

ถามว่ามาหยังตอนนี้
คนดีเอ๊ย ข่อยหนิฮักเจ้าหลาย
มาแสดงความฮักเป็นเทื่อสุดท้าย
ก่อนสิกายเป็นแค่ ควมเก่า
อ้ายคงต้องเศร้า ต้องเหงาหลาย

กะคงซำตาย ทั้งเป็น ที่เจ้าบอกว่าบ่ได้ฮักกัน
มันจบลงแล้วหนอความสัมพันธ์
หัวใจมันกลั้น น้ำตาสิไหล
ใจเอ๋ยพออยากแลนไปกอด
ฮักเจ้าตลอด บ่อยากเสียเจ้าไป
สุดท้ายสองเฮากะคงต้องน้ำตาไหล
ฮ้องไห้ใส่กันก่อนเฮาสิจากหนี

สุดท้ายสองเฮากะคงต้องน้ำตาไหล
ฮ้องไห้ใส่กัน

 

Watermark images with file name

เช้าวันนี้ (2 พฤศจิกายน 2559) มาพร้อมกับงานด่วน
– Watermark ไฟล์รูปด้วยชื่อไฟล์ (ต้นฉบับมาแบบนี้ -*-)
– ไฟล์รูปมีคร่าว ๆ ก็เกือบ 100 รูป ความขี้เกียจเข้าครอบงำโดยพลัน
selection_030

selection_031

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/bin/bash
#
# NAME: WatermarkFilename
# AUTHOR: MF
# A script to add a watermark and overwrite all images in a directory.
savedir=".originals"
mkdir -p $savedir
for image in *png *jpg *jpeg *gif
do
if [ -s $image ] ; then # non-zero file size
width=$(identify -format %w $image)
filename=$(basename "$image")
fname="${filename%.*}"
ext="${filename##*.}"
fullpath="$(dirname $(readlink -f "${image}"))/${image##*/}"
convert -background '#cccccc' \
-fill white -gravity center \
-font loma -pointsize 30 -size ${width}x60 caption:$fname \
$image +swap -gravity south -composite new-$image
mv $image $savedir
mv new-$image $image
echo "Watermarked $image successfully"
fi
done
#!/bin/bash # # NAME: WatermarkFilename # AUTHOR: MF # A script to add a watermark and overwrite all images in a directory. savedir=".originals" mkdir -p $savedir for image in *png *jpg *jpeg *gif do if [ -s $image ] ; then # non-zero file size width=$(identify -format %w $image) filename=$(basename "$image") fname="${filename%.*}" ext="${filename##*.}" fullpath="$(dirname $(readlink -f "${image}"))/${image##*/}" convert -background '#cccccc' \ -fill white -gravity center \ -font loma -pointsize 30 -size ${width}x60 caption:$fname \ $image +swap -gravity south -composite new-$image mv $image $savedir mv new-$image $image echo "Watermarked $image successfully" fi done
#!/bin/bash
#
# NAME:		WatermarkFilename	
# AUTHOR:	MF
# A script to add a watermark and overwrite all images in a directory.


savedir=".originals"
mkdir -p $savedir

for image in *png *jpg *jpeg *gif
do
	if [ -s $image ] ; then   # non-zero file size

		width=$(identify -format %w $image)
		filename=$(basename "$image")
		fname="${filename%.*}"
		ext="${filename##*.}"
		fullpath="$(dirname $(readlink -f "${image}"))/${image##*/}"

		convert -background '#cccccc' \
		-fill white -gravity center \
		-font loma -pointsize 30 -size ${width}x60 caption:$fname \
		$image +swap -gravity south -composite new-$image
		mv $image $savedir
		mv new-$image $image
		echo "Watermarked $image successfully"		
	fi
done

ป.ล.
– เสียเวลาไปกับการตรวจสอบข้อมูลให้ตรงกับชื่อไฟล์ซะมากกว่า
– ไฟล์ตัวอย่างจาก https://unsplash.com/
– ใช้แพคเกจ imagemagick

Find and log which top 5 processes are taking high cpu

เวลาคอมพิวเตอร์ตระกูล *nix พบปัญหา อันดับแรก ๆ ที่จะเริ่มทำเพื่อแก้ปัญหาและช่วยชีวิตเราก็คือเปิด Log เกิดปัญหาปุ๊บเปิด Log ก่อนเลยแต่บางกรณีเราก็มอนิเตอร์ผ่านโปรแกรม/คำสั่งตัวอื่น โดยทั่ว ๆ ไปมักจะใช้ top เพื่อมอนิเตอร์การทำงานของคอมพิวเตอร์ ซึงโปรแกรมจะแสดงสถานะของ Memory, CPU, Process Terminal_042

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

ps – report a snapshot of the current processes.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
a@b  ~  ps -aux  1 ↵  48111:31:05
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 185556 6264 ? Ss 09:55 0:02 /sbin/init spla
root 2 0.0 0.0 0 0 ? S 09:55 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 09:55 0:00 [ksoftirqd/0]
root 5 0.0 0.0 0 0 ? S< 09:55 0:00 [kworker/0:0H]
root 7 0.0 0.0 0 0 ? S 09:55 0:05 [rcu_sched]
root 8 0.0 0.0 0 0 ? S 09:55 0:00 [rcu_bh]
root 9 0.0 0.0 0 0 ? S 09:55 0:00 [migration/0]
root 10 0.0 0.0 0 0 ? S 09:55 0:00 [watchdog/0]
root 11 0.0 0.0 0 0 ? S 09:55 0:00 [watchdog/1]
a@b  ~  ps -aux  1 ↵  481  11:31:05 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 185556 6264 ? Ss 09:55 0:02 /sbin/init spla root 2 0.0 0.0 0 0 ? S 09:55 0:00 [kthreadd] root 3 0.0 0.0 0 0 ? S 09:55 0:00 [ksoftirqd/0] root 5 0.0 0.0 0 0 ? S< 09:55 0:00 [kworker/0:0H] root 7 0.0 0.0 0 0 ? S 09:55 0:05 [rcu_sched] root 8 0.0 0.0 0 0 ? S 09:55 0:00 [rcu_bh] root 9 0.0 0.0 0 0 ? S 09:55 0:00 [migration/0] root 10 0.0 0.0 0 0 ? S 09:55 0:00 [watchdog/0] root 11 0.0 0.0 0 0 ? S 09:55 0:00 [watchdog/1]
 a@b  ~  ps -aux                                    1 ↵  481  11:31:05 
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0 185556  6264 ?        Ss   09:55   0:02 /sbin/init spla
root         2  0.0  0.0      0     0 ?        S    09:55   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        S    09:55   0:00 [ksoftirqd/0]
root         5  0.0  0.0      0     0 ?        S<   09:55   0:00 [kworker/0:0H]
root         7  0.0  0.0      0     0 ?        S    09:55   0:05 [rcu_sched]
root         8  0.0  0.0      0     0 ?        S    09:55   0:00 [rcu_bh]
root         9  0.0  0.0      0     0 ?        S    09:55   0:00 [migration/0]
root        10  0.0  0.0      0     0 ?        S    09:55   0:00 [watchdog/0]
root        11  0.0  0.0      0     0 ?        S    09:55   0:00 [watchdog/1]

ps ใช้แล้วก็จบไง จะดูอีกก็สั่งอีก (ใช้ watch ดูแบบ top ก็ได้นะ แต่จะใช้ watch ก็ไปใช้ top ละเอียดกว่าเยอะ) แต่ในกรณีที่ต้องการเก็บ Log ผลลัพธ์ที่ได้จาก ps เพื่อดูการทำงาน เช่นอาจจะต้องการมอนิเตอร์โปรเสสที่ใช้งานสูง ๆ หรือมอนิเตอร์ดูภายหลังว่าใครกำลังแอบแดกเมมมหาโหด ก็ทำแบบนี้ได้

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
while true; do
ps auxf | sort -nrk 3,3 | head -n 5 >> log.log;
sleep 1;
done
while true; do ps auxf | sort -nrk 3,3 | head -n 5 >> log.log; sleep 1; done
while true; do 
    ps auxf | sort -nrk 3,3 | head -n 5 >> log.log; 
    sleep 1; 
done

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
a@b  ~  tail -f log.log  ✓  48811:40:13
a 6019 28.6 4.0 2189732 663568 tty2 Sl+ 09:57 28:48 /usr/lib/firefox/firefox
a 4376 4.7 1.2 2334564 198912 tty2 Sl+ 09:57 4:49 \_ /usr/bin/gnome-shell
root 4222 2.7 0.4 534160 79804 tty2 Sl+ 09:57 2:43 \_ /usr/lib/xorg/Xorg vt2 -displayfd 3 -auth /run/user/1000/gdm/Xauthority -background none -noreset -keeptty -verbose 3
a@b  ~  tail -f log.log  ✓  488  11:40:13 a 6019 28.6 4.0 2189732 663568 tty2 Sl+ 09:57 28:48 /usr/lib/firefox/firefox a 4376 4.7 1.2 2334564 198912 tty2 Sl+ 09:57 4:49 \_ /usr/bin/gnome-shell root 4222 2.7 0.4 534160 79804 tty2 Sl+ 09:57 2:43 \_ /usr/lib/xorg/Xorg vt2 -displayfd 3 -auth /run/user/1000/gdm/Xauthority -background none -noreset -keeptty -verbose 3
a@b  ~  tail -f log.log                              ✓  488  11:40:13 
a        6019 28.6  4.0 2189732 663568 tty2   Sl+  09:57  28:48 /usr/lib/firefox/firefox
a        4376  4.7  1.2 2334564 198912 tty2   Sl+  09:57   4:49              \_ /usr/bin/gnome-shell
root      4222  2.7  0.4 534160 79804 tty2     Sl+  09:57   2:43          \_ /usr/lib/xorg/Xorg vt2 -displayfd 3 -auth /run/user/1000/gdm/Xauthority -background none -noreset -keeptty -verbose 3

 

 

Dirty Lab : Import many delimited files into MySQL

ดูโค๊ดเอาหล่ะกันเน๊อะ มีความขี้เกียจตั้งแต่เห็นจำนวนไฟล์ละ (คือแบบเยอะมากกกกกกก) แต่จำเป็นต้องใช้ก็เลยเกิดแลปแบบด่วน ๆ
– ใช้โครงสร้างของ HDC
– ไฟล์ที่นำเข้าอยู่ในรูปแบบของโครงสร้างมาตรฐานข้อมูลด้านสุขภาพ กระทรวงสาธารณสุข (43 แฟ้ม)
– ปล้ำ Servlet ของ HDC โดยไม่ติดตั้งระบบนี่ดูยาก ๆ อ่ะ รอปรึกษา Phoubon Ict
– อันนี้ช่วงรอไฟล์นำเข้า

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/bin/sh
#Import delimited file to database;
IMPORTEDFOLDER="imported"
fileCount=0
fileName=""
filePath=""
mkdir -p "../${IMPORTEDFOLDER}"
for zip in *.zip; do
zip_filename="${zip%%.*}"
unzip "${zip}" -d "${zip_filename}"
mv -f "${zip}" "../${IMPORTEDFOLDER}"
for file in $(find ./ -name '*.txt' -or -name '*.TXT'); do
fileName=${file##*/}
fileName=${fileName%.txt}
filePath="$(dirname $(readlink -f "${file}"))/${file##*/}"
#TODO: Extend to GNU Parallel
sh importdelimited.sh "${filePath}" "${fileName}"
fileCount=$((fileCount+1))
done
#rm -rf "${zip_filename}"
done
echo "${fileCount} files completed."
#!/bin/sh #Import delimited file to database; IMPORTEDFOLDER="imported" fileCount=0 fileName="" filePath="" mkdir -p "../${IMPORTEDFOLDER}" for zip in *.zip; do zip_filename="${zip%%.*}" unzip "${zip}" -d "${zip_filename}" mv -f "${zip}" "../${IMPORTEDFOLDER}" for file in $(find ./ -name '*.txt' -or -name '*.TXT'); do fileName=${file##*/} fileName=${fileName%.txt} filePath="$(dirname $(readlink -f "${file}"))/${file##*/}" #TODO: Extend to GNU Parallel sh importdelimited.sh "${filePath}" "${fileName}" fileCount=$((fileCount+1)) done #rm -rf "${zip_filename}" done echo "${fileCount} files completed."
#!/bin/sh
#Import delimited file to database;

IMPORTEDFOLDER="imported"

fileCount=0
fileName=""
filePath=""

mkdir -p "../${IMPORTEDFOLDER}"

for zip in *.zip; do
    zip_filename="${zip%%.*}"
    unzip "${zip}" -d "${zip_filename}"
    mv -f "${zip}" "../${IMPORTEDFOLDER}"
    
    for file in $(find ./ -name '*.txt' -or -name '*.TXT'); do
        fileName=${file##*/}
        fileName=${fileName%.txt}
        filePath="$(dirname $(readlink -f "${file}"))/${file##*/}"
        
        #TODO: Extend to GNU Parallel
        sh importdelimited.sh "${filePath}" "${fileName}" 
        
        fileCount=$((fileCount+1))
    done
    
    #rm -rf "${zip_filename}"
    
done

echo "${fileCount} files completed."

สคริปสำหรับนำเข้าฐานข้อมูลของ MySQL

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#!/bin/sh
#Import delimited file to database;
#Usage : sh importdelimited.sh {Source} {Target}
LOGFILE="importlog.log"
DB="hdc"
USERDB="a1a1a1"
PASSDB="b1b1b1"
SQL=""
SQL="SET SESSION sql_mode=''; LOAD DATA LOCAL INFILE '$1' REPLACE INTO TABLE $2 FIELDS TERMINATED BY '|' LINES TERMINATED BY '\r\n' IGNORE 1 LINES;"
echo "$(date -u) $2:${SQL}" >> "../${LOGFILE}" 2>&1
mysql -u${USERDB} -p${PASSDB} ${DB} -e "${SQL}"
rm -f $1
#!/bin/sh #Import delimited file to database; #Usage : sh importdelimited.sh {Source} {Target} LOGFILE="importlog.log" DB="hdc" USERDB="a1a1a1" PASSDB="b1b1b1" SQL="" SQL="SET SESSION sql_mode=''; LOAD DATA LOCAL INFILE '$1' REPLACE INTO TABLE $2 FIELDS TERMINATED BY '|' LINES TERMINATED BY '\r\n' IGNORE 1 LINES;" echo "$(date -u) $2:${SQL}" >> "../${LOGFILE}" 2>&1 mysql -u${USERDB} -p${PASSDB} ${DB} -e "${SQL}" rm -f $1
#!/bin/sh
#Import delimited file to database;
#Usage : sh importdelimited.sh {Source} {Target}

LOGFILE="importlog.log"
DB="hdc"
USERDB="a1a1a1"
PASSDB="b1b1b1"
SQL=""

SQL="SET SESSION sql_mode=''; LOAD DATA LOCAL INFILE '$1' REPLACE INTO TABLE $2 FIELDS TERMINATED BY '|' LINES TERMINATED BY '\r\n' IGNORE 1 LINES;"
echo "$(date -u) $2:${SQL}" >> "../${LOGFILE}" 2>&1
mysql -u${USERDB} -p${PASSDB} ${DB} -e "${SQL}"
rm -f $1

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