關於SQL語句的佔位符使用及動態SQL
在PLSQL中使用EXECUTE IMMEDIATE語句處理動態SQL語句。
語法如下:
EXECUTE IMMEDIATE dynamic_string
[INTO {define_variable[, define_variable]... | record}]
[USING [IN | OUT | IN OUT] bind_argument
[, [IN | OUT | IN OUT] bind_argument]...]
[{RETURNING | RETURN} INTO bind_argument[, bind_argument]...];
dynamic_string是代表一條SQL語句或一個PL/SQL塊的字串表示式,
define_variable是用於存放被選出的欄位值的變數,
record是使用者定義或%ROWTYPE型別的記錄,用來存放被選出的行記錄。
輸入bind_argument引數是一個表示式,它的值將被傳入(IN模式)或傳出(OUT模式)或先傳入再傳出(IN OUT模式)到動態SQL語句或是PL/SQL塊中。一個輸出bind_argument引數就是一個能儲存動態SQL返回值的變數。
除了多行查詢外,動態字串可以包含任何SQL語句(不含終結符)或PL/SQL塊(含終結符)。
字串中可以包括用於引數繫結的佔位符。
但是,不可以使用繫結引數為動態SQL傳遞模式物件。
在用於單行查詢時,INTO子句要指明用於存放檢索值的變數或記錄。
對於查詢檢索出來的每一個值,INTO子句中都必須有一個與之對應的、型別相容的變數或欄位。
在用於DML操作時,RETURNING INTO子句要指明用於存放返回值的變數或記錄。
對於DML語句返回的每一個值,INTO子句中都必須有一個與之對應的、型別相容的變數或欄位。
我們可以把所有的繫結引數放到USING子句中。預設的引數模式是IN。
對於含有RETURNING子句的DML語句來說,我們可以把OUT引數放到RETURNING INTO之後,並且不用指定它們的引數模式,因為預設就是OUT。
如果我們既使用了USING又使用RETURNING INTO,那麼,USING子句中就只能包含IN模式的引數了。
執行時,動態字串中的繫結引數會替換相對應的佔位符。所以,每個佔位符必須與USING子句和/或RETURNING INTO子句中的一個繫結引數對應。我們可以使用數字、字元和字串作為繫結引數,但不能使用布林型別(TRUE,FALSE和NULL)。要把空值傳遞給動態字串,我們就必須使用工作區。
動態SQL支援所有的SQL型別。所以,定義變數和繫結變數都可以是集合、LOB,物件型別例項和引用。
作為一項規則,動態SQL是不支援PL/SQL特有的型別的。這樣,它就不能使用布林型或索引表。
我們可以重複為繫結變數指定新值執行動態SQL語句。但是,每次都會消耗很多資源,因為EXECUTE IMMEDIATE在每次執行之前都需要對動態字串進行預處理。
1、動態SQL例項
下面的PL/SQL塊包含了幾個動態SQL的例子:
- DECLARE
- sql_stmt VARCHAR2(200);
- plsql_block VARCHAR2(500);
- emp_id NUMBER(4) := 7566;
- salary NUMBER(7, 2);
- dept_id NUMBER(2) := 50;
- dept_name VARCHAR2(14) := 'PERSONNEL';
- location VARCHAR2(13) := 'DALLAS';
- emp_rec emp%ROWTYPE;
- BEGIN
- EXECUTE IMMEDIATE 'CREATE TABLE bonus (id NUMBER, amt NUMBER)';
- sql_stmt := 'INSERT INTO dept VALUES (:1, :2, :3)';
- EXECUTE IMMEDIATE sql_stmt
- USING dept_id, dept_name, location; sql_stmt := 'SELECT * FROM emp WHERE empno = :id';
- EXECUTE IMMEDIATE sql_stmt
- INTO emp_rec
- USING emp_id; plsql_block := 'BEGIN emp_pkg.raise_salary(:id, :amt); END;';
- EXECUTE IMMEDIATE plsql_block
- USING 7788, 500; sql_stmt := 'UPDATE emp SET sal = 2000 WHERE empno = :1 RETURNING sal INTO :2';
- EXECUTE IMMEDIATE sql_stmt
- USING emp_id
- RETURNING INTO salary; EXECUTE IMMEDIATE 'DELETE FROM dept WHERE deptno = :num'
- USING dept_id; EXECUTE IMMEDIATE 'ALTER SESSION SET SQL_TRACE TRUE';
- END;
下例中,過程接受一個數據表名(如"emp")和一個可選的WHERE子句(如"sal > 2000")。
如果我們沒有提供WHERE條件,程式會刪除指定表中所有的行,否則就會按照給定的條件刪除行:
- CREATEORREPLACEPROCEDURE delete_rows(
- table_name IN VARCHAR2,
- condition IN VARCHAR2 DEFAULTNULL
- ) AS
- where_clause VARCHAR2(100) := ' WHERE ' || condition;
- BEGIN
- IF condition ISNULLTHEN
- where_clause := NULL;
- END IF;
- EXECUTE IMMEDIATE 'DELETE FROM ' || table_name || where_clause;
- END;
2、USING子句的向後相容
當動態INSERT、UPDATE或DELETE語句有一個RETURNING子句時,
輸出繫結引數可以放到RETURNING INTO或USING子句的後面。
在新的應用程式中要使用RETURNING INTO,而舊的應用程式可以繼續使用USING,如下例:
- DECLARE
- sql_stmt VARCHAR2(200);
- my_empno NUMBER(4) := 7902;
- my_ename VARCHAR2(10);
- my_job VARCHAR2(9);
- my_sal NUMBER(7, 2) := 3250.00;
- BEGIN
- sql_stmt := 'UPDATE emp SET sal = :1 WHERE empno = :2 RETURNING ename, job INTO :3, :4';
- /* Bind returned values through USING clause. */
- EXECUTE IMMEDIATE sql_stmt
- USING my_sal, my_empno, OUT my_ename, OUT my_job;
- dbms_output.put_line(my_ename || ',' || my_job);
- /* Bind returned values through RETURNING INTO clause. */
- EXECUTE IMMEDIATE sql_stmt
- USING my_sal, my_empno
- RETURNING INTO my_ename, my_job;
- dbms_output.put_line(my_ename || ',' || my_job);
- END;
3、指定引數模式
使用USING子句時,我們不需要為輸入引數指定模式,因為預設的就是IN;
而RETURNING INTO子句中我們是不可以指定輸出引數的模式的,因為定義中它就是OUT模式。
在適當的時候,我們必須為繫結引數指定OUT或IN OUT模式。例如,假定我們想呼叫下面的過程:
- CREATEPROCEDURE create_dept(
- deptno INOUT NUMBER,
- dname IN VARCHAR2,
- loc IN VARCHAR2
- ) AS
- BEGIN
- SELECT deptno_seq.NEXTVAL INTO deptno FROM DUAL;
- INSERTINTO dept VALUES (deptno, dname, loc);
- END;
要從動態PL/SQL塊呼叫過程,就必須為與形參關聯的繫結引數指定IN OUT模式,如下:
- DECLARE
- plsql_block VARCHAR2(500);
- new_deptno NUMBER(2);
- new_dname VARCHAR2(14) := 'ADVERTISING';
- new_loc VARCHAR2(13) := 'NEW YORK';
- BEGIN
- plsql_block := 'BEGIN create_dept(:a, :b, :c); END;';
- EXECUTE IMMEDIATE plsql_block
- USING INOUT new_deptno, new_dname, new_loc;
- dbms_output.put_line(new_deptno);
- END;
4、開啟遊標變數OPEN-FOR
OPEN {cursor_variable | :host_cursor_variable} FOR dynamic_string
[USING bind_argument[, bind_argument]...];
OPEN-FOR的動態形式有一個可選的USING子句。
在執行時,USING子句中的繫結變數可以替換動態SELECT語句中相對應的佔位符
5、使用批量動態SQL
批量繫結能減少PL/SQL和SQL引擎之間的切換,改善效能。
使用下面的命令、子句和遊標屬性,我們就能構建批量繫結的SQL語句,然後在執行時動態地執行:
BULK FETCH 語句
BULK EXECUTE IMMEDIATE 語句
FORALL 語句
COLLECT INTO 子句
RETURNING INTO 子句
%BULK_ROWCOUNT 遊標屬性
動態批量繫結語法
批量繫結能讓Oracle把SQL語句中的一個變數與一個集合相繫結。
集合型別可以是任何PL/SQL集合型別(索引表、巢狀表或變長陣列)。
但是,集合元素必須是SQL資料型別,如CHAR、DATE或NUMBER。
有三種語句支援動態批量繫結:EXECUTE IMMEDIATE、FETCH和FOR ALL。
批量EXECUTE IMMEDIATE這個語句能讓我們把變數或OUT繫結引數批量繫結到一個動態的SQL語句,語法如下:
EXECUTE IMMEDIATE dynamic_string
[[BULK COLLECT] INTO define_variable[, define_variable ...]]
[USING bind_argument[, bind_argument ...]]
[{RETURNING | RETURN}
BULK COLLECT INTO bind_argument[, bind_argument ...]];
在動態多行查詢中,我們可以使用BULK COLLECT INTO子句來繫結變數。
在返回多行結果的動態INSERT、UPDATE或DELETE語句中,我們可以使用RETURNING BULK COLLECT INTO子句來批量繫結輸出變數。
批量FETCH這個語句能讓我們從動態遊標中取得資料,就跟從靜態遊標中取得的方法是一樣的。語法如下:
FETCH dynamic_cursor
BULK COLLECT INTO define_variable[, define_variable ...];
*如果在BULK COLLECT INTO中的變數個數超過查詢的欄位個數,Oracle就會產生錯誤。
批量FORALL這個語句能讓我們在動態SQL語句中批量繫結輸入引數。
此外,我們還可以在FORALL內部使用EXECUTE IMMEDIATE語句。語法如下:
FORALL index IN lower bound..upper bound
EXECUTE IMMEDIATE dynamic_string
USING bind_argument | bind_argument(index)
[, bind_argument | bind_argument(index)] ...
[{RETURNING | RETURN} BULK COLLECT
INTO bind_argument[, bind_argument ... ]];
*動態字串必須是一個INSERT、UPDATE或DELETE語句(不可以是SELECT語句)。
例如
- DECLARE
- TYPE numlist ISTABLEOF NUMBER;
- TYPE namelist ISTABLEOF VARCHAR2(15);
- empcur sys_refcursor;
- empnos numlist;
- enames namelist;
- sals numlist;
- BEGIN
- OPEN empcur FOR'SELECT empno, ename FROM emp';
- FETCH empcur
- BULK COLLECT INTO empnos, enames;
- CLOSE empcur;
- EXECUTE IMMEDIATE 'SELECT sal FROM emp'
- BULK COLLECT INTO sals;
- END;
只有INSERT、UPDATE和DELETE語句才能擁有輸出繫結引數。
我們可以在EXECUTE IMMDIATE的BULK RETURNING INTO子句中進行繫結:
- DECLARE
- TYPE namelist ISTABLEOF VARCHAR2(15);
- enames namelist;
- sal_amt NUMBER := 500;
- sql_stmt VARCHAR(200);
- BEGIN
- sql_stmt := 'UPDATE emp SET sal = :1 RETURNING ename INTO :2';
- EXECUTE IMMEDIATE sql_stmt
- USING sal_amt
- RETURNING BULK COLLECT INTO enames;
- END;
使用FORALL語句和USING子句,但這時的SQL語句不能是查詢語句,如下例:
- DECLARE
- TYPE numlist ISTABLEOF NUMBER;
- TYPE namelist ISTABLEOF VARCHAR2(15);
- empnos numlist;
- enames namelist;
- BEGIN
- empnos := numlist(7369, 7499, 7521);
- FORALL i IN 1 .. 3
- EXECUTE IMMEDIATE 'UPDATE emp SET sal = sal*2 WHERE empno = :1 RETURNING ename INTO :2'
- USING empnos(i)
- RETURNING BULK COLLECT INTO enames;
- END;
6、動態SQL的技巧與陷阱
1)使用繫結變數來改善效能
我們可以使用繫結變數來改善效能,如下例所示,讓Oracle為不同的emp_id值重用同一個遊標。
- CREATEPROCEDURE fire_employee(emp_id NUMBER) AS
- BEGIN
- EXECUTE IMMEDIATE 'DELETE FROM emp WHERE empno = :num'
- USING emp_id;
- END;
2)讓過程對任意模式物件起作用
假設我們需要一個過程,讓它接受資料表名,然後將指定的表從資料庫中刪除。
我們可能會下面這樣編寫使用動態SQL的過程:
- CREATEPROCEDURE drop_table(table_name IN VARCHAR2) AS
- BEGIN
- EXECUTE IMMEDIATE 'DROP TABLE :tab'
- USING table_name;
- END;
但是,在執行的時候,這個過程會報一個表名無效的錯誤。
原因是不可以使用繫結引數為動態SQL傳遞模式物件。
解決方法是直接把引數巢狀到字串中。把上面的EXECUTE IMMEDIATE語句修改一下:
- CREATEORREPLACEPROCEDURE drop_table(table_name IN VARCHAR2) AS
- BEGIN
- EXECUTE IMMEDIATE 'DROP TABLE ' || table_name;
- END;
這樣,我們就可以向動態SQL語句傳遞任意資料表名稱了。
3)使用重複佔位符
動態SQL語句中的佔位符與USING子句中的繫結引數是位置關聯的,而不是名稱關聯。
所以,如果在SQL語句中同樣的佔位符出現兩次或多次,
那麼,它的每次出現都必須與一個USING子句中的繫結引數相關聯。
例如下面的動態字串:
sql_stmt := 'INSERT INTO payroll VALUES (:x, :x, :y, :x)';
我們可以為動態字串編寫對應的USING子句:
EXECUTE IMMEDIATE sql_stmt USING a, a, b, a;
但是,
動態PL/SQL塊中只有唯一的佔位符才與USING子句中的繫結引數按位置對應。
所以,如果一個佔位符在PL/SQL塊中出現兩次或多次,
那麼所有這樣相同的佔位符都只與USING語句中的一個繫結引數相對應。
比如下面的例子,第一個佔位符(x)與第一個繫結引數(a)關聯,第二個佔位符(y)與第二個繫結引數(b)關聯。
- DECLARE
- a NUMBER := 4;
- b NUMBER := 7;
- BEGIN
- plsql_block := 'BEGIN calc_stats(:x, :x, :y, :x); END';
- EXECUTE IMMEDIATE plsql_block
- USING a, b;
- END;
4)使用遊標屬性
每個顯式的遊標都有四個屬性:%FOUND、%ISOPEN、%NOTFOUND和%ROWCOUNT。它們都能返回與靜態或動態SQL語句執行結果相關的有用資訊。
為處理SQL資料操作語句,Oracle會開啟一個名為SQL的隱式遊標。它的屬性會返回最近一次執行的INSERT、UPDATE、DELETE或單行SELECT的相關資訊。例如,下面函式就使用%ROWCOUNT返回從資料表中刪除的行數:
- CREATEFUNCTION rows_deleted(table_name IN VARCHAR2, condition IN VARCHAR2)
- RETURNINTEGERAS
- BEGIN
- EXECUTE IMMEDIATE 'DELETE FROM ' || table_name || ' WHERE ' || condition;
- RETURN SQL%ROWCOUNT; -- return number of rows deleted
- END;
5)傳遞空值
下面,我們來為動態SQL傳遞空值,見下面的EXECUTE IMMEDIATE語句:
EXECUTE IMMEDIATE 'UPDATE emp SET comm = :x' USING NULL;
但是,這個語句會因為在USING子句中使用NULL而執行失敗,
因為USING語句中所傳遞的引數是不能為空的。
所以,要想解決這個問題,直接使用字串就可以了:
- DECLARE
- a_null CHAR(1); -- set to NULL automatically at run time
- BEGIN
- EXECUTE IMMEDIATE 'UPDATE emp SET comm = :x'
- USING a_null;
- END;
6) 遠端操作
如下例所示,PL/SQL子程式能夠執行引用遠端資料庫物件的動態SQL語句:
- PROCEDURE delete_dept(db_link VARCHAR2, dept_id INTEGER) IS
- BEGIN
- EXECUTE IMMEDIATE 'DELETE FROM [email protected]' || db_link || ' WHERE deptno = :num'
- USING dept_id;
- END;
同樣,遠端過程呼叫(RPC)的目標也包括動態SQL語句。
例如,假設下面返回資料表中記錄個數的函式存放在Chicago的資料庫上:
- CREATEFUNCTION row_count(tab_name VARCHAR2)
- RETURNINTEGERAS
- ROWSINTEGER;
- BEGIN
- EXECUTE IMMEDIATE 'SELECT COUNT(*) FROM ' || tab_name
- INTOROWS;
-
相關推薦
關於SQL語句的佔位符使用及動態SQL
在PLSQL中使用EXECUTE IMMEDIATE語句處理動態SQL語句。 語法如下: EXECUTE IMMEDIATE dynamic_string [INTO {define_variable[, define_variable]... | record}] [USING [IN | OUT |
sql語句字符串包含
數據 acl sele ins true sql 數據庫 oracl from rom select instr(‘1222‘,‘122‘) from dual//前者包含後者>0 oracle mysql 數據庫可中 select charindex(‘1‘
Access sql語句建立表及欄位型別
建立一張空表: Sql="Create TABLE [表名]" 建立一張有欄位的表: Sql="Create TABLE [表名]([欄位名1] MEMO NOT NULL, [欄位名2] MEMO, [欄位名3] COUNTER NOT NULL, [欄位名4] DA
mybaits(查詢與別名、日誌框架顯示sql語句、物件屬性和資料庫表字段不匹配resultMap使用、mysql資料查詢分頁、執行sql和儲存過程、動態SQL語句)
主要是各種配置檔案,建議把整個專案搬到自己電腦上慢慢看。 建立maven專案 首先是各種配置檔案: pom.xml: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://m
mysql sql語句調優及,索引總結
Mysql的索引 1.btree索引,btree索引是二叉平衡樹的結構表有(myisam innodb), 2.Hash索引,通過hash演算法計算到的索引是隨機的沒有規律(memory),沒有回杭 一、Btree索引 索引同時只能用上一個 查詢一條sql的執行
提高sql語句執行效率及索引
(1)選擇最有效率的表名順序(只在基於規則的優化器中有效):ORACLE的解析器按照從右到左的順序處理FROM子句中的表名,FROM子句中寫在最後的表(基礎表 driving table)將被最先處理,在FROM子句中包含多個表的情況下,你必須選擇記錄條數最少的表作為基礎表。如果有3個以上的表連線查詢,那就
prepareStatement進行增刪改查---填充佔位符(防止sql注入)
首先建立表 然後構造一個實體類–封裝資料庫欄位 Student package com.godinsec; public class Student { private int id; private String name;
SQL語句建立資料庫及表和約束等
建立資料庫: --drop database Mydatabase create database Mydatabase on primary ( --括號一定是圓括號 name='Mydatabase_data',--資料庫名稱 filename='d:
Mac下Mysql匯出sql語句的方法及可能遇到的mysqldump: command not found
最近切換到了Mac os的開發平臺,於是乎自己又琢磨了一套方法 度娘了一下,尚無針對Mac的SQL語句匯出方法的介紹,在這裡與大家分享。 步驟一: 開啟Terminal,輸入mysqldum
spring+ibatis【基本配置及動態sql】
1、準備jar:commons-dbcp.jar、commons-logging.jar、commons-pool.jar、ibatis-common-2.jar、ibatis-sqlmap-2.jar、javax.servlet-5.1.12.jar、log4j-1.2.
關於使用佔位符來解決SQL注入
總結: SQL已經預編譯好了,然後替換中間的佔位符,這個佔位符在編譯後就已經確定了它只是一個引數屬性。因此,用注入的程式碼去替換佔位符,這個SQL也不會再進行編譯了,所以也達不到注入的目的。 SQL注入並不是一個在SQL內不可解決的問題,這種攻擊方式的存在也不能完全歸
Spring-boot mybatis 控制檯列印執行的SQL語句 SpringBoot中Mybatis列印sql
【轉載】SpringBoot中Mybatis列印sql 1. 如果使用的是application.properties檔案,加入如下配置: 1 logging.level.com.example.demo.dao=debug 紅色部分指的是mybatis對應的方法介面所在的包路徑。 2.
SQL SERVER-10-觸發器|遊標|動態sql
1.觸發器 --可以理解為一個特殊的儲存過程,在某一個動作執行的時候,自動執行,而不需要人手動執行 --觸發器的分類 --1.DML觸發器 --insert,delete,update(不支援select) --after觸發器,instead of 觸發器(相當於其他資
SQL Server建立儲存過程——動態SQL
儲存過程(stored procedure)是一組為了完成特定功能的SQL語句集合,經編譯後儲存在伺服器端的資料庫中,利用儲存過程可以加速SQL語句的執行。 自定義儲存過程,由使用者建立並能完成某一特定功能的儲存過程,儲存過程既可以有引數又有返回值,但是它與函式不同,儲存過程的返回值只是指明執行是否成功,
在SQLPLUS中oracle查看錶結構SQL語句 oracle修改表字段SQL語句 修改表字段SQL語句
1、查看錶結構 desc 表名 2、修改表字段SQL語句 使用rename關鍵字來實現欄位名的修改: alter table 表名 rename column舊的欄位名 to 新的欄位名名; 使用modify關鍵字來實現對資料型別的修改: alter table 表名 mo
通過分析SQL語句的執行計劃優化SQL(總結)
如何幹預執行計劃 - - 使用hints提示 基於代價的優化器是很聰明的,在絕大多數情況下它會選擇正確的優化器,減輕了DBA的負擔。但有時它也聰明反被聰明誤,選擇了很差的執行計劃,使某個語句的執行變得奇慢無比。此時就需要DBA進行人為的干預,告訴優化器使用我們指定的存取路徑或連線型別生成執行計劃,從而使
SSM框架day02-MyBatis——036 動態SQL-where、037 動態SQL-choose、038 動態SQL-foreach陣列、039 動態SQL-foreachList
一、動態SQL-where(1)對映檔案(2)定義介面方法 (3)測試二、動態SQL-choose(1)對映檔案(2)介面實現方法(3)測試三、動態SQL-foreach陣列(1)對映檔案(2)定義介面 方法(3)測試四、動態SQL-foreachList(1)List集合中
python 操作資料庫插入語句佔位符問題
1,在 Python 中使用 sqlite3 連線資料庫,插入語句的展位符為 "?" cur.execute("insert into user values(?,?,?)",(1,2,"zhang"))2、在 Python 中,使用 pymysql 連線 mysql 資
檢視sql語句執行時間或測試sql語句效能
寫程式的人,往往需要分析所寫的SQL語句是否已經優化過了,伺服器的響應時間有多快,這個時候就需要用到SQL的STATISTICS狀態值來查看了。 通過設定STATISTICS我們可以檢視執行SQL時的系統情況。選項有PROFILE,IO ,TIME。介紹如下:
使用Freemarker解析佔位符,構造可執行的SQL語句
背景 最近遇到一個需求, 框架需要執行使用者給定的SQL語句,該SQL語句內包含佔位符, 佔位符表示的內容存在於在框架中,比如下面的sql select * from xxx where id =