คอมพิวเตอร์ หน้าต่าง อินเทอร์เน็ต

ตัวอย่างเคอร์เซอร์ Ms sql เคอร์เซอร์ในขั้นตอนการจัดเก็บ MySQL คุณสมบัติของการใช้เคอร์เซอร์ใน Oracle

สวัสดีเพื่อนผู้อ่านบล็อกในชุมชน

ฉันอยากจะพูดคุยเกี่ยวกับประสบการณ์ล่าสุดของฉันในการเพิ่มประสิทธิภาพเคอร์เซอร์ใน SQL Server
สิ่งแรกที่คุณต้องรู้ก็คือ เคอร์เซอร์ไม่ดี แต่แย่. ในกรณีที่เป็นไปได้ที่จะแทนที่เคอร์เซอร์ด้วย INSERT SELECT หรือใช้ตารางชั่วคราว ก็ควรจะดำเนินการนี้ (โดยมีข้อยกเว้นที่ไม่ค่อยเกิดขึ้น) เคอร์เซอร์มักจะหมายถึงทรัพยากรเซิร์ฟเวอร์เพิ่มเติมและประสิทธิภาพที่ลดลงอย่างมากเมื่อเทียบกับโซลูชันอื่นๆ
ประการที่สอง บางครั้งคุณไม่สามารถทำได้โดยไม่มีเคอร์เซอร์ โดยที่คุณไม่สามารถทำได้โดยไม่ต้องผ่านผลลัพธ์การเลือกทีละบรรทัด ในกรณีเช่นนี้ สิ่งสำคัญมากคือต้องสร้างเคอร์เซอร์ประเภทที่ต้องการอย่างถูกต้อง ซึ่งเป็นประเภทที่ตรงกับปัญหาที่กำลังแก้ไข ไวยากรณ์ทั่วไปสำหรับการประกาศเคอร์เซอร์คือ:

ประกาศเคอร์เซอร์_ชื่อเคอร์เซอร์
[ท้องถิ่น | ทั่วโลก]
[ ส่งต่อ_เท่านั้น | เลื่อน ]
[คงที่ | คีย์เซ็ต | ไดนามิก | เร็ว_ไปข้างหน้า ]
[อ่าน_อย่างเดียว | SCROLL_LOCKS | มองโลกในแง่ดี]
[TYPE_WARNING]
สำหรับ select_statement
[ สำหรับการอัปเดต [ ของ column_name [ ,... n ] ] ] [ ;]

ฉันจะเน้นไปที่พารามิเตอร์หลักสามบรรทัดแรก
LOCAL หรือ GLOBAL: หากเราต้องการให้เคอร์เซอร์สามารถเข้าถึงขั้นตอน ฟังก์ชัน แพ็คเกจอื่นๆ ภายในเซสชันของเราได้ ก็ GLOBAL - ในกรณีนี้ เราจะจัดการลบเคอร์เซอร์ด้วยตัวเอง (คำสั่ง DEALLOCATE) ในกรณีอื่นๆ ทั้งหมด (เช่น ในกลุ่มคนส่วนใหญ่อย่างท่วมท้น) - ท้องถิ่น. โปรดทราบ ตามค่าเริ่มต้นแล้ว เคอร์เซอร์ GLOBAL จะถูกสร้างขึ้น!
FORWARD_ONLY หรือ SCROLL: หากเราต้องการเลื่อนเคอร์เซอร์อย่างบ้าคลั่ง กลับไปกลับมา ให้ SCROLL หรืออย่างอื่น - ส่งต่อ_เท่านั้น. โปรดทราบ ตามค่าเริ่มต้นเคอร์เซอร์ SCROLL จะถูกสร้างขึ้น!
STATIC หรือ KEYSET, DYNAMIC, FAST_FORWARD: หากเราต้องการให้ข้อมูลปัจจุบันจากตารางแสดงเมื่อผ่านเคอร์เซอร์ (เช่น หากหลังจากเปิดเคอร์เซอร์แล้ว เราได้เปลี่ยนข้อมูลในช่องใดช่องหนึ่งของตารางและเราต้องการให้เป็นเช่นนั้น เมื่อผ่านเคอร์เซอร์ในบรรทัดเคอร์เซอร์ที่ต้องการมีข้อมูลที่อัปเดตแล้ว) จากนั้นเราจะใช้ KEYSET (หากทุกตารางที่เข้าร่วมในการเลือกมีดัชนีไม่ซ้ำกัน) หรือ DYNAMIC (ประเภทที่ช้าที่สุด) หากเราต้องการสแน็ปช็อตของผลลัพธ์ตัวอย่างหลังจากเปิดเคอร์เซอร์ - คงที่(ประเภทที่เร็วที่สุด - สำเนาของผลลัพธ์ตัวอย่างจะถูกคัดลอกไปยังฐานข้อมูล tempdb และเราจะดำเนินการแก้ไข) FAST_FORWARD = KEYSET+FORWARD_ONLY+READ_ONLY – พวกอินเทอร์เน็ตเขียนว่า STATIC ใช้เวลาเปิดนานกว่า (เนื่องจากสำเนาถูกสร้างขึ้นใน tempdb) แต่ทำงานได้เร็วกว่า และ FAST_FORWARD ตรงกันข้าม ดังนั้นหากจำนวนบันทึกมีขนาดใหญ่ (เท่าที่แสดงให้เห็นในทางปฏิบัติ) เราจะใช้ STATIC ไม่เช่นนั้นเราจะใช้ FAST_FORWARD ข้อควรสนใจ ตามค่าเริ่มต้นเคอร์เซอร์ DYNAMIC จะถูกสร้างขึ้น

ดังนั้น สำหรับบันทึกจำนวนมาก ในกรณีส่วนใหญ่ ตัวเลือกของฉันคือ:
ประกาศ cursor_name CURSOR LOCAL FORWARD_ONLY STATIC FOR
select_statemen
ที

สำหรับบันทึกจำนวนเล็กน้อย:
ประกาศ cursor_name CURSOR LOCAL FAST_FORWARD FOR
select_statement

ตอนนี้เรามาฝึกซ้อมกันต่อ (ซึ่งจริงๆ แล้วกระตุ้นให้ฉันเขียนสิ่งนี้)
ตั้งแต่สมัยโบราณ เมื่อประกาศเคอร์เซอร์ ฉันใช้ DECLARE ... CURSOR LOCAL FOR... โครงสร้าง
เมื่อพัฒนาการรวมเข้ากับฐานข้อมูลที่แย่มากซึ่งไม่มีดัชนีเดียวและไม่มีคีย์เดียว ฉันใช้วิธีการเดียวกันนี้เมื่อประกาศเคอร์เซอร์เช่นเคย ตัวอย่างเคอร์เซอร์ตัวหนึ่งมีข้อมูล 225,000 รายการ เป็นผลให้กระบวนการนำเข้าข้อมูลจากฐานข้อมูลดังกล่าวใช้เวลา 15 ชั่วโมง 14 นาที!!! และถึงแม้ว่าการนำเข้าจะเป็นการนำเข้าขั้นต้น (เช่น ครั้งเดียว) แม้แต่การทดสอบการนำเข้าตามปกติก็ยังต้องใช้เวลาหลายวัน! หลังจากแทนที่โครงสร้างด้านบนเมื่อประกาศเคอร์เซอร์ด้วย DECLARE .. CURSOR LOCAL FORWARD_ONLY STATIC FOR.. กระบวนการนำเข้าทั้งหมดเอา... ความสนใจ... 10 นาที 5 วินาที!!! ดังนั้นเกมนี้จึงคุ้มค่ากับเทียนอย่างแน่นอน
ฉันอยากจะย้ำอีกครั้งว่าตัวเลือกในอุดมคติคือไม่ใช้เคอร์เซอร์เลย - สำหรับ MS SQL DBMS วิธีการเชิงสัมพันธ์มากกว่าการนำทางนั้นมีความเป็นธรรมชาติมากกว่ามาก

เคอร์เซอร์ที่ชัดเจนคือคำสั่ง SELECT ที่กำหนดไว้อย่างชัดเจนในส่วนการประกาศของโปรแกรม เมื่อคุณประกาศเคอร์เซอร์ที่ชัดเจน เคอร์เซอร์นั้นจะถูกตั้งชื่อ ไม่สามารถกำหนดเคอร์เซอร์ที่ชัดเจนสำหรับคำสั่ง INSERT, UPDATE, MERGE และ DELETE

ด้วยการกำหนดคำสั่ง SELECT ให้เป็นเคอร์เซอร์ที่ชัดเจน โปรแกรมเมอร์จะสามารถควบคุมขั้นตอนหลักในการดึงข้อมูลจากฐานข้อมูล Oracle โดยจะกำหนดเวลาเปิดเคอร์เซอร์ (OPEN) เมื่อใดที่ควรเลือกแถวจากเคอร์เซอร์ (FETCH) จำนวนแถวที่จะเลือก และเมื่อใดที่ควรปิดเคอร์เซอร์โดยใช้คำสั่ง CLOSE ข้อมูลเกี่ยวกับสถานะปัจจุบันของเคอร์เซอร์สามารถดูได้จากแอตทริบิวต์ การควบคุมที่มีรายละเอียดสูงนี้เองที่ทำให้เคอร์เซอร์ที่ชัดเจนเป็นเครื่องมืออันล้ำค่าสำหรับโปรแกรมเมอร์

ลองดูตัวอย่าง:

1 ฟังก์ชัน อิจฉา_ระดับ (2 NAME_IN ใน friends.NAME%TYPE) ส่งคืนหมายเลข 3 เป็น 4 เคอร์เซอร์ อิจฉา_cur 5 คือ 6 เลือกตำแหน่งจากเพื่อน 7 โดยที่ NAME = UPPER (NAME_IN); 8 8 อิจฉา_rec อิจฉา_cur%ROWTYPE; 9 ย้อนกลับ NUMBER; 10 เริ่มต้น 11 เปิดความอิจฉาริษยา; 13 12 ดึงความอิจฉา_cur เข้าสู่ความอิจฉา_rec; 15 13 IF อิจฉา_cur% พบ 14 แล้ว 15 IF อิจฉา_rec.location = "เปอร์โตริโก" 16 แล้ว retval:= 10; 17 ELSIF อิจฉา_rec.location = "ชิคาโก" 18 แล้ว retval:= 1; 19 จบ ถ้า; 20 จบ ถ้า; 24 21 ปิดความอิจฉาริษยา; 26 22 การส่งคืนกลับ; 23 ข้อยกเว้น 24 เมื่อคนอื่นแล้ว 25 ถ้า อิจฉา_cur%ISOPEN แล้ว 26 ปิด อิจฉา_cur; 27 สิ้นสุด ถ้า; 28 จบ;

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

