Oracle PL/SQL 游标中的更新和删除

 

 游标中的更新和删除

  在PL/SQL中依然可以使用UPDATE和DELETE语句更新或删除数据行。显式游标只有在需要获得多行数据的情
况下使用。PL/SQL提供了仅仅使  用游标就可以执行删除或更新记录的方法。
  UPDATE或DELETE语句中的WHERE CURRENT OF子串专门处理要执行UPDATE或DELETE操作的表中取出的最近的
数据。要使用这个方法,在声明游标  时必须使用FOR UPDATE子串,当对话使用FOR UPDATE子串打开一个游标时,所有返回集中的数据行都将处于行级(ROW-LEVEL)独占式锁定,其
  他对象只能查询这些数据行,不能进行UPDATE、DELETE或SELECT...FOR            UPDATE操作。

语法:

  FOR UPDATE [OF [schema.]table.column[,[schema.]table.column]..
  [nowait]

  在多表查询中,使用OF子句来锁定特定的表,如果忽略了OF子句,那么所有表中选择的数据行都将被锁定。
如果这些数据行已经被其他会话锁定,那么正常情况下ORACLE将等待,直到数据行解锁。

  在UPDATE和DELETE中使用WHERE CURRENT OF子串的语法如下:

  WHERE{CURRENT OF cursor_name|search_condition}

  例:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

DELCARE

CURSOR c1 IS SELECT empno,salary

FROM emp

WHERE comm IS NULL

FOR UPDATE OF comm;

v_comm NUMBER(10,2);

BEGIN

FOR r1 IN c1 LOOP

IF r1.salary<500 THEN

v_comm:=r1.salary*0.25;

ELSEIF r1.salary<1000 THEN

v_comm:=r1.salary*0.20;

ELSEIF r1.salary<3000 THEN

v_comm:=r1.salary*0.15;

ELSE

v_comm:=r1.salary*0.12;

END IF;

UPDATE emp;

SET comm=v_comm

WHERE CURRENT OF c1l;

END LOOP;

END

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

-声明游标

--宗地表的调查日期LANDINFO_RESEARCHDATE

--复制到流程表的权属调查时间FLOW_REASEARCHTIME

DECLARE

cursor cur_sel_all is select LANDINFO_RESEARCHDATE,LANDINFO_LANDNO from t_leoa_landinfo; --定义游标

   l_date t_leoa_landinfo.landinfo_researchdate%type; --声明变量分别保存t_leoa_landinfo的各列

   l_landNo t_leoa_landinfo.landinfo_landno%type;

begin

open cur_sel_all;

  loop                 --循环取数,并将游标数据填充到返回纪录集合中

   fetch cur_sel_all into l_date,l_landNo;

   exit when cur_sel_all%NOTFOUND; --循环退出条件

   if cur_sel_all%FOUND then --获取数据

    update T_LEOA_BOOKFLOW t2 set FLOW_REASEARCHTIME = l_date where l_landNo = t2.landinfo_landno;

   end if;

  end loop;

close cur_sel_all;

end;

下面再分享一下另外一则游标使用方法的代码,具体如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

-- 声明游标;CURSOR cursor_name IS select_statement

--For 循环游标

--(1)定义游标

--(2)定义游标变量

--(3)使用for循环来使用这个游标

declare

    --类型定义

    cursor c_job

    is

    select empno,ename,job,sal

    from emp

    where job='MANAGER';

    --定义一个游标变量v_cinfo c_emp%ROWTYPE ,该类型为游标c_emp中的一行数据类型

    c_row c_job%rowtype;

begin

    for c_row in c_job loop

     dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);

    end loop;

end;

--Fetch游标

--使用的时候必须要明确的打开和关闭

declare

    --类型定义

    cursor c_job

    is

    select empno,ename,job,sal

    from emp

    where job='MANAGER';

    --定义一个游标变量

    c_row c_job%rowtype;

begin

    open c_job;

     loop

      --提取一行数据到c_row

      fetch c_job into c_row;

      --判读是否提取到值,没取到值就退出

      --取到值c_job%notfound 是false

      --取不到值c_job%notfound 是true

      exit when c_job%notfound;

      dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);

     end loop;

    --关闭游标

   close c_job;

