我是firebird的新手,我有很多问题。我想在从另一个表中选择的表中插入各种行。
以下是代码:
/*CREATE GENERATOR POS; */
SET GENERATOR POS TO 1;
SET TERM ^;
create trigger BAS_pkassign
for MATERIAL
active before insert position 66
EXECUTE BLOCK
AS
declare posid bigint;
select gen_id(POS, 1)
from RDB$DATABASE
into :posid;
BEGIN
END
SET TERM ; ^
INSERT INTO MATERIAL ( /*ID */ LOCATION, POSID, ARTID, ARTIDCONT, QUANTITY )
SELECT 1000, ':posid', 309, BAS_ART.ID, 1
FROM BAS_ART
WHERE BAS_ART.ARTCATEGORY LIKE '%MyWord%'
ID应该从66开始自动增加。 posid应该从1开始自动增量。
实际上它没有插入任何东西。
我正在使用Firebird Maestro并刚刚打开了SQL脚本编辑器(在执行脚本时不会抛出任何错误消息)。
有人能帮助我吗?
谢谢!
其他信息:
触发器应该自动增加列“ID” - 但我不知道我究竟能如何改变它以便它工作..':posid'使用它抛出一个错误:posid但是像这样没有错误(我猜它的解释为字符串)。但是我该如何使用呢?
我执行它时不会出错。表结构很简单。我有2张桌子: 1。
Material (
ID (INTEGER),
Location (INTEGER),
POSID (INTEGER),
ARTID (INTEGER),
ARTIDCONT (INTEGER),
QUANTITY (INTEGER),
OTHERCOLUMN (INTEGER))
和2.其他表
BAS_ART (ID (INTEGER), ARTCATEGORY (VARCHAR255))
- >我想将表BAS_ART中包含“MyWord”的所有条目插入到MATERIAL表中。
答案 0 :(得分:6)
我不明白为什么你需要触发器。
这个问题:
我想将表格BAS_ART中包含“MyWord”的所有条目插入到MATERIAL表中
可以使用单个insert ... select
语句解决。
insert into material (id, location, posid, artid, quantity)
select next value for seq_mat_id, 1000, next value for seq_pos, id, 1
from bas_art
where artcategory = 'My Word';
这假设有一个名为seq_mat_id
的第二个序列(又名“生成器”),它为列material.id
提供了新的id
答案 1 :(得分:3)
对于我的大部分答案,我将假设一个非常简单的表格:
CREATE TABLE MyTable (
ID BIGINT PRIMARY KEY,
SomeValue VARCHAR(255),
posid INTEGER
)
Firebird(最高版本2.5)没有标识列类型(这将在Firebird 3中添加),而是需要使用序列(也称为生成器)和触发器来实现此目的。
首先,您需要使用CREATE SEQUENCE
创建序列:
CREATE SEQUENCE seqMyTable
序列是原子的,这意味着交错事务/连接不会获得重复值,它也在事务控制之外,这意味着ROLLBACK
不会恢复到先前的值。在大多数用途中,序列应该总是增加,因此在问题开始时重置的值对于几乎所有目的都是错误的;例如,另一个连接可能会在执行过程中途重置序列,从而使您无意中重复POSID
。
要为自动增量标识符生成值,您需要使用BEFORE INSERT TRIGGER
将生成的值分配给 - 在此示例中为ID
列。
CREATE TRIGGER trgMyTableAutoIncrement FOR MyTable
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
NEW.ID = NEXT VALUE FOR seqMyTable;
END
在此示例中,我始终分配生成的值,other examples仅在ID
为NULL
时分配生成的值。
要获取生成的值,您可以使用INSERT
声明的RETURNING
-clause:
INSERT INTO MyTable (SomeValue) VALUES ('abc') RETURNING ID
使用INSERT INTO ... SELECT
,您可以从一个表中选择行并将其插入其他表中。它不适合您的原因是因为您尝试将字符串值':pos'
分配给INTEGER
类型的列,而这是不允许的。
假设我有另一个表格MyOtherTable
,其结构与MyTable
类似,我可以使用以下方式传输值:
INSERT INTO MyTable (SomeValue)
SELECT SomeOtherValue
FROM MyOtherTable
使用INSERT INTO ... SELECT
除非只插入一行,否则无法获取生成的值。
POSID
我不清楚POSID
应该是什么,以及它应该具有什么价值。对于单个INSERT INTO ... SELECT
,您似乎希望从1开始增加值。在高达2.5的Firebird版本中,这种方式是不可能的(在Firebird 3中,您可以使用ROW_NUMBER()
来实现此目的。)
如果我的猜测正确,那么您需要使用EXECUTE BLOCK
(或存储过程)来为每个要插入的行分配和增加值。
执行块类似于:
EXECUTE BLOCK
AS
DECLARE posid INTEGER = 1;
DECLARE someothervalue VARCHAR(255);
BEGIN
FOR SELECT SomeOtherValue FROM MyOtherTable INTO :someothervalue DO
BEGIN
INSERT INTO MyTable (SomeValue, posid) VALUES (:someothervalue, :posid);
posid = posid + 1;
END
END
如果没有ORDER BY
SELECT
,则posid的值基本上没有意义,因为没有保证顺序。