制作双插件的最佳方法

时间:2008-09-30 05:51:40

标签: sql database

在表A中插入信息并使用表A中的索引与表B相关的最佳方法是什么。

我试过的“解决方案”是在表A中插入信息(它有一个自动生成的ID),然后,选择最后一个索引并将其插入表B.这可能不是很有用,因为最后一个索引可能插入之间的更改,因为另一个用户可以在表A中生成新索引

我遇到过各种DBMS postgreSQL,Informix,MySQL和MSSQL的问题(感谢lomaxx的回答)

12 个答案:

答案 0 :(得分:7)

如果您使用的是MSSQL,则可以使用SCOPE_IDENTITY返回当前会话中插入的最后一个ID。然后,您可以使用它插入表B。

This article from MSDN就如何做到这一点提供了一个很好的例子。

答案 1 :(得分:3)

这是序列解决方案(对于postgres),当然,您必须在存储过程或应用程序代码中执行此操作。

postgres=# create table foo(id serial primary key, text varchar);
NOTICE:  CREATE TABLE will create implicit sequence "foo_id_seq" for serial column "foo.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
CREATE TABLE

postgres=# create table bar(id int references foo, text varchar);
CREATE TABLE
postgres=# select nextval('foo_id_seq');
 nextval
---------
       1
(1 row)

postgres=# insert into foo values (1,'a'); insert into bar values(1,'b');
INSERT 0 1
INSERT 0 1

对于MySQL,如果您为多个插页使用相同的连接,则交易非常重要,不要自行绊倒。

  

对于LAST_INSERT_ID(),最多   最近生成的ID保留在   服务器基于每个连接。   它不会被其他客户更改。   如果你更新,它甚至没有改变   另一个带有的AUTO_INCREMENT列   非魔术值(即一个值   不是NULL而不是0)。运用   LAST_INSERT_ID()和AUTO_INCREMENT   同时从多个列   客户完全有效。每   客户端将收到最后插入的   客户端的最后一个语句的ID   执行。

mysql> create table foo(id int primary key auto_increment, text varchar(10)) Engine=InnoDB;
Query OK, 0 rows affected (0.06 sec)

mysql> create table bar(id int references foo, text varchar(10)) Engine=InnoDB;
Query OK, 0 rows affected (0.01 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into foo(text) values ('x');
Query OK, 1 row affected (0.00 sec)

mysql> insert into bar values (last_insert_id(),'y');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.04 sec)

答案 2 :(得分:2)

另一个选项是创建一个序列,在插入表之前获取变量中的序列值,并使用它来插入两个表。

答案 3 :(得分:2)

在ORACLE中,使用序列来保存PK值,并使用RETURNING子句

INSERT INTO table1 ( pk_table1, value1 ) 
   VALUES ( table1_seq.NEXTVAL, p_value1 ) RETURNING pk_table1 INTO l_table1_id;

INSERT INTO table2 ( pk_table2, pk_table1, value2 ) 
  VALUES ( table2_seq.NEXTVAL, l_table1_id, p_value2 );

最佳做法是在Oracle中使用PACKAGES来存储appilcation的所有SQL / Data操作层。

答案 4 :(得分:1)

使用IBM Informix Dynamic Server(IDS),它取决于您用于实现双插入的语言。如果它是服务器(SPL - 存储过程语言),并且如果您使用SERIAL列,则使用DBINFO('sqlca.sqlerrd2')表示插入表B时添加到表A的序列值。如果您您正在客户端(ESQL / C,I4GL,JDBC,ODBC)工作,您通过批准的接口(ESQL / C中的sqlca.sqlerrd [1],I4GL中的sqlca.sqlerrd [2])收集串行,然后传输它再回来。

IDS也支持序列,因此您可以使用该技术。

IDS 11.50支持SERIAL8和BIGSERIAL以及SERIAL(4字节整数);每个细节界面略有不同,但基本原理是相同的。

答案 5 :(得分:0)

如果您的表是UUID键,请生成UUID并在两个插入中使用它。