end;

--1:任意执行一个update操作,用隐式游标sql的属性%found,%notfound,%rowcount,%isopen观察update语句的执行情况。

    begin

     update emp set ENAME='ALEARK' WHERE EMPNO=7469;

     if sql%isopen then

      dbms_output.put_line('Openging');

      else

       dbms_output.put_line('closing');

       end if;

     if sql%found then

      dbms_output.put_line('游标指向了有效行');--判断游标是否指向有效行

      else

       dbms_output.put_line('Sorry');

       end if;

       if sql%notfound then

        dbms_output.put_line('Also Sorry');

        else

         dbms_output.put_line('Haha');

         end if;

          dbms_output.put_line(sql%rowcount);

          exception

           when no_data_found then

            dbms_output.put_line('Sorry No data');

            when too_many_rows then

             dbms_output.put_line('Too Many rows');

             end;

declare

    empNumber emp.EMPNO%TYPE;

    empName emp.ENAME%TYPE;

    begin

     if sql%isopen then

      dbms_output.put_line('Cursor is opinging');

      else

       dbms_output.put_line('Cursor is Close');

       end if;

       if sql%notfound then

        dbms_output.put_line('No Value');

        else

         dbms_output.put_line(empNumber);

         end if;

         dbms_output.put_line(sql%rowcount);

         dbms_output.put_line('-------------');

         select EMPNO,ENAME into empNumber,empName from emp where EMPNO=7499;

         dbms_output.put_line(sql%rowcount);

        if sql%isopen then

        dbms_output.put_line('Cursor is opinging');

        else

        dbms_output.put_line('Cursor is Closing');

        end if;

         if sql%notfound then

         dbms_output.put_line('No Value');

         else

         dbms_output.put_line(empNumber);

         end if;

         exception

          when no_data_found then

           dbms_output.put_line('No Value');

           when too_many_rows then

            dbms_output.put_line('too many rows');

            end;

--2,使用游标和loop循环来显示所有部门的名称

--游标声明

declare

    cursor csr_dept

    is

    --select语句

    select DNAME

    from Depth;

    --指定行指针,这句话应该是指定和csr_dept行类型相同的变量

    row_dept csr_dept%rowtype;

begin

    --for循环

    for row_dept in csr_dept loop

      dbms_output.put_line('部门名称:'||row_dept.DNAME);

    end loop;

end;

--3,使用游标和while循环来显示所有部门的的地理位置(用%found属性)

declare

    --游标声明

    cursor csr_TestWhile

    is

    --select语句

    select LOC

    from Depth;

    --指定行指针

    row_loc csr_TestWhile%rowtype;

begin

 --打开游标

    open csr_TestWhile;

    --给第一行喂数据

    fetch csr_TestWhile into row_loc;

    --测试是否有数据,并执行循环

     while csr_TestWhile%found loop

      dbms_output.put_line('部门地点:'||row_loc.LOC);

      --给下一行喂数据

      fetch csr_TestWhile into row_loc;

     end loop;

    close csr_TestWhile;

end;

select * from emp

     

--4,接收用户输入的部门编号,用for循环和游标,打印出此部门的所有雇员的所有信息(使用循环游标)

--CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;

--定义参数的语法如下:Parameter_name [IN] data_type[{:=|DEFAULT} value]

declare

   CURSOR

   c_dept(p_deptNo number)

   is

   select * from emp where emp.depno=p_deptNo;

   r_emp emp%rowtype;

begin

    for r_emp in c_dept(20) loop

      dbms_output.put_line('员工号:'||r_emp.EMPNO||'员工名:'||r_emp.ENAME||'工资:'||r_emp.SAL);

    end loop;

end;

select * from emp 

--5:向游标传递一个工种,显示此工种的所有雇员的所有信息(使用参数游标)

declare

    cursor

    c_job(p_job nvarchar2)

    is

    select * from emp where JOB=p_job;

    r_job emp%rowtype;

begin

    for r_job in c_job('CLERK') loop

      dbms_output.put_line('员工号'||r_job.EMPNO||' '||'员工姓名'||r_job.ENAME);

    end loop;

