我是Firebird DML的新手。
在TransactSQL中,我可以像在中一样自由简单地声明和使用变量
declare @myID int
select @myID = 42
并在SELECT语句中使用这些变量
select * from mytable where id = @myID
以及在不同语句之间传递值。
简单地说,我的问题是,如何在客户端Firebird DML脚本中声明和使用本地变量?
使用FlameRobin,我可以一次性执行一系列DML语句,例如
update mytable set price = 2 * price;
select * from mytable;
但我完全不知道如何声明和使用局部变量在它们之间传递值。
在谷歌上搜索,我发现了Firebird的PSql的EXECUTE BLOCK构造,它显然支持DECLARE VARIABLE,但它看起来很笨重,似乎包含了一些我在TransactSQL中从未遇到过的奇怪限制,而且似乎不适合我尝试做的那种客户端DML脚本。
在过去的几天里,我一直在努力解决这个问题,试图完成对这个q:sql和fifo简单选择的回答;我花了大约半个小时来编写和测试一种TransactSQL方法来完成OP的要求。
我本可以走向你建议的EXECUTE BLOCK
路线,但我一直遇到DML中显然不允许的事情,所以我放弃了以政治正确的方式做这件事。
因此,我这样做的方式可能会让Firebird纯粹主义者大吃一惊:与其试图声明变量,不如创建一个临时表,其中包含与您将要使用的变量相对应的列,以及一个ID表,以便轻松地从中提取值,然后将变量的值存储在其中的一行中
create table variables(ID int, myID int, myStringVar charchar(80), [etc...])
显然,您可以随心所欲地初始化此表,并在执行过程中更新列值。访问其中的值比访问变量的值要麻烦一些,但不像那样麻烦很多
update mytable set somecolumn = 666 where id = (select myID from variables where ID = 1)
我相信你已经明白了。我发现用这种方式做事唯一的小问题是,在尝试使用一组语句之前,似乎有必要将创建数据库对象(如表和视图)打包到一个提交的事务中。
正如您已经发现的那样,拥有真实变量的唯一方法是使用execute block
(无论出于何种目的,它都是一个匿名存储过程),或者——当然——一个普通存储过程。
正如MartynA的回答所示,您也可以使用表来包含变量,尽管我建议您使用全局临时表,因为这会使变量对连接或事务保持"私有"。
还有一个选项(我之前已经完全忘记了)是使用rdb$get_context
和rdb$set_context
来使用上下文变量,尽管这可能会变得有点麻烦。例如,要设置变量x
,可以使用:
select rdb$set_context('USER_SESSION', 'x', 5) from rdb$database;
如果变量是新创建的,则返回值为0
;如果变量已经存在,则返回1
。值被转换为VARCHAR(255)
,因此它们需要是可以强制转换为VARCHAR(255)
的类型。您可以通过将变量设置为NULL
来删除该变量。您也可以使用USER_TRANSACTION
来代替USER_SESSION
。
USER_SESSION
上下文绑定到当前连接。USER_TRANSACTION
中的变量仅存在于已设置变量的事务中。当事务结束时,上下文和其中定义的所有变量都将被销毁。
可以使用获取变量
select rdb$get_context('USER_SESSION', 'x') from rdb$database;
如果变量不存在,则返回NULL
,否则返回值为的VARCHAR(255)
。