ประกาศเคอร์เซอร์ที่ชัดเจน

เพื่อให้สามารถใช้เคอร์เซอร์ที่ชัดเจนได้ จะต้องประกาศไว้ในส่วนการประกาศของบล็อกหรือแพ็คเกจ PL/SQL:

เคอร์เซอร์ cursor_name [ ([ พารามิเตอร์ [, พารามิเตอร์...]) ] [ RETURN specification_reEirn ] IS SELECT_command ];

ในที่นี้ชื่อเคอร์เซอร์คือชื่อของเคอร์เซอร์ที่ประกาศ spifition_te?it - ส่วน RETURN ที่เป็นทางเลือก KOMaHdaSELECT - คำสั่ง SQL SELECT ที่ถูกต้อง พารามิเตอร์ยังสามารถส่งผ่านไปยังเคอร์เซอร์ได้ (ดูส่วน "พารามิเตอร์เคอร์เซอร์" ด้านล่าง) สุดท้าย หลังจากคำสั่ง SELECT...FOR UPDATE คุณสามารถระบุรายการคอลัมน์ที่จะอัปเดตได้ (ดูด้านล่างด้วย) หลังจากการประกาศ เคอร์เซอร์จะเปิดขึ้นด้วยคำสั่ง OPEN และแถวจะถูกดึงออกมาด้วยคำสั่ง FETCH

ตัวอย่างการประกาศเคอร์เซอร์ที่ชัดเจน

  • เคอร์เซอร์ที่ไม่มีพารามิเตอร์. ชุดผลลัพธ์ของแถวจากเคอร์เซอร์นี้คือชุดรหัสบริษัทที่เลือกจากแถวทั้งหมดในตาราง:
CURSOR company_cur คือ SELECT company_id จากบริษัท;
  • เคอร์เซอร์พร้อมพารามิเตอร์ชุดแถวผลลัพธ์ของเคอร์เซอร์นี้ประกอบด้วยแถวเดียวที่มีชื่อบริษัทที่สอดคล้องกับค่าของพารามิเตอร์ที่ส่งผ่าน:
CURSOR name_cur (company_id_in ใน NUMBER) คือชื่อที่เลือกจาก บริษัท โดยที่ company_id = company_id_in;
  • เคอร์เซอร์ที่มีส่วนคำสั่ง RETURN. ชุดแถวผลลัพธ์ของเคอร์เซอร์นี้มีข้อมูลทั้งหมดในตารางพนักงานสำหรับ ID แผนก 10:
CURSOR emp_cur RETURN พนักงาน% ROWTYPE ถูกเลือก * จากพนักงาน WHERE department_id = 10;

ชื่อเคอร์เซอร์

ชื่อเคอร์เซอร์ที่ชัดเจนต้องมีความยาวไม่เกิน 30 อักขระและเป็นไปตามกฎเดียวกันกับตัวระบุ PL/SQL อื่นๆ ชื่อเคอร์เซอร์ไม่ใช่ตัวแปร แต่เป็นตัวระบุของตัวชี้ไปยังคำขอ ชื่อเคอร์เซอร์ไม่ได้กำหนดค่าและไม่สามารถใช้ในนิพจน์ได้ เคอร์เซอร์จะใช้เฉพาะในคำสั่ง OPEN, CLOSE และ FETCH เท่านั้น และเพื่อให้มีคุณสมบัติแอตทริบิวต์เคอร์เซอร์

ประกาศเคอร์เซอร์ในแพ็คเกจ

เคอร์เซอร์ที่ชัดเจนจะถูกประกาศในส่วนการประกาศของบล็อก PL/SQL เคอร์เซอร์สามารถประกาศได้ที่ระดับแพ็คเกจ แต่ไม่สามารถประกาศภายในขั้นตอนหรือฟังก์ชันแพ็คเกจเฉพาะได้ ตัวอย่างการประกาศเคอร์เซอร์สองตัวในแพ็คเกจ:

PACKAGE book_info เป็น CURSOR titles_cur คือ SELECT ชื่อจากหนังสือ; CURSOR books_cur (title_filter_in IN books.title%TYPE) คืนหนังสือ%ROWTYPE IS SELECT * จากหนังสือ WHERE title LIKE title_filter_in; จบ;

เคอร์เซอร์ titles_cur ตัวแรกจะแสดงเฉพาะชื่อหนังสือเท่านั้น ประการที่สอง books_cur ส่งคืนแถวทั้งหมดของตารางหนังสือซึ่งมีชื่อหนังสือตรงกับรูปแบบที่ระบุเป็นพารามิเตอร์เคอร์เซอร์ (เช่น "หนังสือทั้งหมดที่มีสตริง 'PL/SQL'") โปรดทราบว่าเคอร์เซอร์ตัวที่สองใช้ส่วน RETURN ซึ่งประกาศโครงสร้างข้อมูลที่ส่งคืนโดยคำสั่ง FETCH

ส่วน RETURN สามารถมีโครงสร้างข้อมูลใดๆ ต่อไปนี้:

  • บันทึกที่กำหนดจากแถวตารางข้อมูลโดยใช้แอตทริบิวต์ %ROWTYPE
  • รายการที่กำหนดจากเคอร์เซอร์อื่นที่ประกาศไว้ก่อนหน้านี้ รวมถึงใช้แอตทริบิวต์ %rowtype
  • รายการที่กำหนดโดยโปรแกรมเมอร์

จำนวนนิพจน์ในรายการการเลือกเคอร์เซอร์ต้องตรงกับจำนวนคอลัมน์ใน table_name%ROWTYPE, Kypcop%ROWTYPE หรือเรกคอร์ดประเภทเรกคอร์ด ประเภทข้อมูลขององค์ประกอบจะต้องเข้ากันได้ด้วย ตัวอย่างเช่น หากองค์ประกอบที่สองของรายการที่เลือกเป็นประเภท NUMBER คอลัมน์ที่สองของรายการในส่วน RETURN จะต้องไม่เป็นประเภท VARCHAR2 หรือ BOOLEAN

ก่อนที่จะไปยังการตรวจสอบโดยละเอียดของส่วน RETURN และข้อดีของมัน ก่อนอื่นเรามาทำความเข้าใจก่อนว่าทำไมจึงจำเป็นต้องประกาศเคอร์เซอร์ในแพ็คเกจ ทำไมไม่ประกาศเคอร์เซอร์อย่างชัดเจนในโปรแกรมที่ใช้งาน - ในโพรซีเดอร์, ฟังก์ชัน หรือบล็อกที่ไม่ระบุชื่อ?

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

นอกจากนี้ยังควรพิจารณาสร้างฟังก์ชันที่ส่งคืนตัวแปรเคอร์เซอร์ตาม REF CURSOR โปรแกรมที่เรียกดึงข้อมูลแถวผ่านตัวแปรเคอร์เซอร์ สำหรับข้อมูลเพิ่มเติม โปรดดูส่วน "ตัวแปรเคอร์เซอร์และเคอร์เซอร์อ้างอิง"

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

ตอนนี้เรามาดูที่ส่วน RETURN สิ่งที่น่าสนใจอย่างหนึ่งเกี่ยวกับการประกาศเคอร์เซอร์ในแพ็คเกจก็คือ ส่วนหัวของเคอร์เซอร์สามารถแยกออกจากเนื้อหาได้ ส่วนหัวนี้ชวนให้นึกถึงส่วนหัวของฟังก์ชันมากกว่า ประกอบด้วยข้อมูลที่โปรแกรมเมอร์จำเป็นต้องใช้ในการทำงาน: ชื่อของเคอร์เซอร์ พารามิเตอร์ และประเภทของข้อมูลที่ส่งคืน เนื้อความของเคอร์เซอร์คือคำสั่ง SELECT เทคนิคนี้แสดงให้เห็นในการประกาศเคอร์เซอร์ books_cur เวอร์ชันใหม่ในแพ็คเกจ book_info:

PACKAGE book_info IS CURSOR books_cur (title_filter_in IN books.title%TYPE) ส่งคืนหนังสือ%ROWTYPE; จบ; เนื้อหาแพคเกจ book_info IS CURSOR books_cur (title_filter_in IN books.title%TYPE) คืนหนังสือ%ROWTYPE IS SELECT * จากหนังสือ WHERE title LIKE title_filter_in; จบ;

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

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

การเปิดเคอร์เซอร์ที่ชัดเจน

การใช้เคอร์เซอร์เริ่มต้นด้วยการกำหนดในส่วนการประกาศ จากนั้นจะต้องเปิดเคอร์เซอร์ที่ประกาศไว้ ไวยากรณ์ของคำสั่ง OPEN นั้นง่ายมาก:

OPEN cursor_name [ (อาร์กิวเมนต์ [, อาร์กิวเมนต์...]) ];

ในที่นี้ ชื่อเคอร์เซอร์คือชื่อของเคอร์เซอร์ที่ประกาศไว้ก่อนหน้านี้ และอาร์กิวเมนต์คือค่าที่ส่งไปยังเคอร์เซอร์หากมีการประกาศพร้อมกับรายการพารามิเตอร์

Oracle ยังสนับสนุนไวยากรณ์ FOR เมื่อเปิดเคอร์เซอร์ ซึ่งใช้สำหรับตัวแปรเคอร์เซอร์ทั้งสอง (ดูหัวข้อ "ตัวแปรเคอร์เซอร์และ REF CURSOR") และ SQL ไดนามิกแบบฝัง

เมื่อ PL/SQL เปิดเคอร์เซอร์ จะดำเนินการสืบค้นที่มีอยู่ นอกจากนี้ยังระบุชุดข้อมูลที่ใช้งานอยู่ - แถวของตารางทั้งหมดที่เข้าร่วมในการสืบค้นที่ตรงกับเกณฑ์ WHERE และเงื่อนไขการรวม คำสั่ง OPEN จะไม่ดึงข้อมูล - นั่นคืองานของคำสั่ง FETCH

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

ยิ่งไปกว่านั้น หากคำสั่ง SELECT มีส่วน FOR UPDATE แถวทั้งหมดที่ระบุโดยเคอร์เซอร์จะถูกล็อคเมื่อเปิดเคอร์เซอร์

