Лучший способ сделать двойную вставку - PullRequest
4 голосов
/ 30 сентября 2008

Как лучше всего вставить информацию в таблицу A и использовать индекс из таблицы A для связи с таблицей B.

«Решение», которое я попробовал, - вставить информацию в таблицу A (которая имеет автоматически сгенерированный идентификатор), затем выбрать последний индекс и вставить его в таблицу B. Это может быть не очень полезно, так как последний индекс изменение между вставками, потому что другой пользователь может сгенерировать новый индекс в таблице A

У меня была эта проблема с различными СУБД postgreSQL, Informix, MySQL и MSSQL (спасибо lomaxx за ответ)

Ответы [ 12 ]

7 голосов
/ 30 сентября 2008

если вы используете MSSQL, вы можете использовать SCOPE_IDENTITY, чтобы вернуть последний идентификатор, вставленный в ваш текущий сеанс. Затем вы можете использовать это для вставки в таблицу B.

Эта статья из MSDN дает хороший пример того, как это сделать.

3 голосов
/ 30 сентября 2008

Это последовательное решение (для 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 () наиболее недавно созданный идентификатор сохраняется в сервер для каждого соединения. Это не изменено другим клиентом. Это даже не изменилось, если вы обновите другой столбец AUTO_INCREMENT с немагическое значение (то есть значение, которое не NULL и не 0). С помощью LAST_INSERT_ID () и AUTO_INCREMENT столбцы одновременно из нескольких клиенты совершенно действительны. каждый клиент получит последний вставленный Идентификатор для последнего утверждения этого клиента казнены.

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 голосов
/ 30 сентября 2008

В 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 для хранения всего уровня манипулирования SQL / данными приложения.

2 голосов
/ 30 сентября 2008

Другой вариант - создать последовательность и перед вставкой в ​​таблицу получить значение последовательности в переменной и использовать его для вставки в обе таблицы.

1 голос
/ 30 сентября 2008

В случае IBM Informix Dynamic Server (IDS) это зависит от языка, который вы используете для реализации двойной вставки. Если это сервер (SPL - язык хранимых процедур), и если вы используете столбец SERIAL, то вы используете DBINFO ('sqlca.sqlerrd2') для представления последовательного значения, добавляемого в таблицу A при вставке в таблицу B. Если вы работают в клиенте (ESQL / C, I4GL, JDBC, ODBC), вы собираете серийный номер через утвержденный интерфейс (sqlca.sqlerrd [1] в ESQL / C, sqlca.sqlerrd [2] в I4GL) и затем переносите его назад снова.

IDS также поддерживает последовательности, поэтому вы можете использовать эту технику вместо этого.

IDS 11.50 поддерживает SERIAL8 и BIGSERIAL, а также SERIAL (4-байтовое целое число); подробные интерфейсы немного отличаются для каждого из них, но основной принцип тот же.

0 голосов
/ 26 января 2009

Используйте транзакцию, чтобы избежать этой проблемы: «Это может быть не очень полезно, так как последний индекс может меняться между вставками, потому что другой пользователь может сгенерировать новый индекс в таблице А.»

И, в 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.

0 голосов
/ 28 октября 2008

Если это в 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);

Вот ссылка

(По какой-то причине в моем рабочем компьютере все описывается по-испански, может, потому что в Мексике)

0 голосов
/ 30 сентября 2008

В 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, чтобы избежать его повреждения в будущем коде обслуживания.

Также рекомендуется использовать хранимые процедуры.

0 голосов
/ 30 сентября 2008

если вы используете sql server 2005+, вы также можете использовать предложение OUTPUT, которое выводит данные, которые были обновлены, вставлены или удалены. Это довольно круто и именно для того типа вещей, которые вам нужны. http://msdn.microsoft.com/en-us/library/ms177564.aspx

0 голосов
/ 30 сентября 2008

Другой ответ Access 2000+ (Jet 4.0) - создать Jet 4.0 VIEW (в терминах Access: запрос SELECT, сохраненный как объект запроса) с INNER JOIN для IDENTITY (Autonumber) колонка; объединяющие столбцы должны быть представлены в предложении SELECT и в ссылочной таблице. Затем INSERT INTO VIEW предоставляет значения для всех столбцов NOT NULL, которые не имеют DEFAULT.

Значение столбца IDENTITY может быть либо опущено, в этом случае механизм будет автоматически генерировать значение как обычно, либо явное значение будет предоставлено и выполнено; если дополнительно добавлено значение объединяющего столбца в другой таблице (без столбца IDENTITY), то оно должно совпадать со значением IDENTITY, иначе произойдет ошибка; если значение IDENTITY опущено, то любое значение, предоставленное для присоединяемого столбца, будет игнорироваться. Обратите внимание, что между такими таблицами обычно ожидается FOREIGN KEY, но это не является обязательным условием для работы этого процесса.

Быстрый пример (синтаксис ANSI-92 Query Mode 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)
;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...