end;

SELECT * FROM EMP

--6:用更新游标来为雇员加佣金:(用if实现,创建一个与emp表一摸一样的emp1表,对emp1表进行修改操作),并将更新前后的数据输出出来

--http://zheng12tian.iteye.com/blog/815770

    create table emp1 as select * from emp;

declare

    cursor

    csr_Update

    is

    select * from emp1 for update OF SAL;

    empInfo csr_Update%rowtype;

    saleInfo emp1.SAL%TYPE;

begin

  FOR empInfo IN csr_Update LOOP

   IF empInfo.SAL<1500 THEN

    saleInfo:=empInfo.SAL*1.2;

    elsif empInfo.SAL<2000 THEN

    saleInfo:=empInfo.SAL*1.5;

    elsif empInfo.SAL<3000 THEN

    saleInfo:=empInfo.SAL*2;

   END IF;

   UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_Update;

   END LOOP;

END;

--7:编写一个PL/SQL程序块,对名字以‘A'或‘S'开始的所有雇员按他们的基本薪水(sal)的10%给他们加薪(对emp1表进行修改操作)

declare

   cursor

   csr_AddSal

   is

   select * from emp1 where ENAME LIKE 'A%' OR ENAME LIKE 'S%' for update OF SAL;

   r_AddSal csr_AddSal%rowtype;

   saleInfo emp1.SAL%TYPE;

begin

   for r_AddSal in csr_AddSal loop

     dbms_output.put_line(r_AddSal.ENAME||'原来的工资:'||r_AddSal.SAL);

     saleInfo:=r_AddSal.SAL*1.1;

     UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_AddSal;

   end loop;

end;

--8:编写一个PL/SQL程序块,对所有的salesman增加佣金(comm)500

declare

   cursor

     csr_AddComm(p_job nvarchar2)

   is

     select * from emp1 where  JOB=p_job FOR UPDATE OF COMM;

   r_AddComm emp1%rowtype;

   commInfo emp1.comm%type;

begin

  for r_AddComm in csr_AddComm('SALESMAN') LOOP

    commInfo:=r_AddComm.COMM+500;

     UPDATE EMP1 SET COMM=commInfo where CURRENT OF csr_AddComm;

  END LOOP;

END;

--9:编写一个PL/SQL程序块,以提升2个资格最老的职员为MANAGER(工作时间越长,资格越老)

--(提示:可以定义一个变量作为计数器控制游标只提取两条数据;也可以在声明游标的时候把雇员中资格最老的两个人查出来放到游标中。)

declare

  cursor crs_testComput

  is

  select * from emp1 order by HIREDATE asc;

  --计数器

  top_two number:=2;

  r_testComput crs_testComput%rowtype;

begin

  open crs_testComput;

    FETCH crs_testComput INTO r_testComput;

     while top_two>0 loop

       dbms_output.put_line('员工姓名:'||r_testComput.ENAME||' 工作时间:'||r_testComput.HIREDATE);

       --计速器减一

       top_two:=top_two-1;

       FETCH crs_testComput INTO r_testComput;

      end loop;

   close crs_testComput;

end;

--10:编写一个PL/SQL程序块,对所有雇员按他们的基本薪水(sal)的20%为他们加薪,

--如果增加的薪水大于300就取消加薪(对emp1表进行修改操作,并将更新前后的数据输出出来)

declare

  cursor

    crs_UpadateSal

  is

    select * from emp1 for update of SAL;

    r_UpdateSal crs_UpadateSal%rowtype;

    salAdd emp1.sal%type;

    salInfo emp1.sal%type;

begin

    for r_UpdateSal in crs_UpadateSal loop

      salAdd:= r_UpdateSal.SAL*0.2;

      if salAdd>300 then

       salInfo:=r_UpdateSal.SAL;

       dbms_output.put_line(r_UpdateSal.ENAME||': 加薪失败。'||'薪水维持在:'||r_UpdateSal.SAL);

       else

       salInfo:=r_UpdateSal.SAL+salAdd;

       dbms_output.put_line(r_UpdateSal.ENAME||': 加薪成功.'||'薪水变为:'||salInfo);

      end if;

      update emp1 set SAL=salInfo where current of crs_UpadateSal;

    end loop;