หากคุณพยายามเปิดเคอร์เซอร์ที่เปิดอยู่แล้ว PL/SQL จะแสดงข้อความแสดงข้อผิดพลาดต่อไปนี้:

ORA-06511: PL/SQL: เคอร์เซอร์เปิดอยู่แล้ว

ดังนั้น ก่อนที่จะเปิดเคอร์เซอร์ คุณควรตรวจสอบสถานะโดยใช้ค่าแอตทริบิวต์ %เปิด:

หากไม่ใช่ company_cur% ISOPEN ให้เปิด company_cur; เอนดิฟ;

คุณลักษณะของเคอร์เซอร์ที่ชัดเจนมีการอธิบายไว้ด้านล่างในหัวข้อเฉพาะสำหรับเคอร์เซอร์เหล่านี้

ถ้าโปรแกรมรัน FOR loop โดยใช้เคอร์เซอร์ เคอร์เซอร์ก็ไม่จำเป็นต้องเปิด (ดึงข้อมูล ปิด) อย่างชัดเจน กลไก PL/SQL ทำสิ่งนี้โดยอัตโนมัติ

กำลังดึงข้อมูลจากเคอร์เซอร์ที่ชัดเจน

คำสั่ง SELECT จะสร้างตารางเสมือน - ชุดของแถวที่กำหนดโดยส่วนคำสั่ง WHERE พร้อมด้วยคอลัมน์ที่กำหนดโดยรายการคอลัมน์ SELECT ดังนั้นเคอร์เซอร์จึงแทนตารางนี้ในโปรแกรม PL/SQL วัตถุประสงค์หลักของเคอร์เซอร์ในโปรแกรม PL/SQL คือการเลือกแถวสำหรับการประมวลผล การดึงข้อมูลแถวเคอร์เซอร์ทำได้ด้วยคำสั่ง FETCH:

FETCH cursor_name เข้าสู่ record_or_variable_list;

ในที่นี้ ชื่อเคอร์เซอร์คือชื่อของเคอร์เซอร์ที่เลือกบันทึก และรายการบันทึกหรือตัวแปรคือโครงสร้างข้อมูล PL/SQL ที่จะคัดลอกแถวถัดไปของชุดบันทึกที่ใช้งานอยู่ ข้อมูลสามารถวางในบันทึก PL/SQL (ประกาศด้วยแอตทริบิวต์ %ROWTYPE หรือการประกาศ TYPE) หรือในตัวแปร (ตัวแปร PL/SQL หรือตัวแปรผูก - เช่นในองค์ประกอบ Oracle Forms)

ตัวอย่างของเคอร์เซอร์ที่ชัดเจน

ตัวอย่างต่อไปนี้สาธิตวิธีต่างๆ ในการสุ่มตัวอย่างข้อมูล

  • การดึงข้อมูลจากเคอร์เซอร์ลงในบันทึก PL/SQL:
ประกาศเคอร์เซอร์ company_cur คือ SELECT ...; company_rec company_cur%ROWTYPE; เริ่มเปิด company_cur; FETCH company_cur เข้าสู่ company_rec;
  • การดึงข้อมูลจากเคอร์เซอร์เข้าสู่ตัวแปร:
ดึง new_balance_cur เข้าสู่ new_balance_dollars;
  • การดึงข้อมูลจากเคอร์เซอร์ไปยังแถวของตาราง PL/SQL, ตัวแปร และตัวแปรการผูกของ Oracle Forms:
FETCH emp_name_cur เข้าสู่ emp_name (1), จ้างงาน, :dept.min_salary;

ข้อมูลที่ดึงมาจากเคอร์เซอร์ควรถูกวางไว้ในบันทึกที่ประกาศภายใต้เคอร์เซอร์เดียวกันกับแอตทริบิวต์ %ROWTYPE หลีกเลี่ยงการเลือกรายการตัวแปร การดึงข้อมูลลงในบันทึกจะทำให้โค้ดมีขนาดกะทัดรัดและยืดหยุ่นมากขึ้น ช่วยให้คุณสามารถเปลี่ยนรายการดึงข้อมูลได้โดยไม่ต้องเปลี่ยนคำสั่ง FETCH

การสุ่มตัวอย่างหลังจากประมวลผลแถวสุดท้าย

เมื่อคุณเปิดเคอร์เซอร์ คุณจะเลือกบรรทัดจากบรรทัดนั้นทีละบรรทัดจนกระทั่งหมด อย่างไรก็ตาม คุณยังคงสามารถใช้คำสั่ง FETCH ได้หลังจากนี้

น่าแปลกที่ PL/SQL ไม่มีข้อยกเว้นในกรณีนี้ เขาแค่ไม่ทำอะไรเลย เนื่องจากไม่มีอะไรให้เลือก ค่าของตัวแปรในส่วน INTO ของคำสั่ง FETCH จึงไม่เปลี่ยนแปลง กล่าวอีกนัยหนึ่ง คำสั่ง FETCH ไม่ได้ตั้งค่าตัวแปรเหล่านี้เป็น NULL

นามแฝงคอลัมน์เคอร์เซอร์ที่ชัดเจน

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

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

  • เมื่อดึงข้อมูลจากเคอร์เซอร์ลงในบันทึกที่ประกาศด้วยแอตทริบิวต์ %ROWTYPE ตามเคอร์เซอร์เดียวกัน
  • เมื่อโปรแกรมมีการอ้างอิงไปยังคอลัมน์จากการคำนวณ

พิจารณาคำถามต่อไปนี้ คำสั่ง SELECT เลือกชื่อของบริษัททั้งหมดที่สั่งซื้อสินค้าระหว่างปี 2544 รวมถึงจำนวนคำสั่งซื้อทั้งหมด (สมมติว่ามาสก์การจัดรูปแบบเริ่มต้นสำหรับอินสแตนซ์ฐานข้อมูลปัจจุบันคือ DD-MON-YYYY):

เลือก company_name, SUM (inv_amt) จากบริษัท c, ใบแจ้งหนี้ i WHERE c.company_id = i.company_id AND i.invoice_date ระหว่าง "01-JAN-2001" และ "31-DEC-2001";

การรันคำสั่งนี้ใน SQL*Plus จะสร้างเอาต์พุตต่อไปนี้:

ชื่อ บริษัท ผลรวม (INV_AMT)
แอคมี เทอร์โบ อิงค์ 1000
วอชิงตัน แฮร์ บจก. 25.20

อย่างที่คุณเห็น SUM ส่วนหัวของคอลัมน์ (INV_AMT) ไม่เหมาะกับรายงานมากนัก แต่ก็เหมาะสำหรับการดูข้อมูลเพียงอย่างเดียว ตอนนี้เรามาเรียกใช้แบบสอบถามเดียวกันในโปรแกรม PL/SQL โดยใช้เคอร์เซอร์ที่ชัดเจนและเพิ่มนามแฝงของคอลัมน์:

ประกาศเคอร์เซอร์ comp_cur คือ SELECT c.name, SUM (inv_amt) Total_sales จากบริษัท C, ใบแจ้งหนี้ I WHERE C.company_id = I.company_id AND I.invoice_date BETWEEN "01-JAN-2001" AND "31-DEC-2001"; comp_rec comp_cur%ROWTYPE; เริ่มเปิด comp_cur; ดึงข้อมูล comp_cur เข้าสู่ comp_rec; จบ;

หากไม่มีนามแฝง ฉันจะไม่สามารถอ้างอิงคอลัมน์ในโครงสร้างบันทึก comp_rec ได้ ถ้าคุณมีนามแฝง คุณสามารถทำงานกับคอลัมน์จากการคำนวณได้เช่นเดียวกับที่คุณทำกับคอลัมน์คิวรีอื่นๆ:

หาก comp_rec.total_sales > 5000 แล้ว DBMS_OUTPUT.PUT_LINE (" คุณมีวงเงินเครดิตเกิน $5,000 ด้วย " || TO_CHAR (comp_rec.total_sales - 5,000, "$9999")); เอนดิฟ;

เมื่อเลือกแถวในเรคคอร์ดที่ประกาศด้วยแอตทริบิวต์ %ROWTYPE คอลัมน์ที่คำนวณแล้วสามารถเข้าถึงได้ด้วยชื่อเท่านั้น เนื่องจากโครงสร้างของเรคคอร์ดถูกกำหนดโดยโครงสร้างของเคอร์เซอร์เอง

การปิดเคอร์เซอร์ที่ชัดเจน

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

ไวยากรณ์คำสั่งปิด:

ปิดเคอร์เซอร์_ชื่อ;

ด้านล่างนี้คือเคล็ดลับและข้อควรพิจารณาที่สำคัญบางประการที่เกี่ยวข้องกับการปิดเคอร์เซอร์ที่ชัดเจน

  • หากมีการประกาศเคอร์เซอร์และเปิดในโพรซีเดอร์ อย่าลืมปิดเคอร์เซอร์เมื่อคุณดำเนินการเสร็จแล้ว มิฉะนั้นรหัสของคุณจะทำให้หน่วยความจำรั่ว ตามทฤษฎีแล้ว เคอร์เซอร์ (เช่นเดียวกับโครงสร้างข้อมูลอื่นๆ) ควรถูกปิดและทำลายโดยอัตโนมัติเมื่ออยู่นอกขอบเขต โดยทั่วไปแล้ว เมื่อออกจากโพรซีเดอร์ ฟังก์ชัน หรือบล็อกที่ไม่ระบุชื่อ PL/SQL จะปิดเคอร์เซอร์ที่เปิดอยู่ทั้งหมดภายในนั้น แต่กระบวนการนี้ใช้ทรัพยากรจำนวนมาก ดังนั้นด้วยเหตุผลด้านประสิทธิภาพ บางครั้ง PL/SQL จึงมีความล่าช้าในการระบุและปิดเคอร์เซอร์ที่เปิดอยู่ เคอร์เซอร์ประเภท REF CURSOR ตามคำจำกัดความ ไม่สามารถปิดโดยปริยายได้ สิ่งเดียวที่คุณมั่นใจได้ก็คือเมื่อบล็อก PL/SQL "ด้านนอกสุด" เสร็จสมบูรณ์และส่งคืนการควบคุมไปยัง SQL หรือโปรแกรมที่เรียกอื่น PL/SQL จะปิดเคอร์เซอร์ทั้งหมดที่เปิดโดยบล็อกนั้นหรือบล็อกที่ซ้อนกันโดยปริยาย ยกเว้น REF CURSOR . บทความ "การใช้เคอร์เซอร์ซ้ำใน PL/SQL static SQL" จาก Oracle Technology Network ให้การวิเคราะห์โดยละเอียดเกี่ยวกับวิธีการและเวลาที่ PL/SQL ปิดเคอร์เซอร์ บล็อกที่ไม่ระบุชื่อที่ซ้อนกันเป็นตัวอย่างของสถานการณ์ที่ PL/SQL ไม่ได้ปิดเคอร์เซอร์โดยปริยาย สำหรับข้อมูลที่น่าสนใจในหัวข้อนี้ โปรดดูบทความของ Jonathan Gennick เรื่อง “Does PL/SQL Implicitly Close Cursors?”
  • หากมีการประกาศเคอร์เซอร์ในแพ็คเกจที่ระดับแพ็คเกจและเปิดอยู่ในบล็อกหรือโปรแกรมบางโปรแกรม เคอร์เซอร์นั้นจะยังคงเปิดอยู่จนกว่าคุณจะปิดอย่างชัดเจนหรือจนกว่าเซสชันจะสิ้นสุดลง ดังนั้นหลังจากเสร็จสิ้นการทำงานด้วยเคอร์เซอร์ระดับแบตช์คุณควรปิดเคอร์เซอร์ทันทีด้วยคำสั่ง CLOSE (และควรทำเช่นเดียวกันในส่วนข้อยกเว้น):
