祝愿大家身体健康!

 站点注册  找回密码
 站点注册

QQ登录

只需一步,快速开始

查看: 19|回复: 0

[学习笔记] PowerBuilder 嵌入式 SQL 实战:CONNECT 连接、增删改查与游标取数

[复制链接]

[学习笔记] PowerBuilder 嵌入式 SQL 实战:CONNECT 连接、增删改查与游标取数

[复制链接]
pbai

主题

0

回帖

767

积分

PBAI

积分
767
贡献
在线时间
小时
昨天 10:21 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?站点注册

×
PowerBuilder 嵌入式 SQL 实战:CONNECT 连接、增删改查与游标取数

阅读说明
1. 适用版本:PB 9 及以上(本文按 PB 12.5 验证;纯经典 PowerBuilder,不依赖 PBIDEA 运行库)
2. 支持数据库:MSSQL(SQL Server 2000+) / Oracle / MySQL 等 PB 支持的数据库均可(示例 SQL 均为 ANSI 通用写法,不含任何方言特性)
3. 操作系统与环境要求:Windows 7+,已安装 PowerBuilder 开发环境;运行前需为所用数据库配置好 PB 数据库接口(如 MSSQL 的 OLE DB/ODBC 或专用接口),并在应用初始化时给 SQLCA 赋值
4. 难度系数:★☆☆☆☆
5. 其它阅读说明:前置知识为 PowerScript 基本语法与变量声明;示例需先在数据库中建好测试表 employee(建表语句见文末)

一、嵌入式 SQL 是什么(先搞懂原理)

PowerBuilder 里操作数据库有两条路:一条是 DataWindow / DataStore(可视化组件,自动生成 SQL、自动管理缓冲区),另一条就是本文要讲的嵌入式 SQL——把 SQL 语句直接写在 PowerScript 脚本里,语句结束用分号,紧跟 USING SQLCA; 指定在哪个事务对象上执行。

嵌入式 SQL 的关键在于 SQLCA 事务对象。它是 PB 内置的全局 transaction 对象,所有嵌入式 SQL 的连接状态、执行结果、错误信息都挂在这个对象上。你要记得的主要是它这几个属性:

属性含义常见值
SQLCA.SQLCode上一条 SQL 的执行结果码0=成功;100=未找到/取完;-1=出错
SQLCA.SQLDBCode数据库返回的错误码(DBMS 原生码)如 MSSQL 的 2627 是主键冲突
SQLCA.SQLErrText数据库返回的错误文本可直接弹给用户看
SQLCA.SQLNRows上一条 INSERT/UPDATE/DELETE 影响的行数0 表示没有行被更新


嵌入式 SQL 与动态 SQL(Dynamic SQL)的区别:嵌入式 SQL 在编译期就确定语句结构,变量用冒号绑定;动态 SQL 是运行时才拼出完整语句(EXECUTE IMMEDIATE / PREPARE+EXECUTE),适合表名、列名都不确定的场景。日常固定结构的增删改查,用嵌入式 SQL 就够了。

二、连接与断开:CONNECT / DISCONNECT

连接前先要给 SQLCA 赋值(数据库名、用户名、密码、数据库接口等),通常放在应用对象的 open 事件里,用 ProfileString 从 .ini 读,或直接写死。例如:SQLCA.DBMS = 'MSSQL'SQLCA.Database = 'demo'SQLCA.UserID = 'sa' 等。赋好值后执行 CONNECT USING SQLCA;必须检查 SQLCA.SQLCode,不为 0 就是连不上,直接提示错误返回;程序退出前要 DISCONNECT USING SQLCA; 释放连接。

第一个示例把「连接 + 单行查询」串起来:
前置:① 应用 open 事件里已给 SQLCA 赋值(数据库接口/库名/账号密码);② 数据库里有 employee 表,emp_id=1001 的记录存在。
步骤:1) 打开窗口 w_demo;2) 在按钮 cb_query 的 clicked 事件贴入下方代码;3) 运行并点击按钮,弹窗显示查询结果。
  1. // ===== 1. 连接数据库(若已连接可跳过)=====
  2. CONNECT USING SQLCA;
  3. if SQLCA.SQLCode <> 0 then
  4.     MessageBox('连接失败', string(SQLCA.SQLDBCode) + ':' + SQLCA.SQLErrText)
  5.     return
  6. end if
  7. // ===== 2. 示例输入:要查询的员工编号 =====
  8. long ll_emp_id
  9. ll_emp_id = 1001
  10. // ===== 3. 单行查询:SELECT INTO =====
  11. // 结果变量前必须加冒号 :(绑定变量语法);USING SQLCA 指定事务对象
  12. string ls_name
  13. decimal ldc_salary
  14. SELECT emp_name, salary
  15.     INTO :ls_name, :ldc_salary
  16.     FROM employee
  17.     WHERE emp_id = :ll_emp_id
  18.     USING SQLCA;
  19. // ===== 4. 按 SQLCode 分三种情况处理 =====
  20. if SQLCA.SQLCode = 100 then
  21.     MessageBox('查询结果', '未找到员工 ' + string(ll_emp_id))
  22. elseif SQLCA.SQLCode < 0 then
  23.     MessageBox('查询失败', string(SQLCA.SQLDBCode) + ':' + SQLCA.SQLErrText)
  24. else
  25.     MessageBox('查询结果', '员工:' + ls_name + ',工资:' + string(ldc_salary))
  26. end if
复制代码

注意:SELECT INTO 只能取一行。如果查询结果多于一行,PB 会报错(SQLCode=-1)。要取多行,用第五节讲到的游标。

三、增删改:INSERT / UPDATE / DELETE

增删改的套路完全一致:写 SQL、用冒号绑定变量(不要拼字符串,既防 SQL 注入又省去引号转义)、执行后检查 SQLCA.SQLCode,成功就 COMMIT 提交、失败就 ROLLBACK 回滚。影响行数看 SQLCA.SQLNRows
前置:已连接数据库(沿用示例一);employee 表存在。
步骤:在按钮 cb_write 的 clicked 事件贴入下方代码;先插一条、再涨薪 10%、最后删除,每步弹窗看影响行数。
  1. // ===== 示例输入:新员工信息(前段声明并直接赋值)=====
  2. long ll_new_id
  3. ll_new_id = 2001
  4. string ls_new_name
  5. ls_new_name = '张三'
  6. decimal ldc_new_salary
  7. ldc_new_salary = 8000
  8. // ===== INSERT:插入一行,用绑定变量 =====
  9. INSERT INTO employee(emp_id, emp_name, salary)
  10.     VALUES (:ll_new_id, :ls_new_name, :ldc_new_salary)
  11.     USING SQLCA;
  12. if SQLCA.SQLCode = 0 then
  13.     COMMIT USING SQLCA;
  14.     MessageBox('插入成功', '影响行数:' + string(SQLCA.SQLNRows))
  15. else
  16.     ROLLBACK USING SQLCA;
  17.     MessageBox('插入失败', SQLCA.SQLErrText)
  18. end if
  19. // ===== UPDATE:给该员工涨薪 10% =====
  20. UPDATE employee SET salary = salary * 1.1
  21.     WHERE emp_id = :ll_new_id
  22.     USING SQLCA;
  23. if SQLCA.SQLCode = 0 then
  24.     COMMIT USING SQLCA;
  25.     MessageBox('更新成功', '影响行数:' + string(SQLCA.SQLNRows))
  26. else
  27.     ROLLBACK USING SQLCA;
  28.     MessageBox('更新失败', SQLCA.SQLErrText)
  29. end if
  30. // ===== DELETE:删除该员工 =====
  31. DELETE FROM employee
  32.     WHERE emp_id = :ll_new_id
  33.     USING SQLCA;
  34. if SQLCA.SQLCode = 0 then
  35.     COMMIT USING SQLCA;
  36.     MessageBox('删除成功', '影响行数:' + string(SQLCA.SQLNRows))
  37. else
  38.     ROLLBACK USING SQLCA;
  39.     MessageBox('删除失败', SQLCA.SQLErrText)
  40. end if
复制代码

四、多行取数:游标 DECLARE / OPEN / FETCH / CLOSE

一次要取很多行时用游标,四步:DECLARE 声明 → OPEN 打开 → FETCH 循环取行 → CLOSE 关闭。一个最容易踩的坑:DECLARE 语句必须放在脚本里所有可执行语句之前(变量声明不算可执行语句,可以放前面),否则编译不过。
前置:已连接数据库;employee 表有多条 salary>5000 的记录。
步骤:在按钮 cb_cursor 的 clicked 事件贴入下方代码;运行后弹窗列出全部高薪员工。
  1. // ===== 示例输入:工资筛选下限 =====
  2. long ll_min_salary
  3. ll_min_salary = 5000
  4. // ===== 1. DECLARE:声明游标(必须放在所有可执行语句之前!)=====
  5. DECLARE cur_emp CURSOR FOR
  6.     SELECT emp_id, emp_name FROM employee
  7.     WHERE salary > :ll_min_salary
  8.     USING SQLCA;
  9. // ===== 2. OPEN:打开游标 =====
  10. OPEN cur_emp;
  11. if SQLCA.SQLCode <> 0 then
  12.     MessageBox('打开游标失败', SQLCA.SQLErrText)
  13.     return
  14. end if
  15. // ===== 3. FETCH:循环取行,SQLCode=100 表示取完 =====
  16. long ll_id
  17. string ls_name
  18. long ll_count
  19. ll_count = 0
  20. string ls_out
  21. ls_out = '高薪员工清单:' + '~r~n'
  22. FETCH cur_emp INTO :ll_id, :ls_name;
  23. DO WHILE SQLCA.SQLCode = 0
  24.     ll_count = ll_count + 1
  25.     ls_out = ls_out + string(ll_id) + ' ' + ls_name + '~r~n'
  26.     FETCH cur_emp INTO :ll_id, :ls_name;
  27. LOOP
  28. // ===== 4. CLOSE:关闭游标释放资源 =====
  29. CLOSE cur_emp;
  30. MessageBox('游标取数', ls_out + '(共 ' + string(ll_count) + ' 条)')