end;

--11:将每位员工工作了多少年零多少月零多少天输出出来 

--近似

 --CEIL(n)函数:取大于等于数值n的最小整数

 --FLOOR(n)函数:取小于等于数值n的最大整数

 --truc的用法 http://publish.it168.com/2005/1028/20051028034101.shtml

declare

 cursor

  crs_WorkDay

  is

  select ENAME,HIREDATE, trunc(months_between(sysdate, hiredate) / 12) AS SPANDYEARS,

    trunc(mod(months_between(sysdate, hiredate), 12)) AS months,

    trunc(mod(mod(sysdate - hiredate, 365), 12)) as days

  from emp1;

 r_WorkDay crs_WorkDay%rowtype;

begin

  for  r_WorkDay in crs_WorkDay loop

  dbms_output.put_line(r_WorkDay.ENAME||'已经工作了'||r_WorkDay.SPANDYEARS||'年,零'||r_WorkDay.months||'月,零'||r_WorkDay.days||'天');

  end loop;

end;

--12:输入部门编号,按照下列加薪比例执行(用CASE实现,创建一个emp1表,修改emp1表的数据),并将更新前后的数据输出出来

-- deptno raise(%)

-- 10   5%

-- 20   10%

-- 30   15%

-- 40   20%

-- 加薪比例以现有的sal为标准

--CASE expr WHEN comparison_expr THEN return_expr

--[, WHEN comparison_expr THEN return_expr]... [ELSE else_expr] END

declare

   cursor

     crs_caseTest

     is

     select * from emp1 for update of SAL;

     r_caseTest crs_caseTest%rowtype;

     salInfo emp1.sal%type;

   begin

     for r_caseTest in crs_caseTest loop

     case

      when r_caseTest.DEPNO=10

      THEN salInfo:=r_caseTest.SAL*1.05;

      when r_caseTest.DEPNO=20

      THEN salInfo:=r_caseTest.SAL*1.1;

      when r_caseTest.DEPNO=30

      THEN salInfo:=r_caseTest.SAL*1.15;

      when r_caseTest.DEPNO=40

      THEN salInfo:=r_caseTest.SAL*1.2;

     end case;

     update emp1 set SAL=salInfo where current of crs_caseTest;

    end loop;

end;

--13:对每位员工的薪水进行判断,如果该员工薪水高于其所在部门的平均薪水,则将其薪水减50元,输出更新前后的薪水,员工姓名,所在部门编号。

--AVG([distinct|all] expr) over (analytic_clause)

---作用:

--按照analytic_clause中的规则求分组平均值。

 --分析函数语法:

 --FUNCTION_NAME(<argument>,<argument>...)

 --OVER

 --(<Partition-Clause><Order-by-Clause><Windowing Clause>)

   --PARTITION子句

   --按照表达式分区(就是分组),如果省略了分区子句,则全部的结果集被看作是一个单一的组

   select * from emp1

DECLARE

   CURSOR

   crs_testAvg

   IS

   select EMPNO,ENAME,JOB,SAL,DEPNO,AVG(SAL) OVER (PARTITION BY DEPNO ) AS DEP_AVG

   FROM EMP1 for update of SAL;

   r_testAvg crs_testAvg%rowtype;

   salInfo emp1.sal%type;

   begin

   for r_testAvg in crs_testAvg loop

   if r_testAvg.SAL>r_testAvg.DEP_AVG then

   salInfo:=r_testAvg.SAL-50;

   end if;

   update emp1 set SAL=salInfo where current of crs_testAvg;

   end loop;

end;

总结

以上就是本文关于Oracle中游标Cursor基本用法详解的全部内容,希望对大家有所帮助,欢迎参阅:oracle数据库导入导出命令解析ORACLE SQL语句优化技术要点解析浅谈oracle中单引号转义等,有什么问题可以随时留言,感谢大家!

您可能感兴趣的文章:

原文链接:http://www.cnblogs.com/lcword/p/5857189.html

https://www.jb51.net/article/127299.htm

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值