วันอาทิตย์ที่ 14 ธันวาคม พ.ศ. 2557

ตัวอย่าง: คำสั่ง SELECT ที่ใช้ SQL descriptor ที่ถูกจัดสรรแล้ว

สมมติว่า แอ็พพลิเคชันของคุณจำเป็นต้องจัดการกับคำสั่ง SELECT แบบ dynamic เมื่อค่าหนึ่งเปลี่ยนเป็นอีกค่าหนึ่งสำหรับใช้ต่อไป คำสั่งนี้สามารถอ่านได้จากจอแสดงผล ซึ่งถูกส่งผ่านจากแอ็พพลิเคชันอื่น หรือถูกสร้างขึ้นจากแอ็พพลิเคชันของคุณแบบ dynamic
พูดได้อีกอย่างว่า, คุณไม่ทราบแน่ชัดว่า คำสั่งนี้จะส่งค่าอะไรคืนกลับมาในทุกครั้ง. แอ็พพลิเคชันจำเป็นต้องจัดการกับจำนวนที่แตกต่างกันออกไปของคอลัมน์ผลลัพธ์ที่ไม่ทราบชนิดข้อมูลที่แน่นอนก่อนล่วงหน้า
ยกตัวอย่างเช่น, คำสั่งต่อไปนี้จำเป็นจะต้องถูกประมวลผล:
   SELECT WORKDEPT, PHONENO 
     FROM CORPDATA.EMPLOYEE
     WHERE LASTNAME = 'PARKER'
หมายเหตุ: คำสั่ง SELECT นี้ไม่มี INTO clause. คำสั่ง SELECT แบบ dynamic จะต้องไม่ มี INTO clause, ถึงแม้ว่าจะส่งค่าคืนมาเพียงแถวเดียว.
คำสั่งจะถูกกำหนดค่าให้กับตัวแปรโฮสต์. ตัวแปรโฮสต์, ในกรณีนี้มีชื่อว่า DSTRING, จะถูกทำการประมวลผลโดยใช้คำสั่ง PREPARE ตามที่ได้แสดงไว้ดังนี้:
EXEC SQL
PREPARE S1 FROM :DSTRING;
ขั้นถัดไป, คุณจำเป็นจะต้องหาค่าจำนวนของคอลัมน์ผลลัพธ์และชนิดของข้อมูล. หากต้องการทำสิ่งนี้, คุณจำเป็นต้องจัดสรรจำนวน entry ขนาดใหญ่สุดสำหรับ SQL descriptor ที่คุณคิดว่าคุณต้องการ. สมมติว่า มีคอลัมน์ไม่เกิน 20 คอลัมน์ถูกเรียกใช้โดยคำสั่ง SELECT เดียว.
EXEC SQL
ALLOCATE DESCRIPTOR 'mydescr' WITH MAX 20;
ถึงตอนนี้ descriptor จะถูกจัดสรร, คำสั่ง DESCRIBE สามารถเรียกใช้เพื่อรับข้อมูลคอลัมน์.
EXEC SQL
DESCRIBE S1 USING DESCRIPTOR 'mydescr';
เมื่อคำสั่ง DESCRIBE ถูกรัน, SQL จะใส่ค่าที่ได้เตรียมข้อมูลเกี่ยวกับรายการที่เลือกของคำสั่งเข้าไปใน SQL descriptor area ซึ่งถูกนิยามโดย 'mydescr'.
ถ้า DESCRIBE กำหนดว่า มี entry ไม่เพียงพอที่จะถูกจัดสรรใน descriptor, SQLCODE +239 จะถูกเรียกใช้. ส่วนหนึ่งของการวินิจฉัยนี้, การแทนที่ค่าข้อความที่สองจะบ่งชี้ถึงจำนวนของ entry ที่ต้องการ. ตัวอย่างโค้ดต่อไปนี้แสดงวิธีที่เงื่อนไขนี้สามารถตรวจพบ และแสดง descriptor ที่ถูกจัดสรรด้วยขนาดที่ใหญ่กว่า.
/* Determine the returned SQLCODE from the DESCRIBE statement */
EXEC SQL
  GET DIAGNOSTICS CONDITION 1: returned_sqlcode = DB2_RETURNED_SQLCODE;

if returned_sqlcode = 239 then do;

/* Get the second token for the SQLCODE that indicated 
     not enough entries were allocated */

EXEC SQL 
    GET DIAGNOSTICS CONDITION 1: token = DB2_ORDINAL_TOKEN_2;             
  /* Move the token variable from a character host variable into an integer host variable */
  EXEC SQL 
    SET :var1 = :token;                             
  /* Deallocate the descriptor that is too small */
  EXEC SQL
    DEALLOCATE DESCRIPTOR 'mydescr';                
  /* Allocate the new descriptor to be the size indicated by the retrieved token */
  EXEC SQL 
    ALLOCATE DESCRIPTOR 'mydescr' WITH MAX :var1;   
  /* Perform the describe with the larger descriptor */
  EXEC SQL 
   DESCRIBE s1 USING DESCRIPTOR 'mydescr';         
