在Firebird中插入SELECT

num*_*er5 2 sql firebird select insert firebird2.5

我是火鸟的新手,我有很多问题.我想在从另一个表中选择的表中插入各种行.

这是代码:

/*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%'
Run Code Online (Sandbox Code Playgroud)

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)) 
Run Code Online (Sandbox Code Playgroud)

和2.另一张桌子

BAS_ART (ID (INTEGER), ARTCATEGORY (VARCHAR255))
Run Code Online (Sandbox Code Playgroud)

- >我想将表BAS_ART中包含"MyWord"的所有条目插入到MATERIAL表中,其中包含ARTCATEGORY列中的"MyWord".

Mar*_*eel 6

对于我的大部分回答,我将假设一个非常简单的表格:

CREATE TABLE MyTable (
   ID BIGINT PRIMARY KEY,
   SomeValue VARCHAR(255),
   posid INTEGER
)
Run Code Online (Sandbox Code Playgroud)

自增标识符

Firebird(最高版本 2.5)没有标识列类型(这将在 Firebird 3 中添加),而是需要使用序列(又名生成器)和触发器来获取它。

顺序

首先,您需要使用以下命令创建一个序列CREATE SEQUENCE

CREATE SEQUENCE seqMyTable
Run Code Online (Sandbox Code Playgroud)

序列是原子的,这意味着交错事务/连接不会获得重复的值,它也在事务控制之外,这意味着 aROLLBACK不会恢复到以前的值。在大多数用途中,序列应该始终增加,因此您在问题开始时所做的值重置几乎对于所有目的都是错误的;例如,另一个连接也可能在执行过程中重置序列,从而导致意外的POSID.

扳机

要生成自动增量标识符的值,您需要使用将BEFORE INSERT TRIGGER生成的值分配给 - 在本例中 -ID列。

CREATE TRIGGER trgMyTableAutoIncrement FOR MyTable
ACTIVE BEFORE INSERT POSITION 0
AS 
BEGIN 
    NEW.ID = NEXT VALUE FOR seqMyTable;
END
Run Code Online (Sandbox Code Playgroud)

在此示例中,我始终分配生成值,其他示例ID仅在is时分配生成值NULL

获取值

要获取生成的值,您可以使用RETURNING-语句的INSERT- 子句:

INSERT INTO MyTable (SomeValue) VALUES ('abc') RETURNING ID
Run Code Online (Sandbox Code Playgroud)

插入...选择

使用INSERT INTO ... SELECT您可以从一个表中选择行并将它们插入到其他表中。它对您不起作用的原因是您试图将字符串值分配':pos'给 type 的列INTEGER,而这是不允许的。

假设我有另一个MyOtherTable具有类似结构的表MyTable,我可以使用以下方式传输值:

INSERT INTO MyTable (SomeValue)
  SELECT SomeOtherValue
  FROM MyOtherTable
Run Code Online (Sandbox Code Playgroud)

INSERT INTO ... SELECT除非只插入单行,否则无法使用它获取生成的值(Firebird 5.0 将引入多行RETURNING支持)。

猜测有关POSID

我不清楚它POSID应该是什么,以及它应该具有什么价值。看起来您希望单个 的值从 1 开始递增INSERT INTO ... SELECT。在 Firebird 2.5 之前的版本中,这种方式是不可能的(在 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
Run Code Online (Sandbox Code Playgroud)

如果没有posid 的ORDER BYSELECT,本质上是没有意义的,因为没有保证顺序。


a_h*_*ame 6

我不明白为什么你需要触发器.

这个问题:

我想将包含"MyWord"的表BAS_ART中的所有条目插入到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';
Run Code Online (Sandbox Code Playgroud)

这假定存在第二个序列(也称为"生成器"),其被命名seq_mat_id为列提供新的idmaterial.id