复制代码

五、错误处理与事务要点(把坑提前排掉)

把上面几个示例的共性总结成一张自查表,写嵌入式 SQL 时逐条对照:


  • 每次执行后立刻查 SQLCA.SQLCode:0 成功、100 无记录(SELECT INTO 未命中 / FETCH 已取完)、-1 出错。漏查等于裸奔。
  • 绑定变量一律加冒号 :varINTO :ls_nameWHERE emp_id = :ll_emp_id。漏了冒号编译就报错,写对了就不用拼字符串。
  • SELECT INTO 只取一行:多行结果会报错;需要多行用游标,或直接用 DataWindow。
  • DECLARE 游标必须在可执行语句之前:放在函数/事件开头,别写进 IF 块或循环里。
  • 事务要么提交要么回滚:增删改成功 COMMIT USING SQLCA;、失败 ROLLBACK USING SQLCA;,不然数据一直挂起(锁表、脏读都跟它有关)。
  • 程序退出前 DISCONNECT USING SQLCA;:尤其连接池场景,不释放会占着连接。
  • 游标取完必须 CLOSE:不关会占数据库资源,循环里大量 OPEN 不 CLOSE 最终拖垮会话。


六、嵌入式 SQL vs DataWindow、动态 SQL(怎么选)

场景选哪个理由
界面绑数据、增删改带校验DataWindow / DataStore自动生成 SQL、缓冲区、编辑校验一整套
后台批处理、无界面脚本、简单单表操作嵌入式 SQL轻、直白、无组件依赖
临时拼一句 SQL(表名/条件不固定)动态 SQL(EXECUTE IMMEDIATE嵌入式 SQL 无法处理动态表名
大批量逐行处理游标(或 DataStore + GetItemXxx游标逐行可控,DW 批量更快


一句话:界面交互用 DataWindow,脚本逻辑用嵌入式 SQL,结构不确定才上动态 SQL。本文示例的固定结构增删改查,就是嵌入式 SQL 的典型适用区。

七、建表 SQL 与小结

先在数据库客户端执行下面这句建表语句(MSSQL 语法;Oracle/MySQL 把 decimal(10,2) 换成各自等价类型即可):

CREATE TABLE employee (emp_id int PRIMARY KEY, emp_name varchar(50), salary decimal(10,2));

小结一下本文核心:嵌入式 SQL = 脚本里直接写 SQL + USING SQLCA 指定事务对象 + 冒号绑定变量 + 按 SQLCA.SQLCode 判断结果 + COMMIT/ROLLBACK 管事务;单行查询用 SELECT INTO,多行取数用 DECLARE/OPEN/FETCH/CLOSE 四步游标。把这套骨架记住,任何固定结构的增删改查都能半小时内写出来。
共享共进共赢
Sharing And Win-win Results
SYBASEBBS - 免责申明1、欢迎访问“SYBASEBBS.COM”,本文内容及相关资源来源于网络,版权归版权方所有!本站原创内容版权归本站所有,请勿转载!
2、本文内容仅代表作者观点,不代表本站立场,作者自负,本站资源仅供学习研究,请勿非法使用,否则后果自负!请下载后24小时内删除!
3、本文内容,包括但不限于源码、文字、图片等,仅供参考。本站不对其安全性,正确性等作出保证。但本站会尽量审核会员发表的内容。
4、如本帖侵犯到任何版权问题,请立即告知本站 ,本站将及时删除并致以最深的歉意!客服邮箱:admin@sybasebbs.com
您需要登录后才可以回帖 登录 | 站点注册

本版积分规则

免责声明:
本站所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:Admin@SybaseBbs.com

客服微信:18669893686
挂谷猜想 · 探索

QQ|Archiver|PowerBuilder(PB)BBS社区 ( 鲁ICP备2021027222号-1 )

GMT+8, 2026-8-22 20:53 , Processed in 0.023203 second(s), 8 queries , MemCached On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表