PROC 主要內容: 1) proc簡介 2) proc程序的開發過程 3) 宿主變量和指示變量 4) 嵌入sql語句 5) 連接數據庫 6) 錯誤處理 7) 數據的存取更新操作 8) 動態sql ----------------------------- 1.什么是pro程序? 1.1 概念 在過程化的編程語言中嵌入sql語句而開發出的應用程序,叫pro程序。 在通用的編程語言中嵌入的sql語句稱為嵌入式sql 被嵌入了sql語句的編程語言稱為宿主語言 1.2 proc/c++ 在c/c++語言中嵌入sql語句而開發出的應用程序,稱為proc/c++程序 目的:是C/C++這種高效的語言成為訪問oracle數據庫的工具 2. proc中嵌入的sql語句 #include ..... ... /* 包含一個名為sqlca的結構 */ exec sql include sqlca; 變量的聲明 函數的聲明 int main(void) { /* 連接數據庫 */ exec sql connect:用戶名/密碼; /* 操作數據庫:比如查詢 */ exec sql select 字段列表 into 變量列表 from 表名 where 條件; /* 關閉並釋放連接資源 */ exec sql commit work release; exec sql rollbakc work release; } 3.C程序的開發步驟 1) 編寫源程序 vi xxx.c 2) 編譯、鏈接 gcc xxx.c -lxxxxx 3) 運行 ./a.out 4.proc程序的開發步驟 1) 編寫源程序 vi xxxx.pc 2) 預編譯 proc xxx.pc -----> xxx.c 3) 編譯、鏈接 gcc xxx.c -lclntsh -- linux gcc xxx.c -lorasql10(11) -- windows 4) 運行 ./a.out 案例:first.pc vi first.pc proc first.pc gcc first.c -lclntsh ./a.out 5. 宿主變量 5.1 概念 proc中C語言稱為宿主語言 在宿主語言中定義,即可以在宿主語言中使用,也可以在sql語句中使用的變量,稱為宿主變量。 5.2 宿主變量的數據類型 char 字符型 char var[n] 定長字符串 short int 整型 long float double 浮點型 varchar var[n] 變長字符串 5.3 定長字符串和變長字符串 5.3.1 定長字符串 字符串的長度不足時用空格補齊 案例:charn.pc 5.3.2 變長字符串 案例:varcharn.pc char name[25] ----> varchar name[25] 預編譯時,varchar類型的數組被翻譯成了同名的結構: struct{ unsigned short len; unsigned char arr[25]; } name; varchar類型的數組在sql語句中使用時,和char型數組一樣 在宿主語言中使用時,按照結構的用法: 提取字符串的值:name.arr 獲取字符串的長度:name.len 使用varchar類型的數組時,可以會產生垃圾數據,解決方式: 1) 字符串進行初始化,把數組的所有元素初始化為'\0' varchar name[25] = {0}; 2) 手動為字符串添加結束標志 name.arr[name.len] = '\0'; 5.3.3 使用預編譯選項解決變長字符串的問題 oname 相當於 gcc 的 -o char_map = charz: 處理成定長,空格補齊,'\0'結尾 = varchar2|charf: 處理成定長,空格補齊,不以'\0'結尾 = string: 處理成變長,以'\0'結尾 proc charn.pc char_map=string gcc charn.c -lclntsh ./a.out 5.4 宿主變量使用時的注意事項 1) 在sql語句中使用宿主變量時,最好在變量名前加: ... int id=2; ... exec sql select first_name into name from s_emp where id=id; ... 2) DDL語句中不允許使用宿主變量 案例:droptable.pc ..... char tablename[20]="testdsql_zsm_00"; ..... /* 刪除名為 tablename 的表 */ exec sql drop table tablename; /* 預編譯錯誤:宿主變量不能在ddl語句中使用 */ exec sql drop table :tablename; 3) 宿主變量可以使用指針,但是不推薦 4) 宿主變量的定義,強烈建議放入聲明區 (C++語言、windows平台要求宿主變量的聲明必須在聲明區) exec sql begin declare section; /* 聲明區 */ exec sql end declare section; 練習:定義合適的變量,接收s_dept中id=43的部門的信息,並輸出。 案例:searchdeptbyid.pc
#include <stdio.h> exec sql include sqlca; int main(void) { exec sql begin declare section; char userpasswd[30]="openlab/open123"; int id=43; char name[25]; int rid; exec sql end declare section; exec sql connect :userpasswd; exec sql select id,name,region_id into :id,:name,:rid from s_dept where id=:id; exec sql commit work release; printf("%d %s %d\n",id,name,rid); return 0; }
6.指示變量 6.1 指示變量的作用 當數據庫中的字段的值,賦值給宿主變量時,賦值的狀態了一通過指示變量獲取。 指示變量的值: 0 代表正常賦值 -1 代表數據庫中對應字段的值為null >0 代表截斷賦值 盡量避免(編譯沒問題,執行時在賦值階段不會出現錯誤,引起的后續的問題 時機不確定) 6.2 語法 指示變量的數據類型必須是short short indid; short indname; exec sql select id,first_name into :id,:name from s_emp where id=1; exec sq l select 字段1,字段2 into :宿主變量1 [indicator] :指示變量 , 宿主變量2 from 表名 where 條件; exec sql select id,first_name into :id:indid,:name:indname from s_emp where id=1; 6.3 案例:把s_emp表中id=1的員工的id,first_name,manager_id查詢出來,保存到相應的宿主變量,同時使用指示變量指示賦值狀態。 案例: indvar.pc 7.數組變量 7.1 數組變量使用的注意事項 1) 除了字符型外,其他類型的數組只能使用一維的 int ids[50]; char name[50][25]; 2) 不支持數組指針 3) 最大元素個數 32767 4) 在select語句中使用數組變量時,只能給出數組的名字,不能使用下標 5) 如果要指示多個變量的賦值狀態,可以使用指示變量數組 7.2 把s_emp表中的所有員工的id,first_name和manager_id查詢出來,使用合適的數組接收查詢結果,並使用指示變量數組指示manager_id的賦值狀態 案例:arr_var.pc
#include <stdio.h> exec sql include sqlca; int main(void) { exec sql begin declare section; char userpasswd[30]="openlab/open123"; int ids[50]={0}; char names[50][25]={0}; int mids[50]={0}; short indmids[50]={-2}; exec sql end declare section; exec sql connect:userpasswd; exec sql select id,first_name,manager_id into :ids,:names,:mids:indmids from s_emp; exec sql commit work release; int i=0; for(;i<50;i++) { printf("%d %s %d %hd\n",ids[i],names[i], mids[i],indmids[i]); } return 0; }
8.sqlca通信區 8.1 通信區的概念 通信區:為了取得每個sql語句執行后的相關狀態說明,以便進行錯誤的后續操作或跟蹤 oracle中提供了兩個通信區: SQL通信區:sqlca Oracle通信區:oraca 8.2 sqlca通信區 執行proc程序時,oracle把每一條sql中狀態信息存入sqlca中,包括錯誤代碼、警告標志設置、診斷文本和處理行數等。 本質上,sqlca是一個結構體 proc每執行一條sql語句,都會把相關信息寫入到sqlca,覆蓋上一條sql語句的執行的結果信息,所以需要獲取執行結果信息的話,要執行完馬上獲取。 sqlca.sqlerrd[2]: sql語句執行后影響的行數 sqlca.sqlcode: sql執行的狀態 0: 執行正常 >0: 執行出錯(出現異常) <0 : 數據庫系統錯誤 或者網絡錯誤 sqlca.sqlerrm.sqlerrmc: 錯誤信息 案例:sqlca.pc
#include <stdio.h> exec sql include sqlca; int main(void) { exec sql begin declare section; char userpasswd[30]="openlab/open123"; int ids[50]={0}; char names[50][25]={0}; int mids[50]={0}; short indmids[50]={-2}; exec sql end declare section; exec sql connect:userpasswd; if(sqlca.sqlcode){ printf("%s\n",sqlca.sqlerrm.sqlerrmc); } exec sql select id,first_name,manager_id into :ids,:names,:mids:indmids from s_emp; if(sqlca.sqlcode){ printf("%s\n",sqlca.sqlerrm.sqlerrmc); } exec sql commit work release; int i=0; for(;i<sqlca.sqlerrd[2];i++) { printf("%d %s %d %hd\n",ids[i],names[i], mids[i],indmids[i]); } return 0; }
9. oraca通信區 一個類似於sqlca的結構,可以作為sqlca通信區的補充。當需要獲取更為詳細的狀態信息,可以使用oraca. oraca通信區對sqlca的補充 可以使用oraca獲取執行的sql語句的文本 oraca的使用步驟: 1) 包含oraca exec sql include oraca; 2) 打開oraca option exec oracle option(oraca=yes); 3) 設置sql文本的保存標志 oraca.orastxtf 0: 默認值 不保存 1: sql語句出錯時保存 2: sql語句出現錯誤或警告時保存 3: 都保存 4) 獲取sql文本 oraca.orastxt.orastxtc 案例:oraca.pc
#include <stdio.h> exec sql include sqlca; exec sql include oraca; exec oracle option(oraca=yes); int main(void) { exec sql begin declare section; char userpasswd[30]="openlab/open123"; char name[25]; int id=1; exec sql end declare section; exec sql connect:userpasswd; oraca.orastxtf = 1; exec sql select first_name into :name from s_emp where id=:id; exec sql commit work release; printf("%s\n",name); printf("%s\n",oraca.orastxt.orastxtc); return 0; }
10. proc中如何使用sql語句 1) select語句 在語句前加exec sql,配合into使用 exec sql select 字段列表 into 宿主變量列表 from 表名 where 條件; 2) dml語句(inert delete update) ddl語句(create drop alter) tcl語句(commit rollback savepoint) 直接在語句前加exec sql 注意:ddl語句中不能使用宿主變量 綜合案例:sql.pc
#include <stdio.h> #include <stdlib.h> exec sql include sqlca; int connect(); void createtable(); void insert(); void search(); void update(); void delete(); int main(void) { if(connect()) { printf("連接錯誤\n"); return -1; } int option; printf("歡迎使用學生管理系統\n"); while(1) { printf("1.創建學生表\n"); printf("2.注冊\n"); printf("3.查看\n"); printf("4.修改\n"); printf("5.刪除\n"); printf("0.退出\n"); printf("請選擇:"); scanf("%d",&option); switch(option) { case 1: printf("學生管理系統---- 創建表\n\n"); createtable(); break; case 2: printf("學生管理系統---- 注冊\n"); insert(); break; case 3: printf("學生管理系統---- 查看\n"); break; case 4: printf("學生管理系統---- 修改\n"); break; case 5: printf("學生管理系統---- 刪除\n"); break; case 0: printf("謝謝使用!\n"); exit(0); default: printf("沒有此功能!\n"); break; } } return 0; } int connect() { exec sql begin declare section; char username[20]; char passwd[20]; exec sql end declare section; printf("請輸入用戶名:"); scanf("%s",username); printf("請輸入密碼:"); scanf("%s",passwd); exec sql connect:username identified by :passwd; return sqlca.sqlcode; } void createtable() { exec sql create table student_zsm_00( stuno number(7), stuname varchar2(20), birth date); } void insert() { exec sql begin declare section; int stuno; char name[25]; char birth[20]; exec sql end declare section; printf("請輸入學號:"); scanf("%d",&stuno); printf("請輸入姓名:"); scanf("%s",name); printf("請輸入出生日期:(yyyy-mm-dd)"); scanf("%s",birth); exec sql insert into student_zsm_00 values( :stuno,:name,to_date(:birth,'yyyy-mm-dd')); exec sql commit; }
開發一個超小型的學生管理系統,完成以下功能: 創建學生信息表 添加學生信息 顯示學生信息列表 根據學號更改信息 根據學號刪除信息 循環菜單: 學生管理系統,請選擇: 1.創建表 2.學生注冊 3.查看 4.修改信息 5.刪除信息 0.退出 練習:
