Oracle PL/SQL Dynamic SQL Tutorial: Execute Immediate & DBMS_SQL
โก Smart sammanfattning
Dynamisk SQL i Oracle PL/SQL bygger och kรถr satser vid kรถrning, och anpassar frรฅgor till fรถrรคndrade krav genom tvรฅ metoder: Native Dynamic SQL med EXECUTE IMMEDIATE och OPEN-FOR, och det flexibla DBMS_SQL-paketet fรถr komplexa fall.

Vad รคr dynamisk SQL?
Dynamisk SQL รคr en programmeringsmetodik fรถr att generera och kรถra satser vid kรถrning. Den anvรคnds huvudsakligen fรถr att skriva generella och flexibla program dรคr SQL-satser skapas och kรถrs vid kรถrning baserat pรฅ kravet, till exempel nรคr tabellnamn, kolumnlistor eller WHERE-villkor inte รคr kรคnda fรถrrรคn programmet kรถrs.
Sรคtt att skriva dynamisk SQL
PL/SQL erbjuder tvรฅ sรคtt att skriva dynamisk SQL:
- NDS โ Native Dynamic SQL (satserna EXECUTE IMMEDIATE och OPEN-FOR)
- DBMS_SQL (ett medfรถljande paket)
Den allmรคnna regeln รคr enkel: om antalet och datatyperna fรถr in- och utdatavariablerna รคr kรคnda vid kompileringstillfรคllet, anvรคnd Native Dynamic SQL eftersom det รคr snabbare och krรคver mindre kod. Nรคr den informationen bara รคr kรคnd vid kรถrning, anvรคnd DBMS_SQL-paketet.
NDS (Native Dynamic SQL) โ Kรถr omedelbart
Native Dynamic SQL รคr det enklaste sรคttet att skriva dynamisk SQL. Det anvรคnder kommandot EXECUTE IMMEDIATE fรถr att skapa och kรถra SQL:en vid kรถrning. Fรถr att anvรคnda den hรคr metoden mรฅste datatypen och antalet variabler som anvรคnds vid kรถrning vara kรคnda i fรถrvรคg. Det ger ocksรฅ bรคttre prestanda och lรคgre komplexitet jรคmfรถrt med DBMS_SQL.
syntax
EXECUTE IMMEDIATE dynamic_sql_string [INTO {variable[, variable]... | record}] [USING [IN | OUT | IN OUT] bind_argument[, ...]] [RETURNING INTO bind_argument[, ...]];
- dynamisk_sql_strรคng: Ett strรคnguttryck (VARCHAR2 eller CHAR, inte NVARCHAR2/NCHAR) som innehรฅller en enda SQL-sats eller ett PL/SQL-block.
- INTO-klausul: Valfritt. Anvรคnds endast nรคr den dynamiska SQL-en รคr en SELECT-kod med en rad; den samlar in de returnerade vรคrdena i variabler eller en post. Varje vald kolumn behรถver en typkompatibel variabel.
- ANVรNDNINGSKLAUSUL: Valfritt. Tillhandahรฅller bindningsvariabler. Standardlรคget รคr IN; OUT och IN OUT anvรคnds fรถr att ta emot vรคrden tillbaka.
- ร TERVรNDNINGSKLAUSUL: Anvรคnds med DML-satser som innehรฅller en RETURNING-klausul fรถr att fรฅnga upp berรถrda radvรคrden i bindningsargument.
Exempel 1: I det hรคr exemplet hรคmtar vi data frรฅn emp-tabellen fรถr emp_no '1001' med hjรคlp av en NDS-sats med en bind-variabel.
DECLARE lv_sql VARCHAR2(500); lv_emp_name VARCHAR2(50); ln_emp_no NUMBER; ln_salary NUMBER; ln_manager NUMBER; BEGIN lv_sql := 'SELECT emp_name, emp_no, salary, manager FROM emp WHERE emp_no = :empno'; EXECUTE IMMEDIATE lv_sql INTO lv_emp_name, ln_emp_no, ln_salary, ln_manager USING 1001; DBMS_OUTPUT.PUT_LINE('Employee Name: ' || lv_emp_name); DBMS_OUTPUT.PUT_LINE('Employee Number: ' || ln_emp_no); DBMS_OUTPUT.PUT_LINE('Salary: ' || ln_salary); DBMS_OUTPUT.PUT_LINE('Manager ID: ' || ln_manager); END; /
Produktion
Employee Name : XXX Employee Number: 1001 Salary : 15000 Manager ID : 1000
Code Fรถrklaring:
- Raderna 2โ6: Deklarera variablerna.
- Linje 8: Ramar in SQL-koden vid kรถrning. SQL-koden innehรฅller bindningsvariabeln ':empno' i WHERE-villkoret.
- Raderna 9โ11: Kรถr den inramade SQL-kommandot med EXECUTE IMMEDIATE. INTO-klausulvariablerna innehรฅller de hรคmtade vรคrdena, och USING-klausulen anger vรคrdet fรถr bindningsvariabeln :empno.
- Raderna 12โ15: Visar de hรคmtade vรคrdena.
Anvรคnda dynamisk SQL fรถr DDL
Statisk PL/SQL kan inte kรถra DDL som CREATE, ALTER eller DROP direkt. EXECUTE IMMEDIATE lรถser detta genom att skapa kommandot som en strรคng, vilket ocksรฅ รคr praktiskt nรคr ett objektnamn anges vid kรถrning:
DECLARE l_table_name VARCHAR2(30) := 'my_table'; l_sql_stmt VARCHAR2(200); BEGIN l_sql_stmt := 'CREATE TABLE ' || l_table_name || ' (id NUMBER, name VARCHAR2(30))'; EXECUTE IMMEDIATE l_sql_stmt; END; /
Objektnamn (tabell, kolumn, schema) kan inte skickas som bindningsvariabler, sรฅ de mรฅste sammanfogas till strรคngen. Validera alltid sรฅdan inmatning, till exempel med DBMS_ASSERT.SIMPLE_SQL_NAME, fรถr att undvika SQL-injektion.
DBMS_SQL fรถr dynamisk SQL
PL/SQL tillhandahรฅller DBMS_SQL-paketet fรถr att arbeta med dynamisk SQL nรคr satsens struktur inte รคr kรคnd fรถrrรคn vid kรถrning. Processen att skapa och kรถra den dynamiska SQL-en innefattar fรถljande steg:
- รPPNA MARKรR: Den dynamiska SQL-funktionen kรถrs som en markรถrenFรถr att kรถra SQL-satsen mรฅste vi fรถrst รถppna markรถren.
- PARSE SQL: Parsa den dynamiska SQL-filen. Detta kontrollerar syntaxen och hรฅller frรฅgan redo att kรถras.
- BINDVARIABEL Vรคrden: Tilldela vรคrdena fรถr bindningsvariablerna, om nรฅgra.
- DEFINERA KOLUMN: Definiera varje kolumn med hjรคlp av dess relativa position i select-satsen.
- UTFรRA: Kรถr den analyserade frรฅgan.
- HรMTA VรRDEN: Hรคmta de exekverade vรคrdena.
- STรNG MARKรREN: Nรคr resultaten har hรคmtats, stรคng markรถren.
Exempel 1: I det hรคr exemplet hรคmtar vi data frรฅn emp-tabellen fรถr emp_no '1001' med hjรคlp av en DBMS_SQL-sats. EXCEPTION-blocket stรคnger markรถren รคven om ett fel uppstรฅr.
DECLARE lv_sql VARCHAR2(500); lv_emp_name VARCHAR2(50); ln_emp_no NUMBER; ln_salary NUMBER; ln_manager NUMBER; ln_cursor_id NUMBER; ln_rows_processed NUMBER; BEGIN lv_sql := 'SELECT emp_name, emp_no, salary, manager FROM emp WHERE emp_no = :empno'; ln_cursor_id := DBMS_SQL.OPEN_CURSOR; DBMS_SQL.PARSE(ln_cursor_id, lv_sql, DBMS_SQL.NATIVE); DBMS_SQL.BIND_VARIABLE(ln_cursor_id, ':empno', 1001); DBMS_SQL.DEFINE_COLUMN(ln_cursor_id, 1, lv_emp_name, 50); DBMS_SQL.DEFINE_COLUMN(ln_cursor_id, 2, ln_emp_no); DBMS_SQL.DEFINE_COLUMN(ln_cursor_id, 3, ln_salary); DBMS_SQL.DEFINE_COLUMN(ln_cursor_id, 4, ln_manager); ln_rows_processed := DBMS_SQL.EXECUTE(ln_cursor_id); LOOP IF DBMS_SQL.FETCH_ROWS(ln_cursor_id) = 0 THEN EXIT; ELSE DBMS_SQL.COLUMN_VALUE(ln_cursor_id, 1, lv_emp_name); DBMS_SQL.COLUMN_VALUE(ln_cursor_id, 2, ln_emp_no); DBMS_SQL.COLUMN_VALUE(ln_cursor_id, 3, ln_salary); DBMS_SQL.COLUMN_VALUE(ln_cursor_id, 4, ln_manager); DBMS_OUTPUT.PUT_LINE('Employee Name: ' || lv_emp_name); DBMS_OUTPUT.PUT_LINE('Employee Number: ' || ln_emp_no); DBMS_OUTPUT.PUT_LINE('Salary: ' || ln_salary); DBMS_OUTPUT.PUT_LINE('Manager ID: ' || ln_manager); END IF; END LOOP; DBMS_SQL.CLOSE_CURSOR(ln_cursor_id); EXCEPTION WHEN OTHERS THEN DBMS_SQL.CLOSE_CURSOR(ln_cursor_id); END; /
Produktion
Employee Name : XXX Employee Number: 1001 Salary : 15000 Manager ID : 1000
Code Fรถrklaring:
- Raderna 1โ8: Variabeldeklaration.
- Linje 10: Rama in SQL-satsen.
- Linje 11: รppna markรถren med DBMS_SQL.OPEN_CURSOR, vilket returnerar ID:t fรถr den รถppnade markรถren.
- Linje 12: Efter att markรถren har รถppnats analyseras SQL-koden.
- Linje 13: Bindningsvรคrdet '1001' tilldelas istรคllet fรถr ':empno'.
- Raderna 14โ17: Definiera kolumnerna efter deras relativa position: (1) anstรคllningsnamn, (2) anstรคllningsnr, (3) lรถn, (4) chef.
- Linje 18: Kรถr frรฅgan med DBMS_SQL.EXECUTE, vilket returnerar antalet bearbetade poster.
- Raderna 19โ32: Hรคmtar posterna i en loop. FETCH_ROWS returnerar 0 nรคr inga rader finns kvar, vilket avslutar loopen.
- UNDANTAGSblock: Sรคkerstรคller att markรถren รคr stรคngd sรฅ att รถppna markรถrer inte lรคcker om ett fel uppstรฅr.
NDS vs DBMS_SQL: Nรคr ska man anvรคnda vilket
Bรฅda metoderna kรถr SQL vid kรถrning, men de passar olika situationer:
- Anvรคnd nativ dynamisk SQL (EXEKTERA OMEDELBART / รPPNA FรR) nรคr antalet och datatyperna fรถr in- och utdata รคr kรคnda vid kompileringstillfรคllet. Det รคr snabbare, lรคttare att lรคsa och krรคver mindre kod.
- Anvรคnd DBMS_SQL nรคr strukturen รคr okรคnd fram till kรถrning, till exempel en frรฅga vars antalet valda kolumner eller bindningsvariabler varierar, sรฅ kallad dynamisk SQL fรถr metod 4, eller ett uttalande som รคr fรถr stort fรถr att fรฅ plats i en enda VARCHAR2-variabel pรฅ 32K.


