Mine

รูปภาพของฉัน
หาดใหญ่, ภาคใต้, Thailand
ชอบเอาใจ แต่ก็เอาแต่ใจ

วันจันทร์ที่ 6 กันยายน พ.ศ. 2553

โรคเรื้อรังครั้งแรกหรือไม่ ....

ไหนๆก็ไหนๆ แล้วนำมาฝากกันเพิ่มเติมอีกนิดค่ะ เพราะว่าลืมนึกถึงไปว่าโรคเดียวกันแต่มีหลาย ICD10 ดังนั้น รอบก่อนที่เขียนตาม ICD10 น่ะ ไม่ค่อยเป็นประโชย์มากนัก


รอบนี้เลยขอแก้ตัวใหม่ค่ะ ดูตามโรคกันไป แต่ในที่นี้ขอยกโรคเรื้อรัง ละกันนะคะ เพราะฐานข้อมูล Hospital OS จัดเก็บ โรคเรื้อรังไว้ค่ะ เราสามารถทราบได้ว่า ICD10 ไหนเป็นโรคเรื่อรังอะไรจากข้อมูลตรงนี้ค่ะ

เอาคำสั่งนี้ไปรัน นะคะ (รันครั้งเดียวก็พอ) 

 CREATE OR REPLACE FUNCTION check_new_disease(varchar, varchar, varchar, varchar,varchar) RETURNS bool AS
'
declare
    patient_id varchar;
    visit_id varchar;
    visit_icd10 varchar;   
    visit_datetime varchar;
    disease varchar;
    newvisit boolean;
    check_visit record;
