【问题标题】:Scriptella - How to get and re-use autogenerated ids?Scriptella - 如何获取和重用自动生成的 ID?
【发布时间】:2012-10-09 20:43:59
【问题描述】:

我正在使用 Scriptella 进行 ETL 操作,使用自动生成的 ID 引用的许多表。我想在不使用子查询的情况下重复使用这些 id,这是我的 etl 文件的脚本片段:

<script connection-id="out" if="rownum>1">

SELECT nextval('SQC_CLASE') AS claseId;
INSERT INTO zoologia.clase VALUES( ?claseId, ?phylumId, ?clase, ?subclase, ?infraclase, true );

SELECT nextval('SQC_ORDEN') AS ordenId;
INSERT INTO zoologia.orden VALUES( ?ordenId, ?claseId, ?orden, ?suborden, true );

SELECT nextval('SQC_SUPERFAMILIA') AS superfamiliaId;
INSERT INTO zoologia.superfamilia VALUES( ?superfamiliaId, ?ordenId, ?superfamilia, true );

SELECT nextval('SQC_FAMILIA') AS familiaId;
INSERT INTO zoologia.familia VALUES( ?familiaId, ?superfamiliaId, ?familia, ?subfamilia, ?tribu, true );

SELECT nextval('SQC_GENERO') AS generoId;
INSERT INTO zoologia.genero VALUES( ?generoId, ?familiaId, ?genero, true );

SELECT nextval('SQC_ESPECIE') AS especieId;
INSERT INTO zoologia.especie VALUES( ?especieId, ?generoId, ?especie, ?subespecie, ?variedad, ?genero, true );

</script>

这显然是错误的,因为SELECT 不能在脚本中执行,对吧?我不确定如何在没有子查询的情况下做到这一点。我正在使用 PostgreSQL。

编辑: 我想要实现的是,例如,获取在第一个表的插入中使用的自动生成 id 的值,以便在第二个表的插入中使用它,因为应该引用记录

【问题讨论】:

  • 为什么您要为已删除的项目重复使用 ID?
  • ... 为什么不使用子查询呢?你说的是“不使用子查询”,但不是为什么

标签: postgresql scriptella


【解决方案1】:

感谢 Scriptella 论坛的一位用户,这是解决方案,一个包含所有序列值的查询:

<query connection-id="external">
    <query connection-id="sizoo">
        SELECT nextval('SQC_PHYLUM') AS phylumId
        , nextval('SQC_CLASE') AS claseId
        , nextval('SQC_ORDEN') AS ordenId
        , nextval('SQC_SUPERFAMILIA') AS superfamiliaId
        , nextval('SQC_FAMILIA') AS familiaId
        , nextval('SQC_GENERO') AS generoId
        , nextval('SQC_ESPECIE') AS especieId;

        <script connection-id="sizoo" if="rownum>1">
            INSERT INTO zoologia.phylum VALUES( ?phylumId, ?phylum, true );
            INSERT INTO zoologia.clase VALUES( ?claseId, ?phylumId, ?clase, ?subclase, ?infraclase, true );
            INSERT INTO zoologia.orden VALUES( ?ordenId, ?claseId, ?orden, ?suborden, true );
            INSERT INTO zoologia.superfamilia VALUES( ?superfamiliaId, ?ordenId, ?superfamilia, true );
            INSERT INTO zoologia.familia VALUES( ?familiaId, ?superfamiliaId, ?familia, ?subfamilia, ?tribu, true );
            INSERT INTO zoologia.genero VALUES( ?generoId, ?familiaId, ?genero, true );
            INSERT INTO zoologia.especie VALUES( ?especieId, ?generoId, ?especie, ?subespecie, ?variedad, ?genero, true );
        </script>
    </query>
</query>

【讨论】:

  • 这仅适用于 Postgres。如果 Scriptella 在后台使用 stmt.getGeneratedKeys() 为最后一次插入提供一个变量,我们可以以 DB 中立的方式做到这一点,这似乎是一个更好的解决方案。
【解决方案2】:

您的代码最初看起来完全是伪造的,因为似乎没有任何东西将SELECT 连接到下面的INSERT,所以即使它运行了,您也只会生成一个 ID 并将其丢弃。不过,看起来您的脚本工具可能会自动将 SELECT 列别名的结果定义为可以在以后的查询中引用的变量;见"copy to another database" in the Scriptella tutorial。快速浏览一下这表明您想要执行的操作可能有效,但您必须使用嵌套的 &lt;query/&gt;&lt;script/&gt; 块来执行此操作。

使用序列生成的 ID 的正确方法是:

INSERT INTO zoologia.especie VALUES( nextval('SQC_ESPECIE'), ?generoId, ?especie, ?subespecie, ?variedad, ?genero, true );

INSERT INTO zoologia.especie VALUES( DEFAULT, ?generoId, ?especie, ?subespecie, ?variedad, ?genero, true );

INSERT INTO zoologia.especie(generoId, especie, subespecie, variedad, genero, someothercol) 
VALUES( ?generoId, ?especie, ?subespecie, ?variedad, ?genero, true );

您的问题最初似乎是关于重新使用已删除的 ID(即无间隙序列),但看起来您已经澄清它以删除它。


更新后编辑+评论改变了问题的含义:

如果您尝试在随后的INSERTs 中使用从一行生成的 ID,您必须:

  • 使用INSERT ... RETURNING 或在INSERT 之后调用currval('the_id_sequence') 捕获ID,将ID 存储在脚本语言的客户端变量中,并将其传递给后续的INSERTs;或

  • 在后续插入的VALUES 列表中使用currval('the_id_sequence')

我什至从未听说过 Scriptella,更不用说使用它了,所以我无法帮助使用客户端变量的第一个选项。不过,如果它没有办法存储SELECTINSERT ... RETURNING 的结果以供以后使用,我会感到非常惊讶。快速浏览一下就知道它是使用嵌套的 &lt;query/&gt;&lt;script/&gt; 块完成的,但这只是本教程的 30 秒浏览。

第二个选项很简单。假设您刚刚插入:

INSERT INTO zoologia.genero VALUES( DEFAULT, ?familiaId, ?genero, true );

并想在especie 中插入一个新行,该行具有刚刚插入的generogeneroId。假设 genero 的 ID 序列遵循 PostgreSQL 使用的标准命名 tablename_columnname_id_seq,您将使用:

INSERT INTO zoologia.especie VALUES( DEFAULT, currval('genero_generoId_seq'), ...);

见:

【讨论】:

  • 只是为了澄清,这是我用于 ETL 操作的脚本片段,我正在使用 Scriptella。原因是,有 7 个表通过自动生成的 id 相互引用,我需要在所有这些表中插入记录,但是使用 Scriptella 我无法获取第一个表的自动生成的 id 的值,例如,按顺序使用它在第二个表中插入,因为应该引用记录
  • @Neotaku 好的,这比你原来的问题更有意义。很难弄清楚你想要什么。答案已更新。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-08-12
  • 2012-11-13
  • 1970-01-01
  • 2011-04-03
  • 1970-01-01
  • 2018-08-23
  • 2019-12-10
相关资源
最近更新 更多