在Firebird中插入SELECT

时间:2014-01-14 14:14:24

标签: sql select insert firebird firebird2.5

我是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表中。

2 个答案:

答案 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仅在IDNULL时分配生成的值。

获取值

要获取生成的值,您可以使用INSERT声明的RETURNING-clause

INSERT INTO MyTable (SomeValue) VALUES ('abc') RETURNING ID

INSERT INTO ... SELECT

使用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的值基本上没有意义,因为没有保证顺序。