end;            
ถึงตอนนี้ descriptor จะมีข้อมูล เกี่ยวกับคำสั่ง SELECT และคุณพร้อมที่จะดึงผลลัพธืของคำสั่ง SELECT ออกมา. สำหรับ SQL แบบ dynamic, คำสั่ง SELECT INTO จะไม่อนุญาตให้ใช้. คุณต้องใช้เคอร์เซอร์.
EXEC SQL
  DECLARE C1 CURSOR FOR S1;
คุณจะสังเกตว่า ชื่อคำสั่งที่ถูกจัดเตรียมจะถูกใช้ในการประกาศเคอร์เซอร์แทนการทำคำสั่ง SELECT ให้สมบูรณ์. ถึงตอนนี้ คุณสามารถวนซ้ำแถวที่เลือก, ประมวลผลแถวเหล่านั้นตามที่คุณอ่านได้. ตัวอย่างโค้ดต่อไปนี้แสดงถึงวิธีการทำสิ่งนี้.
EXEC SQL
  OPEN C1;

EXEC SQL
    FETCH C1 USING SQL DESCRIPTOR 'mydescr';
do while not at end of data;

 /* process current data returned  (see below for discussion of doing this) */

/* then read the next row */

 EXEC SQL
    FETCH C1 USING SQL DESCRIPTOR 'mydescr';
end;

EXEC SQL
  CLOSE C1;
เคอร์เซอร์ถูกเปิด. แถวที่เป็นผลลัพธ์จากคำสั่ง SELECT จะถูกส่งคืนมาครั้งละหนึ่งแถวโดยใช้คำสั่ง FETCH. ในคำสั่ง FETCH, จะไม่มีรายชื่อของตัวแปรโฮสต์อยู่. แทนที่จะเป็นเช่นนั้น, คำสั่ง FETCH จะบอกให้ SQL ส่งคืนผลลัพธ์เข้าไปใน descriptor area.
หลังจากประมวลผล FETCH แล้ว, คุณสามารถใช้คำสั่ง GET DESCRIPTOR เพื่ออ่านค่าเหล่านั้น. อันดับแรก, คุณต้องอ่านค่าส่วนหัวที่บ่งชี้ถึงจำนวน descriptor entry ที่ถูกใช้.
EXEC SQL
  GET DESCRIPTOR 'mydescr' :count = COUNT;
หลังจากนั้น คุณสามารถอ่านข้อมูลเกี่ยวกับ descriptor entry แต่ละตัว. หลังจากที่คุณกำหนดชนิดข้อมูลของคอลัมน์ผลลัพธ์แล้ว, คุณสามารถทำให้ GET DESCRIPTOR อื่นส่งคืนค่าที่เป็นจริง. หากต้องการรับค่าของตัวบ่งชี้, ให้ระบุไอเท็ม INDICATOR. ถ้าค่าของไอเท็ม INDICATOR เป็นลบ, ค่าของไอเท็ม DATA จะไม่ถูกนิยาม. จนกว่า FETCH อื่นจะถูกทำ, ไอเท็ม descriptor จะยังคงรักษาค่าเหล่านั้นไว้.
do i = 1 to count;
  GET DESCRIPTOR 'mydescr' VALUE :i  /* set entry number to get */
                         :type = TYPE,                    /* get the data type */
                         :length = LENGTH,                /* length value */
                         :result_ind = INDICATOR;            
 if result_ind >= 0 then 
    if type = character 
     GET DESCRIPTOR 'mydescr' VALUE :i
                        :char_result = DATA;       /* read data into character field */
    else
    if type = integer
       GET DESCRIPTOR 'mydescr' VALUE :i      
                        :int_result = DATA;       /* read data into integer field */
  else 
      /* continue checking and processing for all data types that might be returned */
end;
มีไอเท็ม descriptor อื่นๆ หลายไอเท็มที่คุณอาจต้องการตรวจสอบ เพื่อกำหนดวิธีการจัดการกับข้อมูลผลลัพธ์. PRECISION, SCALE, DB2_CCSID, และ DATETIME_INTERVAL_CODE อยู่ระหว่างกัน. ตัวแปรโฮสต์ที่มีการอ่านค่า DATA เข้าไปในตัวแปรต้องมีชนิดข้อมูลเดียวกัน และ CCSID ต้องเป็นข้อมูลที่อ่านได้. ถ้าชนิดข้อมูลมีความยาวผันแปร, ตัวแปรโฮสต์จะถูกประกาศความยาวได้ยาวกว่าข้อมูลจริง. สำหรับชนิดข้อมูลอื่นๆ ทั้งหมด, ความยาวต้องตรงกัน.
NAME, DB2_SYSTEM_COLUMN_NAME, และ DB2_LABEL จะถูกใช้เพื่อรับค่าชื่อที่สัมพันธ์กันสำหรับคอลัมน์ผลลัพธ์. โปรดดู GET DESCRIPTOR สำหรับข้อมูลเพิ่มเติมเกี่ยวกับไอเท็มที่ถูกส่งคืนสำหรับคำสั่ง GET DESCRIPTOR และสำหรับ definition ของค่า TYPE