Oracle - 无法使用绑定变量更新表记录
Posted
技术标签:
【中文标题】Oracle - 无法使用绑定变量更新表记录【英文标题】:Oracle - Cannot update table record using bind variable 【发布时间】:2015-06-15 21:50:09 【问题描述】:此查询返回 1 行:
SELECT col1, col2 FROM table1 WHERE col1 = :column1;
但这更新了 0 行:
UPDATE table1 SET col2 = :column2 WHERE col1 = :column1;
COMMIT;
我添加了这个约束来将 col1 设置为主键,但它没有修复它。
ALTER TABLE table1 ADD CONSTRAINT col1_pk PRIMARY KEY (col1);
我正在从 SQL Developer 尝试这个,知道为什么它不更新行吗?
编辑:
col1 是VARCHAR2(32 BYTE) NOT NULL
col2 是CLOB NOT NULL
EDIT 2:测试用例,在选择和更新语句中设置 :var1 为 0011223344556677。
CREATE TABLE MY_TABLE
( COL1 VARCHAR2(32 BYTE) NOT NULL ENABLE,
COL2 CLOB,
CONSTRAINT "MY_TABLE_PK" PRIMARY KEY ("COL1")
)
INSERT INTO MY_TABLE (COL1, COL2) VALUES ('0011223344556677', '1434407992143440799214344079921434407992');
SELECT * FROM MY_TABLE WHERE COL1 = :var1;
UPDATE MY_TABLE SET COL2 = 'test' WHERE COL1 = :var1;
COMMIT;
【问题讨论】:
某些东西无法追踪。如果select
返回单行,则update
将修改恰好1 行,假设它们在相同的上下文中运行。如果您的select
在它选择的行未提交的会话中运行,而update
在不同的会话中运行,则update
将看不到有问题的行。如果其他会话在 update
发生并提交更改之前删除了该行,则 update
将更新 0 行。不过,在某种程度上,提供一个显示该行实际上没有更新的测试用例会很有帮助。
如何确定update
修改了0行?如果所有这些都在单个会话中完成并且select
返回一行,则两个语句的绑定变量值实际上不同,或者您实际上没有执行update
或update
正在修改行,你错过了它。
感谢 @JustinCave,检查 Edit 2 中的测试用例。 SQL Developer 显示消息:“0 行已更新。提交完成。”在脚本输出中。我在同一个会话中使用相同的绑定变量值进行选择和更新。
你怎么知道绑定变量的值对于两个语句是一样的?
当我在 SQL Developer 中执行语句时,它会提示一个对话框输入绑定,在那里我输入 0011223344556677 for :var1 (实际上,sql developer 存储了这个值,所以我只需要输入一次)。你试过测试用例吗?它会更新您环境中的行吗?
【参考方案1】:
TL;DR - 确保存储在绑定变量中的值被解析为字符串而不是数字。
我已经在 SQL Developer(版本 4.0.3.16)中运行了这个:
CREATE TABLE MY_TABLE
( COL1 VARCHAR2(32 BYTE) NOT NULL ENABLE,
COL2 CLOB,
CONSTRAINT "MY_TABLE_PK" PRIMARY KEY ("COL1")
);
/
INSERT INTO MY_TABLE (COL1, COL2) VALUES ('0011223344556677', '1434407992143440799214344079921434407992');
/
VARIABLE var1 VARCHAR2(32);
/
BEGIN
:var1 := '0011223344556677';
END;
/
SELECT * FROM MY_TABLE WHERE COL1 = :var1;
/
UPDATE MY_TABLE SET COL2 = 'test' WHERE COL1 = :var1;
/
COMMIT;
/
SELECT * FROM MY_TABLE;
/
它运行良好:
table MY_TABLE created.
1 rows inserted.
anonymous block completed
COL1 COL2
-------------------------------- --------------------------------------------------------------------------------
0011223344556677 1434407992143440799214344079921434407992
1 rows updated.
committed.
COL1 COL2
-------------------------------- --------------------------------------------------------------------------------
0011223344556677 test
如果将变量赋值更改为(去掉引号):
BEGIN
:var1 := 0011223344556677;
END;
然后将值解析为数字,忽略前导零,输出为:
table MY_TABLE created.
1 rows inserted.
anonymous block completed
no rows selected
0 rows updated.
committed.
COL1 COL2
-------------------------------- --------------------------------------------------------------------------------
0011223344556677 1434407992143440799214344079921434407992
【讨论】:
有没有办法在不声明 VARIABLE var1 的情况下做到这一点?必须有一种方法,因为我能够为 select 和 insert 语句做到这一点。 否 - 如果您使用CTRL-ENTER
运行查询,则 SQL Developer 将隐式定义变量(可能没有正确的数据类型),但如果您使用 F5
作为脚本运行它,那么将告诉你绑定变量没有定义,你需要手动定义它(就像我做的那样)。
当我在 SQL Developer 中运行你的脚本时,虽然你定义了 var1 并设置了一个值,但它会提示一个对话框输入 var1 绑定,所以我输入 0011223344556677(不带引号)并正确更新行,但它对我不起作用,因为我不应该手动定义变量,因为我必须在 C 中使用 OCILIB 来执行此操作。
您可以使用准备好的语句在 OCILIB 中尝试它,看看它是否有效(它应该),如果无效,那么您可以在不同的问题中发布 OCILIB 源并询问。关于为什么当您手动输入值时 SQL 开发人员不执行您想要的操作,我没有明确的答案,但它可能是在某处对用户隐藏的影响相等比较的隐式类型转换使用 - 以编程方式执行,您可以定义类型,不要遇到问题。以上是关于Oracle - 无法使用绑定变量更新表记录的主要内容,如果未能解决你的问题,请参考以下文章
Oracle中触发器内的select语句出现错误的绑定变量错误
在 to_date 函数中使用 cx_oracle 变量时无法正确绑定
无法在 oracle SQL 开发人员中更新内部 if 条件