เริ่มเปิด my_package.my_cursor; ... การทำงานกับเคอร์เซอร์ CLOSE my_package.my_cursor; ยกเว้นในกรณีที่ mypackage.my_cursor%ISOPEN ปิด my_package.my_cursor; เอนดิฟ; จบ;
  • เคอร์เซอร์สามารถปิดได้เฉพาะเมื่อเปิดไว้ก่อนหน้านี้เท่านั้น มิฉะนั้น ข้อยกเว้น INVALID_CURS0R จะถูกส่งออกไป สถานะเคอร์เซอร์ถูกตรวจสอบโดยใช้แอตทริบิวต์ %ISOPEN:
ถ้า company_cur%ISOPEN แล้วปิด company_cur; เอนดิฟ;
  • หากมีเคอร์เซอร์ที่เปิดอยู่มากเกินไปในโปรแกรม จำนวนเคอร์เซอร์อาจเกินค่าของพารามิเตอร์ฐานข้อมูล OPEN_CURSORS หากคุณได้รับข้อความแสดงข้อผิดพลาด ขั้นแรกตรวจสอบให้แน่ใจว่าเคอร์เซอร์ที่ประกาศในแพ็คเกจถูกปิดเมื่อไม่จำเป็นต้องใช้อีกต่อไป

คุณลักษณะเคอร์เซอร์ที่ชัดเจน

Oracle รองรับแอตทริบิวต์สี่รายการ (%FOUND, %NOTFOUND, %ISOPEN, %ROWCOUNTM) เพื่อรับข้อมูลเกี่ยวกับสถานะของเคอร์เซอร์ที่ชัดเจน การอ้างอิงแอ็ตทริบิวต์มีไวยากรณ์ต่อไปนี้: cursor%attribute

เคอร์เซอร์ในที่นี้คือชื่อของเคอร์เซอร์ที่ประกาศ

ค่าที่ส่งคืนโดยแอตทริบิวต์เคอร์เซอร์ที่ชัดเจนจะแสดงในตาราง 1.

ตารางที่ 1.คุณลักษณะเคอร์เซอร์ที่ชัดเจน

ค่าของแอตทริบิวต์เคอร์เซอร์ก่อนและหลังดำเนินการต่างๆ จะแสดงในตาราง 2.

เมื่อทำงานกับแอตทริบิวต์เคอร์เซอร์ที่ชัดเจน ให้พิจารณาสิ่งต่อไปนี้:

  • หากคุณพยายามเข้าถึงแอตทริบิวต์ %FOUND, %NOTFOUND หรือ %ROWCOUNT ก่อนที่จะเปิดเคอร์เซอร์หรือหลังจากปิดแล้ว Oracle จะส่งข้อผิดพลาด CURSOR ที่ไม่ถูกต้อง (ORA-01001)
  • ถ้าครั้งแรกที่คำสั่ง FETCH ถูกดำเนินการ ชุดแถวผลลัพธ์จะว่างเปล่า แอ็ตทริบิวต์เคอร์เซอร์ส่งคืนค่าต่อไปนี้: %FOUND = FALSE , %NOTFOUND = TRUE และ %ROWCOUNT = 0
  • เมื่อใช้ BULK COLLECT แอตทริบิวต์ %ROWCOUNT จะส่งกลับจำนวนแถวที่ดึงข้อมูลในคอลเลกชันที่กำหนด

ตารางที่ 2.ค่าแอตทริบิวต์เคอร์เซอร์

การดำเนินการ %พบ %ไม่พบ %เปิด %ROWCOUNT
ก่อนเปิด ข้อยกเว้น
โอรา-01001
ข้อยกเว้น
โอรา-01001
เท็จ ข้อยกเว้น
โอรา-01001
หลังจากเปิด โมฆะ โมฆะ จริง 0
ก่อน FETCH ตัวอย่างแรก โมฆะ โมฆะ จริง 0
หลังจากตัวอย่างแรก
ดึงข้อมูล
จริง เท็จ จริง 1
ก่อนต่อมา
ดึงข้อมูล
จริง เท็จ จริง 1
หลังจาก FETCH ตามมา จริง เท็จ จริง ขึ้นอยู่กับข้อมูล
ก่อนตัวอย่าง FETCH สุดท้าย จริง เท็จ จริง ขึ้นอยู่กับข้อมูล
หลังจากตัวอย่าง FETCH สุดท้าย จริง เท็จ จริง ขึ้นอยู่กับข้อมูล
ก่อนปิด เท็จ จริง จริง ขึ้นอยู่กับข้อมูล
หลังจากปิด ข้อยกเว้น ข้อยกเว้น เท็จ ข้อยกเว้น

การใช้คุณลักษณะทั้งหมดเหล่านี้แสดงให้เห็นในตัวอย่างต่อไปนี้:

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

PL/SQL ช่วยให้คุณสามารถส่งพารามิเตอร์ไปยังเคอร์เซอร์ได้ พวกมันทำหน้าที่เหมือนกับพารามิเตอร์ของโมดูลซอฟต์แวร์รวมถึงฟังก์ชันเพิ่มเติมอีกหลายตัว

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

จำนวนพารามิเตอร์เคอร์เซอร์ไม่จำกัด เมื่อเรียก OPEN จะต้องระบุพารามิเตอร์ทั้งหมด (ยกเว้นที่มีค่าเริ่มต้น) สำหรับเคอร์เซอร์

เคอร์เซอร์ต้องการพารามิเตอร์เมื่อใด กฎทั่วไปที่นี่เหมือนกับขั้นตอนและฟังก์ชัน: หากคาดว่าจะใช้เคอร์เซอร์ในตำแหน่งที่แตกต่างกันและมีค่าต่างกันในส่วน WHERE ควรกำหนดพารามิเตอร์ให้ ลองเปรียบเทียบเคอร์เซอร์ที่มีและไม่มีพารามิเตอร์กัน ตัวอย่างเคอร์เซอร์ที่ไม่มีพารามิเตอร์:

เคอร์เซอร์ joke_cur คือชื่อ, หมวดหมู่, Last_used_date จากเรื่องตลก;

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

เคอร์เซอร์ joke_cur คือ SELECT ชื่อ, หมวดหมู่, Last_used_date จากเรื่องตลก WHERE category = "สามี";

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

เคอร์เซอร์พร้อมพารามิเตอร์

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

กระบวนการ expl_joke (main_category_in IN joke_category.category_id%TYPE) IS /* || เคอร์เซอร์พร้อมรายการพารามิเตอร์ที่ประกอบด้วย || จากพารามิเตอร์สตริงเดียว */ CURSOR joke_cur (category_in IN VARCHAR2) คือ SELECT ชื่อ, หมวดหมู่, Last_used_date จาก Joke WHERE category = UPPER (category_in); joke_rec joke_cur%ROWTYPE; BEGIN /* ตอนนี้เมื่อเปิดเคอร์เซอร์ อาร์กิวเมนต์จะถูกส่งผ่านไป */ OPEN joke_cur (main_category_in); ดึง joke_cur เข้าสู่ joke_rec;

ระหว่างชื่อเคอร์เซอร์และคีย์เวิร์ด IS ขณะนี้มีรายการพารามิเตอร์ ค่า HUSBAND แบบฮาร์ดโค้ดในส่วนคำสั่ง WHERE ถูกแทนที่ด้วยการอ้างอิงถึงพารามิเตอร์ UPPER (category_in) เมื่อคุณเปิดเคอร์เซอร์ คุณสามารถตั้งค่าเป็น HUSBAND , สามี หรือ HuSbAnD - เคอร์เซอร์จะยังคงทำงานอยู่ ชื่อของหมวดหมู่ที่เคอร์เซอร์ควรส่งคืนแถวตารางตลกจะถูกระบุในคำสั่ง OPEN (ในวงเล็บ) ในรูปแบบตัวอักษร ค่าคงที่ หรือนิพจน์ เมื่อเปิดเคอร์เซอร์ คำสั่ง SELECT จะถูกแยกวิเคราะห์และพารามิเตอร์จะเชื่อมโยงกับค่า ชุดผลลัพธ์ของแถวจะถูกกำหนด และเคอร์เซอร์ก็พร้อมสำหรับการดึงข้อมูล

การเปิดเคอร์เซอร์ด้วยตัวเลือก

สามารถเปิดเคอร์เซอร์ใหม่เพื่อระบุหมวดหมู่ใดก็ได้:

เปิด joke_cur(Jokes_pkg.category); เปิด joke_cur("สามี"); เปิด joke_cur("นักการเมือง"); เปิด joke_cur (Jokes_pkg.relation || "-ในกฎหมาย");

พารามิเตอร์เคอร์เซอร์มักใช้ในส่วนคำสั่ง WHERE แต่สามารถอ้างอิงถึงที่อื่นในคำสั่ง SELECT:

ประกาศเคอร์เซอร์ joke_cur (category_in ใน ARCHAR2) คือชื่อที่เลือก, category_in, Last_used_date จากเรื่องตลก WHERE category = UPPER (category_in);