答案 6 :(得分:0)

Microsoft Knowledge Base中描述了Access 2000+(Jet 4.0)的答案。基本上,您可以使用SELECT @@Identity来检索在连接上生成的自动增量字段的值。

答案 7 :(得分:0)

另一个Access 2000+(Jet 4.0)的答案是创建一个Jet 4.0 VIEW(在Access术语中:保存为Query对象的SELECT查询),其中包含INNER JOIN IDENTITY(自动编号)列;必须在SELECT子句和引用的表中公开连接列。然后INSERT INTO VIEW提供没有NOT NULL的所有DEFAULT列的值。

IDENTITY列值可以省略,在这种情况下,引擎将像往常一样自动生成值,或者提供和尊重显式值;如果另外提供了另一个表(没有IDENTITY列的那个)中的连接列的值,则它必须与IDENTITY值相同,否则将发生错误;如果省略IDENTITY值,则将忽略为连接列提供的任何值。请注意,这些表之间通常需要FOREIGN KEY,但这不是此过程工作的先决条件。

快速示例(ANSI-92查询模式Jet 4.0语法):

CREATE TABLE Table1 
(
   key_col INTEGER IDENTITY NOT NULL PRIMARY KEY, 
   data_col_1 INTEGER NOT NULL
)
;
CREATE TABLE Table2
(
   key_col INTEGER NOT NULL, 
   data_col_2 INTEGER NOT NULL, 
   PRIMARY KEY (key_col, data_col_2)
)
;
CREATE VIEW View1
AS 
SELECT T1.key_col AS key_col_1, T2.key_col AS key_col_2, 
       T1.data_col_1, T2.data_col_2
  FROM Table2 AS T2
       INNER JOIN Table1 AS T1
          ON T1.key_col = T2.key_col
;
INSERT INTO View1 (data_col_1, data_col_2) 
VALUES (1, 2)
;

答案 8 :(得分:0)

如果您使用的是sql server 2005+,您还可以使用OUTPUT子句输出已更新,插入或删除的数据。它非常酷,而且非常适合您需要它的类型。 http://msdn.microsoft.com/en-us/library/ms177564.aspx

答案 9 :(得分:0)

在SQL Server中,您使用@@ IDENTITY字段,并在事务中包装INSERT

DEFINE ... etc etc 

BEGIN TRANSACTION

INSERT INTO table1 ( value1 ) VALUES ( @p_value1 )
SET @pk_table1 = @@IDENTITY

INSERT INTO table2 ( pk_table1, value2 ) VALUES ( @pk_table1, @p_value2 )

COMMIT

TSQL中的最佳做法是在@@IDENTITY之后立即将INSERT值存储在变量中,以避免将来的维护代码损坏该值。

使用存储过程也是最佳做法。

答案 10 :(得分:0)

如果它在Informix和JSP中,有一个函数在插入后返回表的Serial字段。

import com.informix.jdbc.*;

cmd = "insert into serialTable(i) values (100)";
stmt.executeUpdate(cmd);
System.out.println(cmd+"...okay");
int serialValue = ((IfmxStatement)stmt).getSerial();
System.out.println("serial value: " + serialValue);

Here's the Link

(出于某种原因,在我的工作计算机中它用西班牙语描述了一切,也许是因为在墨西哥)

答案 11 :(得分:0)

使用事务来避免这个问题:“这可能不是很有用,因为最后一个索引可能会在插入之间发生变化,因为另一个用户可能会在表A中生成一个新索引。”

而且,在PostgreSQL中,您可以使用'nextval'和'currval'来完成您想要做的事情:

BEGIN;

INSERT INTO products (prod_id, prod_name, description) VALUES (
    nextval('products_prod_id_seq')
    , 'a product'
    , 'a product description'
);

INSERT INTO prices (price_id, prod_id, price) VALUES (
    nextval('prices_price_id_seq')
    , currval('products_prod_id_seq')
    , 0.99
);

COMMIT;

如果您还需要DDL片段,请告诉我。