如何在存储过程的执行语句中使用生成器?

Posted

技术标签:

【中文标题】如何在存储过程的执行语句中使用生成器?【英文标题】:How to use a generator in my execute statement in a stored procedure? 【发布时间】:2019-07-19 06:23:31 【问题描述】:

我正在尝试在 IBExpert 中为 Firebird 2.5 数据库创建一个简单的存储过程。不过,我在使用发电机时遇到了麻烦。我想我已经创建了一个有效的生成器和触发器。但我不知道如何在我的执行语句中应用这些。

表:

ID            BIGINT NOT NULL,
DATUM         INTEGER,
KOSTENST      INTEGER,
KUNDENNUMMER  INTEGER,
DISPONENT     CHAR(5),
KONTAKTART    CHAR(2)

触发器:

CREATE OR ALTER trigger kontakte_erw_id_bi for kontakte_erw_id
active before insert position 0
AS
BEGIN
if (NEW.ID is NULL) then NEW.ID = GEN_ID(ID_KONTAKTE, 1);
END 

生成器:

CREATE SEQUENCE ID_KONTAKTE;
ALTER SEQUENCE ID_KONTAKTE RESTART WITH 0;

程序语句(我认为问题出在此处?如何解决触发器以填充 ID 列?):

for execute statement('
  SELECT
        KONTAKTE.DATUM,
        KUNDEN.KOSTENST,
        KUNDEN.KUNDENNR,
        KONTAKTE.DISPONENT,
        KONTAKTE.KONTAKTART

FROM KONTAKTE
INNER JOIN KUNDEN ON KONTAKTE.KUNDENNR = KUNDEN.KUNDENNR

')
          on external 'db'
          as user 'xxx' password xxx

          into :XDATUM, :XKOSTENST, :XKUNDENNUMMER, :XDISPONENT, :XKONTAKTART

  do
  begin

    execute statement

    ('update or insert into KONTAKTE_ERW_ID (DATUM, KOSTENST, KUNDENNUMMER, DISPONENT, KONTAKTART)

      values

    (:DATUM, :KOSTENST, :KUNDENNUMMER, :DISPONENT, :KONTAKTART)')


   (DATUM:= XDATUM, KOSTENST := XKOSTENST, KUNDENNUMMER := XKUNDENNUMMER, DISPONENT := XDISPONENT, KONTAKTART := XKONTAKTART)

        on external 'db'
        as user 'xxx' password xxx;

  end

这是我在尝试填充图表时遇到的错误:

336003099 : UPDATE OR INSERT field list does not match primary key of table KONTAKTE_ERW_ID
Statement : update or insert into KONTAKTE_ERW_ID (DATUM, KOSTENST, KUNDENNUMMER, DISPONENT, KONTAKTART)

      values

    (?, ?, ?, ?, ?)

【问题讨论】:

不清楚你在问什么。 “我如何处理触发器以填充 ID 列?” 无论如何,假设您正确地创建了触发器(看起来确实如此),您不需要做任何事情,它会被自动调用。但是,我想知道您为什么在这里使用on external 电话?如果这是同一个数据库,那么你应该使用普通语句。 那个错误是非常重要的信息。请edit您的问题添加该错误。您的问题是 update or insert 需要一些东西来唯一标识要更新或插入的行。 这有点“鸡和蛋”的问题。你需要一些独特的东西才能使用update or insert。是否存在也唯一标识行的值组合?在这种情况下,您可以使用MATCHING 子句。 您如何设想“在语句中生成唯一值” 来解决您的问题?如果那是您想要的,您应该忘记使用update or insert,而只需使用insert,因为最终结果将是相同的。但是,我假设您正在尝试跨数据库同步数据,因此这不是一个真正的解决方案。您需要在业务领域中唯一标识记录的东西。 【参考方案1】:

您的问题是,为了能够使用UPDATE OR INSERT,Firebird 需要知道一行何时已经存在。为此,它要么使用主键,要么 - 如果提供 - MATCHING 子句。

在您的语句中,您没有提供主键,也没有提供 MATCHING 子句,因此 Firebird 无法确定是否有要更新的行或是否应该插入。

在您的情况下,在语句中包含主键似乎不是一个选项(或者您需要应用一种方案来生成可以在不同数据库中唯一的标识符),因此您唯一的选择是使用 @ 987654325@ 子句。但是,查看您的专栏,我并没有立即看到可以被认为是独特的东西。

【讨论】:

只能通过将其更改为“插入”来解决此问题吗?我假设那时不需要 Primarykey 或 Matching 子句? 你帮我理解了很多问题!非常感谢,我想我现在可以找到解决方法了。 @sHooP 是的,更改为插入将解决该问题。但是,如果您尝试跨数据库同步记录,那仅意味着您将在每次同步时插入新记录,并且永远不会更新现有记录。

以上是关于如何在存储过程的执行语句中使用生成器?的主要内容,如果未能解决你的问题,请参考以下文章

SqlServer 中如何查看某一个Sql语句是复用了执行计划,还是重新生成了执行计划

如何在plsql中执行存储过程

一个sql存储过程中@sql语句加入引号的问题

sql存储过程有什么用

MS sql如何使用存储过程?

plsql中如何执行存储过程?