แทนที่จะอ่านหมวดหมู่จากตาราง เราเพียงแค่แทนที่พารามิเตอร์ category_in ลงในรายการที่เลือก ผลลัพธ์ยังคงเหมือนเดิมเนื่องจากส่วนคำสั่ง WHERE จำกัดหมวดหมู่ตัวอย่างไว้ที่ค่าพารามิเตอร์

ขอบเขตพารามิเตอร์เคอร์เซอร์

ขอบเขตของพารามิเตอร์เคอร์เซอร์ถูกจำกัดไว้ที่เคอร์เซอร์นั้น ไม่สามารถอ้างอิงพารามิเตอร์เคอร์เซอร์ภายนอกคำสั่ง SELECT ที่เชื่อมโยงกับเคอร์เซอร์ได้ ตัวอย่าง PL/SQL ต่อไปนี้ไม่ได้คอมไพล์เนื่องจาก program_name ไม่ใช่ตัวแปรท้องถิ่นในบล็อก นี่คือพารามิเตอร์เคอร์เซอร์อย่างเป็นทางการที่กำหนดไว้ภายในเคอร์เซอร์เท่านั้น:

ประกาศเคอร์เซอร์ scariness_cur (program_name VARCHAR2) คือผลรวมที่เลือก (scary_level) Total_scary_level จาก tales_from_the_crypt โดยที่ prog_name = program_name; BEGIN program_name:= "THE BREATHING MUMMY"; /* ลิงก์ไม่ถูกต้อง */ OPEN scariness_cur (program_name); .... ปิด Scariness_cur; จบ;

โหมดพารามิเตอร์เคอร์เซอร์

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

ค่าพารามิเตอร์เริ่มต้น

พารามิเตอร์เคอร์เซอร์สามารถกำหนดค่าเริ่มต้นได้ ตัวอย่างของเคอร์เซอร์ที่มีค่าพารามิเตอร์เริ่มต้น:

CURSOR emp_cur (emp_id_in NUMBER:= 0) คือ SELECT Employee_id, emp_name จากพนักงาน WHERE Employee_id = emp_id_in;

เนื่องจากพารามิเตอร์ emp_id_in มีค่าเริ่มต้น จึงสามารถละเว้นได้ในคำสั่ง FETCH ในกรณีนี้เคอร์เซอร์จะส่งคืนข้อมูลเกี่ยวกับพนักงานด้วยรหัส 0