begin
    patient_id = $1;
    visit_id = $2;
    visit_icd10 = $3;
    visit_datetime = $4;
    disease = $5; 
    newvisit = true;
  
    if (patient_id <> '''' and visit_id <> '''' and visit_icd10 <> '''' and disease <> '''' and visit_datetime <> '''')
    then  
            for check_visit in (select t_visit.t_visit_id as t_visit_id
                                        from t_visit inner join t_diag_icd10
                                                on t_visit.t_visit_id = t_diag_icd10.diag_icd10_vn and t_diag_icd10.diag_icd10_active = ''1''
                                                inner join b_group_icd10
                                                on upper(substring(b_group_icd10.group_icd10_number,1,3)) = upper(substring(t_diag_icd10.diag_icd10_number,1,3))
                                                 inner join b_group_chronic
                                                on b_group_icd10.b_group_chronic_id = b_group_chronic.b_group_chronic_id
                                        where t_visit.t_visit_id <> visit_id
                                                and t_visit.t_patient_id = patient_id
                                                and b_group_chronic.b_group_chronic_id = disease
                                                and t_visit.f_visit_status_id <> ''4''
                                                and substring(t_visit.visit_financial_discharge_time,1,10) < substring(visit_datetime,1,10))        
            loop
                if check_visit.t_visit_id is not null
                then newvisit = false;
                else
                --กรณี Join กันไม่สำเร็จ
                end if;
            end loop;
    else      newvisit = true;       
    end if;
    return newvisit;
end;
'
LANGUAGE 'plpgsql';

ตัวอย่างการนำไปใช้ ดังนี้ค่ะ
SELECT t_visit.t_visit_id
,t_visit.t_patient_id
,t_diag_icd10.diag_icd10_number
,b_group_chronic.b_group_chronic_id
,b_group_chronic.group_chronic_number
,b_group_chronic.group_chronic_description_th
--เรียกใช้ตรงนี้
,check_new_disease(t_visit.t_patient_id,t_visit.t_visit_id,t_diag_icd10.diag_icd10_number,t_visit.visit_financial_discharge_time,b_group_chronic.b_group_chronic_id)
FROM t_visit inner join t_diag_icd10
on t_visit.t_visit_id = t_diag_icd10.diag_icd10_vn and t_diag_icd10.diag_icd10_active = '1'
inner join b_group_icd10
on upper(substring(b_group_icd10.group_icd10_number,1,3)) = upper(substring(t_diag_icd10.diag_icd10_number,1,3))
inner join b_group_chronic
on b_group_icd10.b_group_chronic_id = b_group_chronic.b_group_chronic_id
where t_visit.f_visit_status_id <> '4'
and substring(t_visit.visit_financial_discharge_time,1,10) = '2553-04-01';


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

วันเสาร์ที่ 4 กันยายน พ.ศ. 2553

อยากทราบมั้ยว่าผู้ที่มารับบริการและได้รับการวินิจฉัยนั้นเป็นครั้งแรกในปีหรือไม่

สวัสดีค่ะ ไหนๆวันนี้เราก็ได้ Function ไป 1 แล้ว เอาเพิ่มไปอีกอันแล้วกันค่ะ เป็นเรื่องของการหารายใหม่ในปีของโรคนั้นๆ ...

ก่อนอื่นมาทำความเข้าใจกับคำว่ารายใหม่กันก่อนนะคะ สำหรับรายใหม่ที่จริงก็ขึ้นอยู่กับว่ารายงานเราต้องการอะไรมากกว่า
1.ต้องการรายใหม่ในปีงบประมาณ
นั่นคือ ผู้มารับบริการรายนั้น มารับบริการครั้งแรกในปีงบประมาณ  (เช่น ปีงบประมาณ 2553 เริ่มจาก ตุลาคม 2552 - กันยายน 2553)
2.ต้องการรายใหม่ในปีปฏิทิน
นั่นคือ ผู้มารับบริการรายนั้น มารับบริการครั้งแรกในปีปฏิทิน  (เช่น ปี 2553 เริ่มจาก มกราคม 2553 - ธันวาคม 2553)

จาก 2 ข้อข้างต้นที่กล่าวมานั้นเป็นการหาผู้ที่มารับบริการรายใหม่ในปี แต่ที่จะกล่าวถึงต่อไปนี้เป็นการหารายใหม่ในปีของโรคนั้นๆ หมายความว่า เราต้องการทราบว่า ผู้ที่มารับบริการและได้รับการวินิจฉัยนั้นเป็นครั้งแรกหรือไม่ (ปีปฏิทินนะคะ)

ซึ่งเราก็สามารถเอาความรู้เรื่อง Function มาช่วยเขียนเพื่อลดความซับซ้อนลงได้ค่ะ

Function check_newvisit_icd เป็น Function สำหรับตรวจสอบว่า นั้นเป็นรายใหม่ในปีของโรคนั้นหรือไม่ โดยผลที่ส่งออกมาจะ เป็นค่า
true = รายใหม่  
false = รายเก่า

เอาคำสั่งนี้ไปรัน นะคะ (รันครั้งเดียวก็พอ)

CREATE OR REPLACE FUNCTION check_newvisit_icd (varchar, varchar, varchar, varchar) RETURNS bool AS
'
declare
    patient_id varchar;
    visit_id varchar;
    visit_datetime varchar;
    visit_icd10 varchar;
    newvisit boolean;
    check_visit record;
begin
    patient_id = $1;
    visit_id = $2;
    visit_icd10 = $3;
    visit_datetime = $4;
    newvisit = true;
   
    if (patient_id <> '''' and visit_id <> '''' and visit_datetime <> '''' and visit_icd10 <> '''')
    then   
            for check_visit in select t_diag_icd10.diag_icd10_number as icd10
                    from t_visit inner join t_diag_icd10 on t_visit.t_visit_id = t_diag_icd10.diag_icd10_vn
                    where t_visit.t_visit_id <> visit_id
                            and t_visit.t_patient_id = patient_id
                            and t_diag_icd10.diag_icd10_active = ''1''
                            and t_diag_icd10.diag_icd10_number = visit_icd10
                            and substring(t_visit.visit_financial_discharge_time,1,4) = substring(visit_datetime,1,4)
                            and substring(t_visit.visit_financial_discharge_time,1,10) < substring(visit_datetime,1,10)  
                           
            loop
                if check_visit.icd10 is not null
                then newvisit = false;
                else
                --กรณี Join กันไม่สำเร็จ
                end if;
            end loop;

    else      newvisit = true;
        
    end if;

    return newvisit;
end;
'
LANGUAGE 'plpgsql';

หลังจากนั้นเวลาเรียกใช้ 
select
t_visit.t_visit_id
,t_visit.t_patient_id
,t_visit.visit_vn
,t_visit.visit_financial_discharge_time
,t_diag_icd10.diag_icd10_number
-- บรรทัดข้างล่างเป็นการเรียกใช้ 
--โดยส่งค่า t_patient_id,t_visit_id,isit_financial_discharge_time,diag_icd10_number
,check_newvisit_icd(t_visit.t_patient_id,t_visit.t_visit_id,t_diag_icd10.diag_icd10_number,t_visit.visit_financial_discharge_time)
-- เป็นการดัดแปลงไปใช้งาน เพื่อแสดงผลตามที่ต้องการ โดยใช้ case เข้ามาช่วย เนื่องจากส่งค่า true กับ  false จึงไม่ต้องมีเงื่อนไขอะไรอีก when ไปได้เลยค่ะ
,case when check_newvisit_icd(t_visit.t_patient_id,t_visit.t_visit_id,t_diag_icd10.diag_icd10_number,t_visit.visit_financial_discharge_time)
    then 'รายใหม่'
    else 'รายเก่า'
end
from t_visit inner join t_diag_icd10
on t_visit.t_visit_id = t_diag_icd10.diag_icd10_vn
where t_visit.f_visit_status_id <> '4'
and t_diag_icd10.diag_icd10_active = '1'
and substring(t_visit.visit_financial_discharge_time,1,10) = '2553-03-29';

* ส่วนเราจะปรับใช้อย่างไร ก็ได้ค่ะ ...

แก้ปัญหาการเขียน Query ยาวๆ กับการจัดการเรื่องวันที่ใน Hospital OS

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

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

เกือบจะไปบวชชีแล้ว ... แต่ก็ยังละทางโลกไม่ได้ที อิอิ
งั้นเรามาเข้าเรื่องกันดีกว่าค่ะ  เพื่อให้เราทำงานง่ายขึ้นเราก็เขียนตัวช่วยมาซักตัวเอาไว้เรียกใช้กันนะคะ
สำหรับที่นำมาฝากกันวันนี้ เป็นเรื่องการหาผลต่างของเวลา ซึ่งโดยปกติ Hospital OS เก็บข้อมูลวันที่เป็น varchar ในลักษณะของปี พ.ศ. เช่น '2553-09-04,10:16:38'  จะเก็บข้อมูลไว้แบบนี้ค่ะเวลาเรานำข้อมูลมาใช้งาน เราก็ต้องเข้าใจว่าข้อมูลเก็บอยู่อย่างไร

มาเล่าเรื่องวันที่กันอีกทีนะคะ ขึ้นอยู่กับว่าเรานำข้อมูลไปใช้ยังไง
สมมติข้อมูล
t_visit.visit_financial_discharge_time = '2553-04-03,01:22:24'
t_visit.visit_begin_visit_time = '2553-03-30,13:46:48'

1. เรานำไปแสดงในรายงานโดยตรง ส่วนใหญ่ผู้ใช้งานต้องการ เป็น พ.ศ. อยู่แล้ว
เราสามารถ Substring ไปได้เลยค่ะ
ใช้คำสัง -> substring(t_visit.visit_financial_discharge_time,1,10)
ผลลัพธ์ -> 2553-04-03
2. ออกแฟ้มรายงาน หรือ ส่งเข้าโปรแกรมอื่นที่ต้องการข้อมูลรูปแบบ ค.ศ.
ใช้คำสัง -> cast(substring(t_visit.visit_financial_discharge_time,1,4) as numeric) - 543 || substring(t_visit.visit_financial_discharge_time,5,6)
ผลลัพธ์ -> 2010-04-03
3. ต้องการคำนวนวันจากวันที่ การใช้ Function เกี่ยวกับวันที่นั้นโดยปกติของฐานข้อมูลจะมองข้อมูลวันที่เป็น ค.ศ. ดังนั้นหากเราต้องการได้ข้อมูลที่ถูกต้องจริงๆ เราจะต้องแปลงข้อมูลให้เป็น ค.ศ. เสียก่อน (อ้างอิงจาก ข้อ 2 ) หลังจากนั้นเราก็ค่อยนำมาใช้กับ Function อีกที ในที่นี้จะยกตัวอย่างการแปลงวันที่ เพื่อลบกันได้ นั่นคือ
3.1 เราทำการแปลวันที่สิ้นสุดก่อน ในที่นี้ขอใช้ วันที่จำหน่ายทางการเงิน
cast(substring(t_visit.visit_financial_discharge_time,1,4) as numeric) - 543 || substring(t_visit.visit_financial_discharge_time,5,6)
จะได้วันที่ในรูปแบบ ค.ศ.
หลังจากนั้นก็ cast ให้เป็นวันที่ เพื่อจะนำไปลบ โดยยกข้างต้นมาทั้งชุดเลยนะคะ
เขียน cast( as date) วางไว้ก่อนก็ได้ จากนั้น copy มาทั้งชุดมาวางหลัง วงเล็บเปิด (
จะได้
cast(cast(substring(t_visit.visit_financial_discharge_time,1,4) as numeric) - 543 || substring(t_visit.visit_financial_discharge_time,5,6) as date)
จากข้อมูลสมมติ จะได้ 3/4/2553
3.2 เราทำการแปลงวันที่เริ่มต้น ในที่นี้ขอใช้วันที่ visit
cast(substring(t_visit.visit_begin_visit_time,1,4) as numeric) - 543 || substring(t_visit.visit_begin_visit_time,5,6)
จะได้วันที่ในรูปแบบ ค.ศ.
หลังจากนั้นก็ cast ให้เป็นวันที่ เพื่อจะนำไปลบ โดยยกข้างต้นมาทั้งชุดเลยนะคะ
เขียน cast( as date) วางไว้ก่อนก็ได้ จากนั้น copy มาทั้งชุดมาวางหลัง วงเล็บเปิด (
จะได้
cast(cast(substring(t_visit.visit_begin_visit_time,1,4) as numeric) - 543 || substring(t_visit.visit_begin_visit_time,5,6) as date)
จากข้อมูลสมมติ จะได้ 30/3/2553
3.3 นำข้อ 3.1 ลบด้วย 3.2
cast(cast(substring(t_visit.visit_financial_discharge_time,1,4) as numeric) - 543 || substring(t_visit.visit_financial_discharge_time,5,6) as date)
-
cast(cast(substring(t_visit.visit_begin_visit_time,1,4) as numeric) - 543 || substring(t_visit.visit_begin_visit_time,5,6) as date)

จากข้อมูลสมมติ จะได้ 4 หน่วยเป็นวัน (วันที่ - วันที่ = จำนวนวัน

ทีนี้เราทำแค่นี้อาจจะดูไม่ยุ่งยากนะคะ แต่ถ้าเรานำไปเขียนร่วมกับ Query ยาวแล้วอ่านจะตาลายมั้ยก็ไม่รู้ ...
ลองนำ Function นี้ไปใช้กันมั้ยคะ
function difference_datead_secs เป็น Function สำหรับหาผลต่างของวันที่และเวลา ได้ค่า วินาที ออกมาค่ะ

เริ่มต้นจากนำคำสั่งนี้ไปรัน นะคะ (รันครั้งเดียวก็พอ)
CREATE OR REPLACE FUNCTION difference_datead_secs (varchar, varchar) RETURNS int4 AS
'
declare
    date_start varchar;
    date_end varchar;
    result_secs int;
begin
    date_start = $1;
    date_end = $2;
   
    if (length(date_start) >= 10 and length(date_end) >= 10)
    then  
               result_secs = (date_part(''day'', (cast((cast(substring(date_end,1,4) as numeric) - 543) || substring(date_end,5) as timestamp)
                                                 -
                                               cast((cast(substring(date_start,1,4) as numeric) - 543) || substring(date_start,5) as timestamp))) * 60 * 60 * 24
                                    +
                                    date_part(''hour'', (cast((cast(substring(date_end,1,4) as numeric) - 543) || substring(date_end,5) as timestamp)
                                                 -
                                               cast((cast(substring(date_start,1,4) as numeric) - 543) || substring(date_start,5) as timestamp))) * 60 * 60
                                    +
                                    date_part(''min'', (cast((cast(substring(date_end,1,4) as numeric) - 543) || substring(date_end,5) as timestamp)
                                                 -
                                               cast((cast(substring(date_start,1,4) as numeric) - 543) || substring(date_start,5) as timestamp))) * 60
                                    +
                                    date_part(''sec'', (cast((cast(substring(date_end,1,4) as numeric) - 543) || substring(date_end,5) as timestamp)
                                                 -
                                               cast((cast(substring(date_start,1,4) as numeric) - 543) || substring(date_start,5) as timestamp))) ) ;

    else    result_secs = 0;
        
    end if;

    return result_secs;
end;
'
LANGUAGE 'plpgsql';

หลังจากนั้นเวลาเรียกใช้ 
select
t_visit.t_patient_id
,t_visit.t_visit_id
,t_visit.visit_vn
,t_visit.visit_begin_visit_time
,t_visit.visit_financial_discharge_time
,t_visit_service.b_service_point_id
,t_visit_service.assign_date_time
,t_visit_service.visit_service_treatment_date_time
,t_visit_service.visit_service_finish_date_time
-- บรรทัดข้างล่างเป็นการเรียกใช้ โดยส่งวันที่เข้าไปไม่ต้องแปลงข้อมูลใน Function ที่เราสร้างไปแล้วนั้นจะแปลงให้เองค่ะ
,difference_datead_secs(t_visit.visit_begin_visit_time,t_visit.visit_financial_discharge_time)
from t_visit inner join  t_visit_service
on t_visit.t_visit_id = t_visit_service.t_visit_id
where t_visit_service.visit_service_finish_date_time <> ''
and t_visit.f_visit_status_id <> '4'
and t_visit.f_visit_type_id = '0'
and substring(t_visit.visit_financial_discharge_time,1,10) = '2553-04-03'
order by
t_visit.t_patient_id
,t_visit.t_visit_id;

ลองดูนะคะ หากไม่เข้าใจก็ถามได้ค่ะ