2010-01-04 18 views
41

Estoy usando PostgreSQL.Insertar datos en tablas vinculadas por clave externa

Customer 
================== 
Customer_ID | Name 

Order 
============================== 
Order_ID | Customer_ID | Price 

Para insertar un pedido, esto es lo que tengo que hacer por lo general,

Por ejemplo, para "John" lugar "1,34" precio.

(1) Get Customer_ID from Customer table, where name is "John" 
(2) If there are no Customer_ID returned (There is no John), insert "John" 
(3) Get Customer_ID from Customer table, where name is "John" 
(4) Insert "Customer_ID" and "1.34" into Order table. 

¡Hay 4 comunicaciones SQL con base de datos involucradas para esta operación simple!

¿Hay alguna manera mejor, que se puede lograr usando 1 instrucción SQL?

Respuesta

44

Puede hacerlo en una declaración SQL para clientes existentes, 3 declaraciones para las nuevas. Todo lo que tiene que hacer es ser un optimista y actuar como si el cliente ya existe:

insert into "order" (customer_id, price) values \ 
((select customer_id from customer where name = 'John'), 12.34); 

Si no existe el cliente, obtendrá una excepción de SQL, que será algo así como el texto:

null value in column "customer_id" violates not-null constraint 

(siempre que haya realizado customer_id no admite nulos, lo que estoy seguro que hizo). Cuando se produce esta excepción, inserte el cliente en la tabla de clientes y hacer de nuevo la inserción en la tabla orden:

insert into customer(name) values ('John'); 
insert into "order" (customer_id, price) values \ 
((select customer_id from customer where name = 'John'), 12.34); 

menos que su negocio está creciendo a un ritmo que hará que "donde poner todo el dinero" su única verdadera problema, la mayoría de sus insertos serán para clientes existentes. Por lo tanto, la mayoría de las veces, la excepción no ocurrirá y habrá terminado en una declaración.

+0

¿Puedes modificar tu respuesta para usar "DEVOLUCIÓN" como se sugirió depesz? De modo que no necesitamos realizar una consulta adicional [select customer_id del cliente donde name = 'John'] –

+0

No es una optimización que haría. He aquí por qué: Primero, mantener el código simple: si el segundo inserto en el orden es idéntico al primero, puede usar el mismo código para hacer ambos insertos. Segundo: no es probable que haya una ganancia de rendimiento real. Dado que acaba de hacer la consulta sobre el cliente y luego la inserción, Postgres tendrá la fila y el índice apropiado en la memoria caché, por lo que el cliente seleccionado será muy rápido. –

3

No con una declaración regular, no.

Lo que puede hacer es ajustar la funcionalidad en una función PL/pgsql (u otro idioma, pero PL/pgsql parece ser la más adecuada para esto), y luego simplemente llame a esa función. Eso significa que seguirá siendo una declaración única para su aplicación.

1

Utilice procedimientos almacenados.

Y aun suponiendo que usted quiere no utilizar procedimientos almacenados - no es como máximo 3 comandos para ejecutarse, no 4. Segundo conseguir id es inútil, ya que puede hacer "INSERT INTO ... que vuelve".

+0

¿Vuelve a utilizar los procedimientos, en lugar de emitir como máximo 3 comandos SQL continuos? El uso de procedimientos almacenados será más rápido/ –

+0

Es poco probable que sea más rápido. Es decir. la diferencia no debe ser medible. Al menos suponiendo una conexión de red sensata. –

Cuestiones relacionadas