เคอร์เซอร์คือลิงก์ไปยังพื้นที่หน่วยความจำตามบริบท ในการใช้งานภาษาการเขียนโปรแกรม SQL บางอย่าง (Oracle, Microsoft SQL Server) - ชุดผลลัพธ์ที่ได้รับเมื่อดำเนินการค้นหาและตัวชี้บันทึกปัจจุบันที่เกี่ยวข้อง ฉันจะบอกว่าเคอร์เซอร์เป็นตารางเสมือนที่แสดงถึงการจัดเก็บข้อมูลทางเลือก ในกรณีนี้ เคอร์เซอร์ช่วยให้คุณเข้าถึงข้อมูลได้เหมือนกับว่าเป็นข้อมูลของอาร์เรย์ปกติ
เคอร์เซอร์ถูกใช้ในขั้นตอนการจัดเก็บ ทฤษฎีพอแล้ว ลองดูตัวอย่าง:
เรามีฐานข้อมูล (ฐานข้อมูลไม่ค่อยดีนิดหน่อย นี่เป็นหนึ่งในผลงานในห้องปฏิบัติการของฉัน แต่ครูฐานข้อมูลของเรายืนยันโครงสร้างนี้)
/*ข้อมูลธนาคาร*/
สร้างตาราง `ธนาคาร` (

`ชื่อธนาคาร` VARCHAR (50) COLLATE utf8_bin ไม่ใช่ค่าเริ่มต้นที่เป็นโมฆะ ""


คีย์หลัก (`BankId`)

)เครื่องยนต์=อินโนดีบี
ชุดอักขระ "utf8" เรียงกัน "utf8_bin" ;
/*ข้อมูลเกี่ยวกับเงินฝาก */
สร้างตาราง `การกระจายทางธนาคาร` (
`BankId` จำนวนเต็ม (11) ไม่เป็นโมฆะ
`จำนวนเต็มถาวร (11) ค่าเริ่มต้น NULL
`จำนวนการมีส่วนร่วม` ทศนิยม (10,0) ไม่เป็นโมฆะ
`ClientId` จำนวนเต็ม (11) ไม่เป็นโมฆะ
คีย์หลัก(`BankId`, `ClientId`),
คีย์ `BankId` (`BankId`)
คีย์ `ClientId` (`ClientId`)
ข้อจำกัด `bankdistribution_fk` คีย์ต่างประเทศ (`BankId`) การอ้างอิง `bank` (`BankId`)
ข้อจำกัด `bankdistribution_fk1` คีย์ต่างประเทศ (`ClientId`) การอ้างอิง `client` (`ClientId`)
)เครื่องยนต์=อินโนดีบี
/*ข้อมูลเกี่ยวกับนักลงทุน*/
สร้างตาราง `ลูกค้า` (
`ClientId` จำนวนเต็ม (3) ไม่เป็นโมฆะ AUTO_INCREMENT
`CreditCardId` BIGINT(10) ไม่เป็นโมฆะ
`นามสกุล` VARCHAR (50) COLLATE utf8_bin ไม่ใช่ค่าเริ่มต้น "" ,
`ชื่อ` VARCHAR (50) COLLATE utf8_bin ไม่เป็นค่าเริ่มต้น ""
`ชื่อ` VARCHAR (50) COLLATE utf8_bin ไม่เป็นค่าเริ่มต้น "" ,
`โทรศัพท์` VARCHAR (50) COLLATE utf8_bin ไม่เป็นค่าเริ่มต้น ""
`ที่อยู่ ` VARCHAR (50) COLLATE utf8_bin ไม่เป็นค่าเริ่มต้น "" ,
`SafeId` จำนวนเต็ม (5) ไม่เป็นโมฆะ
คีย์หลัก(`ClientId`, `CreditCardId`),
คีย์ `รหัสลูกค้า` (`รหัสลูกค้า`)

)เครื่องยนต์=อินโนดีบี
AUTO_INCREMENT=ชุดอักขระ 11 ตัว "utf8" COLLATE "utf8_bin"

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

เลือก `ธนาคาร`* จาก `ธนาคาร` จำกัดจำนวน THE_RECORD_WE NEED,1
. ดังนั้น เมื่อใช้ LIMIT WE NEED_RECORD NUMBER, 1 เราจะแยกแต่ละระเบียนในลูปจากตารางธนาคารและดำเนินการตามที่เราต้องการ ในขณะที่เพิ่มค่าของ WE NEED_RECORD NUMBER ขึ้น 1 ตอนนี้เราจะทำเช่นเดียวกัน แต่ใช้ เคอร์เซอร์
เริ่ม
/* ตัวแปรที่เราดึงข้อมูลออกมา */
ประกาศจำนวนเต็ม vBankId ;
ประกาศ vBankName VARCHAR(50);
ประกาศ vAddress VARCHAR(50);
ประกาศ vPhone VARCHAR (50);
/* ตัวแปรแฮดเลอร์ - a*/
ประกาศค่าเริ่มต้นจำนวนเต็มเสร็จสิ้น 0;
/*ประกาศเคอร์เซอร์*/
ประกาศเคอร์เซอร์ BankCursor เพื่อเลือก `bank`.`BankId`,`bank`.`BankName`,`bank`.`Address`,`bank`.`Phone`, จาก `bank` โดยที่ 1;
/*วัตถุประสงค์ของ HANDLER ซึ่งจะอธิบายด้านล่าง*/
ประกาศตัวจัดการต่อสำหรับ SQLSTATE "02000" SET เสร็จสิ้น = 1;
/* เปิดเคอร์เซอร์ */
เปิดเคอร์เซอร์ธนาคาร;
/*ดึงข้อมูล*/
ในขณะที่ทำเสร็จ = 0 DO

เราดำเนินการตามที่เราต้องการ
สิ้นสุดในขณะที่ ;
/*ปิดเคอร์เซอร์*/
ปิดเคอร์เซอร์ธนาคาร;
จบ ;

* ซอร์สโค้ดนี้ถูกเน้นด้วย Source Code Highlighter

ข้อผิดพลาด: 1329 SQLSTATE: 02000 (ER_SP_FETCH_NO_DATA)

ข้อความ: ไม่มีข้อมูล - ดึง เลือก หรือประมวลผลแถวเป็นศูนย์

SQLSTATE: 02000 เริ่มทำงานเมื่อถึงจุดสิ้นสุดของเคอร์เซอร์ หรือเมื่อการเลือกหรืออัปเดตส่งคืนสตริงว่าง

บรรทัดถัดไปเราประกาศเคอร์เซอร์ DECLARE cursor_name CURSOR FOR select_statement;
เปิดเคอร์เซอร์ เปิด cursor_name;
จากนั้นจนกว่าเราจะไปถึงจุดสิ้นสุดของเคอร์เซอร์ (ในขณะที่ทำ = 0 DO) เราจะแยกข้อมูลและประมวลผล
คุณต้องปิดเคอร์เซอร์ก่อนที่จะออกจากขั้นตอนการจัดเก็บ ปิด cursor_name;

ดูเหมือนจะไม่ซับซ้อน แต่มีข้อผิดพลาดมากมายที่เกี่ยวข้องกับ SQLSTATE "02000"

ในขณะที่ทำเสร็จ = 0 DO
ดึง BankCursor เข้าสู่ vBankId, vBankName, vAddress, vPhone;

เลือก (ContributeAmount) ลงใน vContributeAmountSUM จากการกระจายทางธนาคาร โดยที่ BankId = vBankId จำกัด 1;
เราดำเนินการบางอย่าง
สิ้นสุดในขณะที่ ;

* ซอร์สโค้ดนี้ถูกเน้นด้วย Source Code Highlighter


ทุกอย่างเรียบร้อยดีและถูกต้องจากมุมมองทางไวยากรณ์ แต่จากมุมมองเชิงตรรกะไม่มี อาจเกิดขึ้นได้ว่าผู้ฝากเงินยังไม่ได้เปิดบัญชีในบางธนาคาร ดังนั้นสำหรับเลือก (ContributeAmount) เข้าสู่ vContributeAmountSUM จากการกระจายของธนาคาร โดยที่ BankId = vBankId จำกัด 1; SQLSTATE: 02000 จะเริ่มการทำงาน ตัวแปรที่ทำเสร็จแล้วจะถูกตั้งค่าเป็น 1 และลูป while จะสิ้นสุดเร็วกว่าที่เราคาดไว้ สิ่งนี้สามารถหลีกเลี่ยงได้โดยทำดังต่อไปนี้
ในขณะที่ทำเสร็จ = 0 DO
ดึง BankCursor เข้าสู่ vBankId, vBankName, vAddress, vPhone;
/* แยกจำนวนเงินฝากใด ๆ ให้กับธนาคาร */


ถ้า (vContributeAmountSUM > 0) แล้ว
/* แยกจำนวนเงินฝากใด ๆ ให้กับธนาคาร */

สิ้นสุดถ้า ;
เราดำเนินการบางอย่าง
สิ้นสุดในขณะที่ ;

* ซอร์สโค้ดนี้ถูกเน้นด้วย Source Code Highlighter


ในคำขอแรก เราจะตรวจสอบว่ามีส่วนสนับสนุนหรือไม่ (หากไม่มี จากนั้น vContributeAmountSUM == 0) และหากมี เราจะดึงข้อมูลเท่านั้น

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

ประกาศเคอร์เซอร์ ClientSummCursor สำหรับผลรวมที่เลือก (`bankdistribution`.`ContributeAmount`), `bankdistribution`.`ClientId` จาก `bankdistribution` เข้าร่วมภายในไคลเอนต์บน (client.ClientId = bankdistribution.`ClientId`) โดยที่ 1 กลุ่มโดย `bankdistribution` `รหัสลูกค้า`;

เปิด ClientSummCursor;
ในขณะที่ทำเสร็จ = 0 DO
ดึง BankCursor เข้าสู่ vBankId, vBankName, vAddress, vPhone;
/* แยกจำนวนเงินฝากใด ๆ ให้กับธนาคาร */
เลือกจำนวน(ContributeAmount) ลงใน vContributeAmountSUM จากการกระจายทางธนาคาร โดยที่ BankId = vBankId จำกัด 1;
/* ตรวจสอบว่ามีเงินฝากในธนาคารนี้จริงหรือไม่ */
ถ้า (vContributeAmountSUM > 0) แล้ว
/* แยกจำนวนเงินฝากใด ๆ ให้กับธนาคาร */
เลือก ContributeAmount ลงใน vContributeAmountSUM จากการกระจายทางธนาคาร โดยที่ BankId = ขีดจำกัด vBankId 1;
สิ้นสุดถ้า ;


เราดำเนินการบางอย่าง
สิ้นสุดในขณะที่ ;

* ซอร์สโค้ดนี้ถูกเน้นด้วย Source Code Highlighter

สถานการณ์เดียวกันอาจเกิดขึ้นเมื่อข้อมูลในเคอร์เซอร์ ClientSummCursor สิ้นสุดเร็วกว่าข้อมูลใน BankCursor, SQLSTATE: 02000 ถูกทริกเกอร์, ตัวแปรที่ทำเสร็จแล้วถูกตั้งค่าเป็น 1 และลูป while สิ้นสุดเร็วกว่าที่เราคาดไว้ สิ่งนี้สามารถหลีกเลี่ยงได้โดยทำดังต่อไปนี้

เปิด ClientSummCursor;
ในขณะที่ทำเสร็จ = 0 DO
ดึง BankCursor เข้าสู่ vBankId, vBankName, vAddress, vPhone;
/* แยกจำนวนเงินฝากใด ๆ ให้กับธนาคาร */
เลือกจำนวน(ContributeAmount) ลงใน vContributeAmountSUM จากการกระจายทางธนาคาร โดยที่ BankId = vBankId จำกัด 1;
/* ตรวจสอบว่ามีเงินฝากในธนาคารนี้จริงหรือไม่ */
ถ้า (vContributeAmountSUM > 0) แล้ว
/* แยกจำนวนเงินฝากใด ๆ ให้กับธนาคาร */
เลือก ContributeAmount ลงใน vContributeAmountSUM จากการกระจายทางธนาคาร โดยที่ BankId = ขีดจำกัด vBankId 1;
สิ้นสุดถ้า ;
/* ก่อนที่จะแยกข้อมูลจากเคอร์เซอร์ตัวที่สอง ให้จำสถานะ sqlstate */
SET old_status = เสร็จสิ้น;
/* ดึงข้อมูลที่เราต้องการ */
ดึง ClientSummCursor เข้าสู่ vSum, vClientId;
/* ตรวจสอบว่าข้อมูลถูกดึงมาหรือไม่ และ sqlstate 0200 ล้มเหลวหรือไม่ */
ถ้า (เสร็จสิ้น = 0) แล้ว
เราดำเนินการบางอย่าง
สิ้นสุดถ้า ;
/* ก่อนสิ้นสุด while ให้คืนค่าของตัวแปรที่ทำเสร็จแล้ว */
ตั้งค่าเสร็จแล้ว = old_status;
สิ้นสุดในขณะที่ ;

* ซอร์สโค้ดนี้ถูกเน้นด้วย Source Code Highlighter

ขอบคุณทุกคนที่อ่านมาจนถึงตอนนี้ ฉันหวังว่าสิ่งนี้จะเป็นประโยชน์กับใครบางคน

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

เคอร์เซอร์ช่วยให้คุณทำงานกับแถวของตารางโดยระบุหมายเลขซีเรียลในชุดข้อมูล

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

วงจรชีวิตของเคอร์เซอร์:

การสร้างเคอร์เซอร์:ประกาศ<имя курсора>[ ไม่รู้สึก ] [ เลื่อน ] เคอร์เซอร์เพื่อ< SELECT -оператор>สำหรับ (อ่านอย่างเดียว | อัปเดต)

ในที่นี้ คีย์เวิร์ด INSENSITIVE หมายความว่าเคอร์เซอร์จะเป็นแบบคงที่ (ภาพรวมของข้อมูล) ในขณะที่ตามค่าเริ่มต้น เคอร์เซอร์จะถูกสร้างขึ้นแบบไดนามิก (การดึงข้อมูลจะดำเนินการทุกครั้งที่มีการเข้าถึงแถว) คีย์เวิร์ด SCROLL หมายความว่าเคอร์เซอร์สามารถเลื่อนไปในทิศทางใดก็ได้ มิฉะนั้นเคอร์เซอร์จะถูกสร้างขึ้นเป็นเคอร์เซอร์ "ตามลำดับ"

เคอร์เซอร์เปิด:เปิด [ทั่วโลก]<имя курсора>. เคอร์เซอร์ที่ระบุเป็น GLOBAL จะไม่ถูกลบโดยอัตโนมัติเมื่อขั้นตอนหรือแพ็คเกจที่ถูกเรียกว่าสิ้นสุด

การอ่านข้อมูล : ดึงข้อมูล [[ ถัดไป | ก่อน | ครั้งแรก | สุดท้าย | สัมบูรณ์ n | n ที่เกี่ยวข้อง ] จาก ] [ ทั่วโลก ]<имя курсора>[INTO@variable_name,...] SQL Server 2000 อนุญาตให้คุณอ่านเพียงแถวเดียวจากเคอร์เซอร์ คีย์เวิร์ด FIRST คือการส่งคืนแถวแรกของเคอร์เซอร์ LAST – บรรทัดสุดท้ายของเคอร์เซอร์ NEXT – บรรทัดถัดไปหลังจากบรรทัดปัจจุบัน บรรทัดที่ส่งคืนจะกลายเป็นบรรทัดปัจจุบัน PRIOR – ก่อนหน้าก่อนปัจจุบัน; ABSOLUTE n – ส่งคืนบรรทัดด้วยหมายเลขลำดับสัมบูรณ์ในเคอร์เซอร์ RELATIVE – n บรรทัดหลังจากบรรทัดปัจจุบัน ข้อมูลคอลัมน์จะถูกจัดเก็บไว้ในตัวแปรที่ระบุแต่ละตัวตามลำดับที่แสดง

เปลี่ยนข้อมูล:รันคำสั่ง UPDATE ด้วยไวยากรณ์ที่ออกแบบมาเพื่อทำงานกับเคอร์เซอร์

การลบข้อมูล:รันคำสั่ง DELETE ด้วยไวยากรณ์ที่ออกแบบมาเพื่อทำงานกับเคอร์เซอร์

การปิดเคอร์เซอร์:ปิด [ทั่วโลก]<имя курсора>

ปล่อยเคอร์เซอร์:จัดสรรคืน [ทั่วโลก]<имя курсора>

ตัวอย่างการใช้เคอร์เซอร์:

ประกาศ fo_curs เคอร์เซอร์คงที่สำหรับ

เลือก name_rus จากสำหรับ ORDER BY name_rus

ประกาศ @name varchar(50)

ดึงข้อมูลจาก fo_curs เข้าสู่ @name ก่อน

ในขณะที่ @@FETCH_STATUS=0

ดึงข้อมูลถัดไปจาก fo_curs เข้าสู่ @name

ยกเลิกการจัดสรร fo_curs

2.7. มั่นใจในความปลอดภัยของข้อมูลและความสมบูรณ์ใน Microsoft SQL Server การจัดการฐานข้อมูล บทบาท การกำหนดสิทธิ์ให้กับผู้ใช้ (GRANT, DENY, REVOKE) วิธีการและเทคโนโลยีสำหรับการปกป้องข้อมูลใน SQL Server

การรักษาความปลอดภัยและการดูแลระบบเซิร์ฟเวอร์ SQL .

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

การจัดการฐานข้อมูล

หากต้องการสร้างฐานข้อมูลโดยใช้ TSQL ให้ใช้คำสั่ง CREATE DATABASE แต่โดยปกติแล้วความสามารถของ SQL Server Management Studio จะถูกนำมาใช้เพื่อจุดประสงค์นี้ มีการดำเนินการฐานข้อมูลค่อนข้างน้อยที่กำหนดไว้ใน SQL Server: การเพิ่ม (ลด) ขนาดไฟล์, การเปลี่ยนแปลงการกำหนดค่า (คำสั่ง ALTER), การแนบและการแยกออก, การโอนความเป็นเจ้าของ, การเปลี่ยนชื่อ, การดูคุณสมบัติและสุดท้ายคือการลบ (DROP DATABASE)

เช่นเดียวกับเซิร์ฟเวอร์ฐานข้อมูลส่วนใหญ่ SQL Server มีผู้ใช้ที่มีสิทธิ์การดูแลระบบเต็มรูปแบบ - นี่คือ ผู้ดูแลระบบหรือ 'sa'. หลังจากการติดตั้งเซิร์ฟเวอร์ครั้งแรก รหัสผ่าน sa จะว่างเปล่า ผู้ใช้ที่สร้างฐานข้อมูลใหม่จะกลายเป็นเจ้าของโดยอัตโนมัติ ('dbo' - เจ้าของฐานข้อมูล) ในขณะที่สร้างฐานข้อมูล ผู้ใช้ "แขก" จะถูกกำหนดด้วย หากบัญชีผู้ใช้ไม่ได้รับการแมปอย่างชัดเจนกับผู้ใช้ของ ฐานข้อมูลเฉพาะ ผู้ใช้จะได้รับอนุญาตให้เข้าถึงโดยนัยโดยใช้ชื่อแขก แขก แขกมักถูกห้าม

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

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

db_owner. มีสิทธิทั้งหมดในฐานข้อมูล

Db_accessadmin. สามารถเพิ่มหรือลบผู้ใช้ได้

db_securityadmin. จัดการสิทธิ์ วัตถุ บทบาท และผู้ใช้ทั้งหมด

Db_ddladmin. สามารถดำเนินการคำสั่ง DDL ทั้งหมด ยกเว้น GRANT, DENY, REVOKE

Db_backupoperator. Archiver สามารถรันคำสั่งได้ ข้อมูล

db_datareader. บางทีก็ดู.. ข้อมูลใด ๆ ในตารางใด ๆ

db_datawriter บางทีอาจมีการปรับเปลี่ยน ข้อมูลใด ๆ ในตารางใด ๆ

Db_denydatareader ต้องห้าม ดู รัก ข้อมูลในใด ๆ ตาราง

Db_denydatawriter ห้ามแก้ไขข้อมูลใดๆ ในตารางใดๆ

การกำหนดสิทธิ์ให้กับผู้ใช้ พื้นฐานของการรักษาความปลอดภัยของ SQL Server คือ (1) บัญชี; (2) ผู้ใช้; (3) บทบาท; (4) กลุ่ม

เมื่อผู้ใช้เชื่อมต่อกับ SQL Server การกระทำที่เขาสามารถทำได้จะถูกกำหนดโดยสิทธิ์ที่มอบให้แก่เขาในฐานะผู้ใช้และสมาชิกของบทบาท สิทธิ์จะได้รับจากผู้ดูแลระบบ DBMS เจ้าของฐานข้อมูล หรือเจ้าของออบเจ็กต์ฐานข้อมูลเฉพาะ สิทธิ์ในฐานข้อมูลสามารถแบ่งออกเป็นสามประเภท: (1) สิทธิ์ในการเข้าถึงวัตถุฐานข้อมูล; (2) สิทธิ์ในการรันคำสั่ง TSQL; (3) สิทธิโดยนัย เซิร์ฟเวอร์อนุญาตให้คุณโอนความเป็นเจ้าของจากผู้ใช้รายหนึ่งไปยังอีกรายหนึ่ง

คำสั่งต่อไปนี้ใช้ในการจัดการสิทธิ์ของผู้ใช้ในการเข้าถึงวัตถุฐานข้อมูล:

ยินยอม(ทั้งหมด |< вид действия >,…}

( บน (<имя таблицы или представления>} [(<имя столбца>,…)]

| บน (< имя хранимой процедуры >}

| บน (< имя пользовательской функции >}

ถึง ( สาธารณะ |<имя объекта системы безопасности>,…}

[ เช่น<имя группы> | <имя роли>]

การกำหนดสิทธิ์ให้กับผู้ใช้, ที่ไหน

ทั้งหมด – ผู้ใช้จะได้รับสิทธิ์ที่เป็นไปได้ทั้งหมด มิฉะนั้นจะระบุ

<вид действия>– สิทธิ์ในการดำเนินการที่มีให้กับผู้ใช้ ได้แก่ :

SELECT – สำหรับมุมมอง สำหรับคอลัมน์ตาราง และสำหรับตาราง (มุมมอง)

INSERT – เพื่อเพิ่มสำหรับตาราง (มุมมอง) โดยรวม

UPDATE – สำหรับการเปลี่ยนแปลง สำหรับคอลัมน์ตาราง และสำหรับตาราง (มุมมอง)

DELETE – เพื่อลบตาราง (มุมมอง) โดยรวม

EXECUTE – เพื่อดำเนินการตามขั้นตอนที่เก็บไว้

การอ้างอิง – ความสามารถในการอ้างอิงถึงวัตถุที่ระบุ (รวมเป็นส่วนหนึ่งของคีย์ต่างประเทศ)

<имя объекта системы безопасности>– บัญชี SQL Server, ผู้ใช้โดเมน Windows; สาธารณะ – สำหรับผู้ใช้ทุกคน

ด้วยตัวเลือกการให้สิทธิ์ - อนุญาตให้ผู้ใช้ที่ได้รับสิทธิ์ในปัจจุบันสามารถกำหนดสิทธิ์การเข้าถึงวัตถุให้กับผู้ใช้รายอื่น

เช่น<имя группы> | <имя роли>– การมีส่วนร่วมของผู้ใช้ในบทบาทที่ได้รับความสามารถในการให้สิทธิ์แก่ผู้ใช้รายอื่น

ให้สิทธิ์เลือกแก่ผู้เขียนสู่สาธารณะ

ให้สิทธิ์แทรก อัปเดต ลบผู้เขียนถึง Mary, John, Tom

ให้สิทธิ์เลือกบน Plan_Data ให้กับการบัญชีด้วยตัวเลือกการให้สิทธิ์

ให้สิทธิ์เลือก Plan_Data ให้กับ Jack AS Accounting

แจ็คไม่ใช่สมาชิกของบทบาทการบัญชี แต่มีคนในบทบาทนั้นสามารถให้สิทธิ์ได้

ปฏิเสธ(ทั้งหมด |< вид действия >,…}

( บน (<имя таблицы или представления>} [(<имя столбца>,…)]

| บน (<имя хранимой процедуры>}

| บน (<имя пользовательской функции>}

ถึง ( สาธารณะ |<имя объекта системы безопасности>,…}

การปฏิเสธการเข้าถึงผู้ใช้ไปยังวัตถุฐานข้อมูล CASCADE เพิกถอนสิทธิ์ไม่เพียงแต่จากผู้ใช้รายนี้เท่านั้น แต่ยังรวมถึงทุกคนที่เขาให้สิทธิ์ด้วย

ตัวอย่าง (บน คำสั่งห้าม TSQL):

ปฏิเสธการสร้างตารางให้กับ Jack CASCADE

ทีม ถอนใช้เพื่อปฏิเสธการเข้าถึงวัตถุฐานข้อมูลโดยปริยาย ไวยากรณ์เหมือนกับคำสั่ง DENY การปฏิเสธโดยนัยนั้นคล้ายคลึงกับการปฏิเสธการเข้าถึง ยกเว้นว่าจะใช้เฉพาะในระดับที่กำหนดไว้เท่านั้น ตัวอย่าง: ผู้ใช้ Jack ซึ่งเป็นสมาชิกของบทบาท GoodUsers ได้รับสิทธิ์ในการเข้าถึงตาราง XFiles หาก REVOKE ถูกปฏิเสธสำหรับบทบาท GoodUsers ในการเข้าถึงตารางนี้ Jack ยังคงสามารถเข้าถึงตารางนี้ได้เนื่องจากสิทธิ์สำหรับเขาถูกกำหนดไว้อย่างชัดเจน หากคุณใช้ REVOKE เป็นการส่วนตัว เขาจะเสียสิทธิ์ในการเข้าถึง XFiles

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

เทคโนโลยีการปกป้องข้อมูลใน MS SQL Server

1.กลไก จุดตรวจ- จุดตรวจสอบที่สร้างขึ้นหลังจาก ~ 60 วินาทีเพื่อเขียนหน้าที่อัพเดตลงดิสก์ (จุดตรวจสอบสามารถบังคับได้ด้วยคำสั่ง CHECKPOINT)

2. กลไกในตัวและภายนอกสำหรับการตรวจสอบความสมบูรณ์ของฐานข้อมูล (เปิดใช้งานโดยอัตโนมัติหรือเช่นยูทิลิตี้ DBCC - ตัวตรวจสอบความสอดคล้องของฐานข้อมูล - ด้วยตนเอง)

3. การทำสำเนาทางกายภาพ (หากอนุญาต) ของไฟล์ฐานข้อมูลโดยใช้ระบบปฏิบัติการ (รวมถึงกลไกของฮาร์ดไดรฟ์แบบมิเรอร์)

4. การสำรองฐานข้อมูลและบันทึกธุรกรรม - โดยการเขียนดัมพ์ฐานข้อมูลไปยังอุปกรณ์สำรองข้อมูล (เทปแม่เหล็กหรือฮาร์ดไดรฟ์)

5. การจำลองแบบ – ความสามารถในการทำซ้ำข้อมูลเป็นระยะ (ในบางกรณี พร้อมกัน) โดยถ่ายโอนข้อมูลจากเซิร์ฟเวอร์ SQL หนึ่งไปยังอีกเซิร์ฟเวอร์หนึ่ง

6. การเข้ารหัสการรับส่งข้อมูลระหว่างไคลเอนต์และเซิร์ฟเวอร์ รวมถึงการเข้ารหัสรหัสที่ใช้ในการทำงานกับออบเจ็กต์ฐานข้อมูล (ขั้นตอนที่เก็บไว้ ทริกเกอร์ ฯลฯ)

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

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

การทำงานกับเคอร์เซอร์มักเกี่ยวข้องกับขั้นตอนต่อไปนี้:

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

เคอร์เซอร์ถูกประกาศโดยใช้คำสั่ง DECLARE ซึ่งมีรูปแบบดังแสดงด้านล่าง ควรสังเกตว่าใน SQL Server ตัวดำเนินการนี้รองรับทั้งไวยากรณ์ของมาตรฐาน ISO SQL (ไม่ได้ระบุเวอร์ชันของมาตรฐานในเอกสารประกอบ) และไวยากรณ์โดยใช้ชุดส่วนขยายภาษา Transact-SQL CURSOR

สำหรับ select_statement

ไวยากรณ์ Transact-SQL แบบขยาย:

ประกาศเคอร์เซอร์_ชื่อเคอร์เซอร์

สำหรับ select_statement

]][;]

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

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

FORWARD_ONLY หมายความว่าคุณสามารถ "เลื่อน" ไปตามเคอร์เซอร์ไปข้างหน้าเท่านั้น (เฉพาะคำสั่ง FETCH NEXT เท่านั้นที่ใช้งานได้ ดูด้านล่าง) เช่น แต่ละรายการในเคอร์เซอร์สามารถประมวลผลได้มากที่สุดหนึ่งครั้ง หากระบุ FORWARD ONLY โดยไม่มีคีย์เวิร์ด STATIC, KEYSET หรือ DYNAMIC เคอร์เซอร์จะทำงานเป็นเคอร์เซอร์ DYNAMIC (ดูด้านล่าง) หากไม่ได้ระบุ FORWARD_ONLY หรือ SCROLL และหากไม่มีการระบุคำหลัก STATIC, KEYSET หรือ DYNAMIC ค่าเริ่มต้นจะเป็น FORWARD_ONLY

SCROLL หมายความว่าคุณสามารถ “เลื่อน” ไปรอบๆ เคอร์เซอร์ในทิศทางใดก็ได้ (FIRST, LAST, PRIOR, NEXT, RELATIVE, ABSOLUTE มีอยู่ในคำสั่ง FETCH) ไม่สามารถระบุตัวเลือก SCROLL ด้วยตัวเลือก FAST_FORWARD เคอร์เซอร์แบบคงที่, คีย์เซ็ต และไดนามิกมีค่าเริ่มต้นเป็น SCROLL

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

KEYSET – สำหรับเคอร์เซอร์ประเภทนี้ ชุดของค่าคีย์ที่ระบุบันทึกที่เลือกจะถูกเก็บไว้ในตารางชั่วคราว เมื่อคุณเลื่อนเคอร์เซอร์ ค่าของแอตทริบิวต์ที่ไม่ใช่คีย์จะถูกดึงมาจากตารางที่เกี่ยวข้อง ดังนั้นการเปลี่ยนแปลงในคอลัมน์ที่ไม่ใช่คีย์จะมองเห็นได้เมื่อคุณเลื่อนเคอร์เซอร์ หากแถวที่อยู่ในเคอร์เซอร์ถูกลบออกจากตารางแล้วตามเวลาที่ดึงข้อมูลโดยตัวดำเนินการ FETCH ตัวแปรบริการ @@ FETCH_STATUS จะส่งกลับค่า -2 แถวที่เพิ่มลงในตารางหลังจากเปิดเคอร์เซอร์จะไม่ปรากฏในเคอร์เซอร์ หากแบบสอบถามที่สร้างเคอร์เซอร์เกี่ยวข้องกับตารางอย่างน้อยหนึ่งตารางที่ไม่มีดัชนีเฉพาะ เคอร์เซอร์ประเภท KEYSET จะถูกแปลงเป็นประเภท STATIC

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

FAST_FORWARD เป็นประเภทเคอร์เซอร์ที่เร็วที่สุด ซึ่งช่วยให้คุณสามารถย้ายจากบรรทัดหนึ่งไปยังอีกบรรทัดหนึ่งได้เพียง "ไปข้างหน้า" เท่านั้น นี่คือประเภทเคอร์เซอร์เริ่มต้น (เมื่อละเว้นคำหลักเพิ่มเติม) มันเทียบเท่ากับเคอร์เซอร์ที่ประกาศด้วยพารามิเตอร์ FORWARD_ONLY และ READ_ONLY

READ_ONLY - กำหนดเคอร์เซอร์ "อ่านอย่างเดียว": การเปลี่ยนแปลงฐานข้อมูลไม่สามารถทำได้ผ่านเคอร์เซอร์ดังกล่าว

SCROLL_LOCKS หมายความว่า SQL Server จะล็อกแถวขณะที่อ่านลงในเคอร์เซอร์ เพื่อให้แน่ใจว่าสามารถอัปเดตหรือลบแถวเหล่านั้นได้ผ่านเคอร์เซอร์ประเภทนั้น

เคอร์เซอร์ที่ประกาศด้วยคีย์เวิร์ด OPTIMISTIC ไม่จำเป็นต้องมีการล็อกแถว และอนุญาตให้แก้ไขข้อมูลได้ หากการเปลี่ยนแปลงในตารางฐานเกิดขึ้นหลังจากอ่านข้อมูลในเคอร์เซอร์แล้ว การพยายามแก้ไขข้อมูลนั้นผ่านเคอร์เซอร์จะส่งผลให้เกิดข้อผิดพลาด

TYPE_WARNING ระบุว่าเมื่อเคอร์เซอร์ถูกแปลงจากประเภทที่ร้องขอไปเป็นประเภทอื่นโดยปริยาย (เช่น การแปลงเคอร์เซอร์ KEYSET เป็น STATIC ที่อธิบายไว้ข้างต้นเมื่อไม่มีดัชนีที่ไม่ซ้ำกันในตาราง) คำเตือนจะถูกส่งไปยังไคลเอนต์

Select_statement – ​​​​คำสั่ง SELECT ที่สร้างชุดผลลัพธ์ของเคอร์เซอร์

คำสั่ง FOR UPDATE ระบุคอลัมน์ในเคอร์เซอร์ที่ต้องการอัพเดต ถ้าของ column_name [, . . . n] ดังนั้นเฉพาะคอลัมน์ที่อยู่ในรายการเท่านั้นที่จะพร้อมสำหรับการเปลี่ยนแปลง หากไม่มีรายการคอลัมน์ การอัพเดตสามารถทำได้สำหรับคอลัมน์ทั้งหมด ยกเว้นในกรณีของการประกาศเคอร์เซอร์ด้วยพารามิเตอร์ READ_ONLY

หากต้องการเปิดและเติมเคอร์เซอร์ ให้ใช้คำสั่ง

เปิด (( cursor_name) ฉัน @cursor_variable)

เมื่อเปิด เคอร์เซอร์สามารถระบุด้วยชื่อ (cursor_name) หรือผ่านตัวแปรประเภท CURSOR (@cursor_variable) พารามิเตอร์ GLOBAL ระบุว่า cursor_name เป็นเคอร์เซอร์โกลบอล

หากต้องการเลื่อนผ่านชุดข้อมูลของเคอร์เซอร์และดึงข้อมูลเป็นค่าตัวแปร ให้ใช้คำสั่ง FETCH:

ดึงข้อมูล [

(( cursor_name] ฉัน @cursor_variable]

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

สิ่งสำคัญคือต้องทราบว่าหากเคอร์เซอร์เพิ่งเปิดขึ้น การดำเนินการ FETCH NEXT ครั้งแรกจะส่งผลให้มีการข้ามไปยังบันทึกแรกของเคอร์เซอร์

ตารางที่ 10.10

การนำทางชุดข้อมูลเคอร์เซอร์

ตัวแปรโกลบอล @@FETCH_STATUS ช่วยให้คุณค้นหาผลลัพธ์ของการดำเนินการคำสั่ง FETCH ครั้งล่าสุด:

O – การดำเนินการเสร็จสมบูรณ์แล้ว

  • -1 – การดำเนินการของผู้ปฏิบัติงานล้มเหลว หรือบรรทัดอยู่นอกชุดผลลัพธ์ (เคอร์เซอร์สิ้นสุด)
  • -2 – แถวที่เลือกหายไป เช่น หากในขณะที่ทำงานกับเคอร์เซอร์ประเภท "ไวต่อการเปลี่ยนแปลง" บันทึกปัจจุบันจะถูกลบออกจากฐานข้อมูล

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

ปิด (( cursor_name)|@cursor_variable )

คำสั่ง DEALLOCATE จะลบการเชื่อมโยงระหว่างเคอร์เซอร์กับชื่อหรือตัวแปร หากนี่คือนามสกุลหรือตัวแปรที่อ้างอิงเคอร์เซอร์ ตัวเคอร์เซอร์เองจะถูกลบและทรัพยากรใดๆ ที่ใช้จะถูกปล่อย:

DEALLOCATE (( cursor_name] | @cursor_variable) ลองพิจารณาตัวอย่างง่ายๆ ของการใช้เคอร์เซอร์ ที่นี่ ผู้แต่งและชื่อหนังสือที่ตีพิมพ์ไม่เร็วกว่าปี 2000 จะถูกเลือกจากตาราง หลังจากนั้นข้อมูลจะถูกส่งออกในลูปไปยังคำสั่ง SELECT - แต่ละครั้งจะมีหนึ่งบันทึกที่มีชื่อของตัวเอง คำอธิบายเพิ่มเติมได้รับจากความคิดเห็นในโค้ด:

/*ประกาศตัวแปร*/

ประกาศ @auth varchar(50), @title varchar(50)

โดยที่ >= 2000

/*เปิดเคอร์เซอร์แล้ว “เรียกใช้” ผ่านเคอร์เซอร์ โดยแสดงผู้แต่งและชื่อเรื่องโดยใช้คำสั่ง SELECT แยกต่างหาก*/

ดึงข้อมูลถัดไปจากเคอร์เซอร์ไปที่ @auth, @title

ในขณะที่ SSFETCH_STATUS = 0

ดึงข้อมูลถัดไปจากเคอร์เซอร์ไปที่ @auth, Stitle

/*ปิดเคอร์เซอร์แล้วปล่อย*/

เคอร์เซอร์ DEALLOCATE

ตามที่ระบุไว้ข้างต้น ตัวแปรประเภท CURSOR สามารถใช้แทนชื่อเคอร์เซอร์ได้ ด้านล่างนี้เป็นโค้ดที่คล้ายกันโดยใช้ตัวแปรเหล่านี้:

ประกาศ varchar ใต้ (50), varchar สิทธิ์ (50)

/*ประกาศตัวแปรประเภทเคอร์เซอร์*/

ประกาศเคอร์เซอร์ Scurl

ประกาศเคอร์เซอร์ CURSOR FAST_FORWARD

เลือกผู้แต่ง ชื่อเรื่องจาก dbo.Bookl

โดยที่ >= 2000

/*กำหนดค่าให้กับตัวแปรประเภทเคอร์เซอร์*/

SET Scurl = เคอร์เซอร์

ในขณะที่ SSFETCH_STATUS = 0

ดึงข้อมูลถัดไปจาก Scurl Into South, Stitle