Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > SQL
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 19-05-2010
Avatar de santiago14
santiago14 santiago14 is offline
Miembro
 
Registrado: sep 2003
Ubicación: Cerrillos, Salta, Argentina
Posts: 583
Poder: 21
santiago14 Va por buen camino
Question Insert múltiple (o masivo)

Buenas, la duda es la siguiente:
¿Se puede hacer un insert masivo en Firebird 1.5?

La idea sería poder hacer algo así: (como en MySQL, por ejemplo)

Código SQL [-]
Insert into conceptos (codigo, nombre, direccion, estado)
values (1, 'santiago', 'Salta', 'A'), (2, 'Juan', 'La loma', 'A'),
(3, 'Pedro', 'Cerrillos', 'A')

Nunca he podido armar algo parecido, así me libero de hacer un for y enviar un insert por vez. Esto lograría que fuéramos una sola vez hacia el servidor firebird e insertar todos los valores de una sola vez.

Bien, espero haber sido claro.

Saludos.
__________________
Uno es responsable de lo que hace y de lo que omite hacer.
Responder Con Cita
  #2  
Antiguo 19-05-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.040
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Que yo sepa no se puede, ¿en qué casos puedes necesitar hacerlo así?
Responder Con Cita
  #3  
Antiguo 19-05-2010
Avatar de defcon1_es
defcon1_es defcon1_es is offline
Miembro
 
Registrado: mar 2004
Ubicación: Cuenca - España
Posts: 533
Poder: 21
defcon1_es Va por buen camino
Cita:
Empezado por Casimiro Notevi Ver Mensaje
Que yo sepa no se puede, ¿en qué casos puedes necesitar hacerlo así?
Sólo se puede si los datos están en otra tabla o se pueden recuperar de un procedimiento almacenado de la BD, de la forma:
Código SQL [-]
INSERT INTO FACTPEND(IDFACTURA, IDDOCUMENTO)
SELECT DISTINCT PARIDFACTURA, PARIDDOCUMENTOCOBRO 
FROM PRAJUSTES
WHERE (PARPENDIENTE != 0)
__________________
Progress Openedge
https://abevoelker.com/progress_open...dered_harmful/


Delphi forever...

Última edición por defcon1_es fecha: 19-05-2010 a las 12:57:06.
Responder Con Cita
  #4  
Antiguo 19-05-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.040
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Sí, en eso tienes razón, aunque una sentencia de insert como la que ha puesto santiago14 no la había visto nunca
Responder Con Cita
  #5  
Antiguo 19-05-2010
Avatar de santiago14
santiago14 santiago14 is offline
Miembro
 
Registrado: sep 2003
Ubicación: Cerrillos, Salta, Argentina
Posts: 583
Poder: 21
santiago14 Va por buen camino
Bueno, el caso puntual es de una factura (su detalle), la carga se hace renglón por renglón y se va acumulando en una grilla, en pantalla. Luego de esto, un botón de confirmación hace los controles correspondientes y recorremos la grilla con un FOR, por cada vuelta del FOR tengo que hacer un Insert, esto implica todo un tramiterío de la transacción hasta que vuelve a tomar el control mi software para así dar lugar al siguiente Insert.
Bien, creo que sería mas práctico "armar" una SQL con los datos que voy sacando de la grilla y enviarla una sola vez en el Insert.
Esto no es descabellado, lo he visto en MySQL (la sintaxis no la recuerdo exactamente pero es algo parecido a lo que puse) y así evitamos tantas idas y vueltas para cargar los detalles.

Bueno, espero haber aclarado la cosa.
Si no hay forma en Firebird, ya está, habrá que ver la manera de minimizar los accesos a la BD en los casos de los Insert's.

Gracias.
__________________
Uno es responsable de lo que hace y de lo que omite hacer.
Responder Con Cita
  #6  
Antiguo 19-05-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.040
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Si también tienes que hacer el bucle para recorrer los registros y crear el insert... pues igual lo haces con firebird, tan sólo que ya lo insertas directamente sin tener que armar el sql de todos en conjunto
En fin, de todas formas, no se puede con firebird.
Responder Con Cita
  #7  
Antiguo 19-05-2010
Avatar de rgstuamigo
rgstuamigo rgstuamigo is offline
Miembro
 
Registrado: jul 2008
Ubicación: Santa Cruz de la Sierra-Bolivia
Posts: 1.646
Poder: 17
rgstuamigo Va por buen camino
Arrow

Cita:
Empezado por Casimiro Notevi Ver Mensaje
Que yo sepa no se puede, ¿en qué casos puedes necesitar hacerlo así?
Bueno la razón mas obvia sería cuando se tiene que insertar muchos registros(no pocos) en una tabla si se lo quiere hacer de una sola vez.
Por ejemplo: Supongamos que tenemos la tabla> Artículo (ID,Nombre); lo normal para insertar datos es hacerlo asi:
Código SQL [-]
Insert into Artículo values (1,'Arroz');
Insert into Artículo values (2,'Azucar');
Insert into Artículo values (3,'Fideo');
Insert into Artículo values (4,'Frejol');
Insert into Artículo values (5,'Avena');
...
Si nos damos cuenta es un poco tedioso, por tal motivo algunos servidores de Bases de datos (MySQL por ejemplo) soportan las inserciones masivas, de tal manera que cuando se quiera insertar miles de registro de un golpe, sencillamente se puede utilizar una sintaxis SQL parecida a la siguiente:
Código SQL [-]
Insert into Artículo (ID,Nombre) values(1,'Arroz'),(2,'Azucar'),(3,'Fideo'),(4,'Frejol'),(5,'Avena'),...;
.
Si nos damos cuenta ésto nos permite ahorrar sintaxis y sobre todo evitamos la saturación de estar insertardo uno a uno los registro, es éste caso se insertar todos de una sola vez. desde luego es recomendable utilizar transacciones para hacer las inserciones masivas, ya que cuando se está hablando de muchos registros, puede ocurrir que cuando nuestro servidor esté guardando la insercion ocurra un fallo y tengamos problemas, de ahí que es conveniente usar transacciones, O en todo caso si se tiene que insertar miles de registro, pues dividir la insercion en bloques por ejemplo de 1000 registros cada una para mayor seguridad.

En lo personal he implementado desde delphi una inserción masiva, para lo cual he encontrado dos formas de hacerlo; en mi caso yo mando todos los registros a insertar dentro de una lista(un objeto TObjectList) a una funcion en la que hago es ir creando mi consulta SQL con los elementos de esa lista.
A continuacion describo las dos formas con las que he logrado implememtar con mi funcion en particular:
Primera forma de hacerlo: Creando muchos parámetros en la consulta SQL:
Código Delphi [-]
function TDet_Req_Dinero.InsertarLista(L: TObjectList): Boolean;
var I:Integer;
aux:TDet_Req_Dinero;
Query:TZQuery;
n,p:String;
begin
Result:=True;
if L.Count>0 then  //si mi lista tiene elementos
 Begin
    Result:=False;
    Query:=TZQuery.Create(nil);//creo mi Query
      try
         with Query do
          begin
            Connection:=DataModule1.ZConnection1;//asigno el componente Conexion a mi query
            SQL.Add('Insert into Req_Dine(Item,Nro_Req,MontoEnBs,MontoEnSus,Motivo)values ');//adicono la primera parte de mi SQL
            for  I:=0  to L.Count-1 do
            begin
              aux:=TDet_Req_Dinero(L.Items[i]);//Obtengo el objeto [i] de la lista y le hago casting hacia un objeto TDet_Req_Dinero
              n:=IntToStr(I);//convierto i a string
              p:='(:I'+n+',:Nro'+n+',:Bs'+n+',:Sus'+n+',:Moti'+n+')';//hago que se cree los parámetros necesarios en esa iteración
              if (i=L.Count-1) then // si es la ultima fila agrego el punto y coma ( ; )
                    SQL.Add(p+';')
              else  SQL.Add(p+',');//sino solamante pongo coma(,)

                //asigno los datos a los parámetros [i] de esa iteracion
              ParamByName('I'+n).AsInteger:=aux.Item;
              ParamByName('Nro'+n).AsInteger:=aux.Nro_R;
              ParamByName('Bs'+n).AsFloat:=aux.MontoBs;
              ParamByName('Sus'+n).AsFloat:=aux.MontoSus;
              ParamByName('Moti'+n).AsString:=aux.Motivo;
            end;
           ExecSQL;// ejecuto la inserción masiva
           Result:=True;
          end;
      finally
      Query.Free;
      end;
 end;
end;
Segunda forma de hacerlo: Usando la funcion Format de la unidad SysUtils, en este caso no se crea ningun parámetro en la consulta SQL, sino mas bien se arma la consulta SQL manualmente:
Código Delphi [-]
function TDet_Req_Dinero.InsertarLista2(L: TObjectList): Boolean;
var I:Integer;
aux:TDet_Req_Dinero;
Query:TZQuery;
s:String;
begin
Result:=True;
if L.Count>0 then //si mi lista tiene elementos
 Begin
    Result:=False;
    Query:=TZQuery.Create(nil);//creo mi Query
      try
         with Query do
          begin
           Connection:=DataModule1.ZConnection1;//asigno el componente Conexion a mi query
           DecimalSeparator:='.';{Cambio el caracter a la variable "DecimalSeparator" de la unidad "SysUtils"
                                  Esto sirve para que los decimales de los datos float me aparescan con punto(.)
                                  y no con coma(,) al hacer la conversion a string usando la funcion "format",
                                  para mas info ver la ayuda}
            SQL.Add('Insert into Req_Dine(Item,Nro_Req,MontoEnBs,MontoEnSus,Motivo)values ');//adicono la primera parte de mi SQL
            for  I:=0  to L.Count-1 do
            begin
              aux:=TDet_Req_Dinero(L.Items[i]);
              s:=Format('(%d,%d,%f,%f,''%s'')',[aux.Item,aux.Nro_R,aux.MontoBs,aux.MontoSus,aux.Motivo]);{Formateo los datos
                                    dentro de mi varible "s", para mas info ver la ayuda de Delphi sobre los diferentes formatos
                                    que se puede dar en la funcion "Format"}
              if (i=L.Count-1) then // si es la ultima fila agrego el punto y coma ( ; )
                    SQL.Add(s+';')
              else  SQL.Add(s+',');//sino solamante pongo coma( , )
            end;
           ExecSQL;// ejecuto la inserción masiva
           Result:=True;
          end;
      finally
      Query.Free;
      DecimalSeparator:=',';//Vuelvo a poner el caracter por defecto de la varible "DecimalSeparator" de la unidad "SysUtils"
      end;
 end;
end;
Espero que le sirva como ejemplo al amigo santiago14..
Saludos...
__________________
"Pedid, y se os dará; buscad, y hallaréis; llamad, y se os abrirá." Mt.7:7

Última edición por rgstuamigo fecha: 20-05-2010 a las 21:53:10.
Responder Con Cita
  #8  
Antiguo 20-05-2010
fled fled is offline
Miembro
 
Registrado: feb 2004
Posts: 18
Poder: 0
fled Va por buen camino
Hola rgstuamigo, estaba checando tus procedimientos y me di cuenta de que utilizas el ZQuery, tiene este algo en especifico por el cual lo utilices, o funcionaria igual con el IBQuery?
Responder Con Cita
  #9  
Antiguo 20-05-2010
Avatar de santiago14
santiago14 santiago14 is offline
Miembro
 
Registrado: sep 2003
Ubicación: Cerrillos, Salta, Argentina
Posts: 583
Poder: 21
santiago14 Va por buen camino
Thumbs up Mil gracias

Mi mas eterno agradecimiento, rgstuamigo, creo que tu PRIMERA SOLUCIÓN, es la que necesito.
Puesto que de esa manera trabajo un poco mas en el módulo del Insert y luego le mando una sola vez el paquete para que Firebird haga la inserción.
Todo por supuesto bajo una transacción que controla la cosa.

Igualmente, esto está hecho para Zeos, yo uso MDO así que voy a hacer las adaptaciones pertinentes y aviso que tal me fue.

Agradezco desde ya a todos por su ayuda.
__________________
Uno es responsable de lo que hace y de lo que omite hacer.
Responder Con Cita
  #10  
Antiguo 20-05-2010
Avatar de santiago14
santiago14 santiago14 is offline
Miembro
 
Registrado: sep 2003
Ubicación: Cerrillos, Salta, Argentina
Posts: 583
Poder: 21
santiago14 Va por buen camino
Smile

Bueno, en principio para Firebird la forma propuesta no funciona. Estoy probando algunas opciones alternativas. Mañana les digo puesto que ya es medio tarde.
__________________
Uno es responsable de lo que hace y de lo que omite hacer.
Responder Con Cita
  #11  
Antiguo 23-05-2010
Avatar de santiago14
santiago14 santiago14 is offline
Miembro
 
Registrado: sep 2003
Ubicación: Cerrillos, Salta, Argentina
Posts: 583
Poder: 21
santiago14 Va por buen camino
Wink

Bueno, investigando un poco encontré esto, igualmente no funciona en Firebird 1.5.
Quisiera que me den una mano.


How to insert multiple rows in a single statement?

There are various approaches. For example, if you wish to insert these:

10 ten
11 eleven
12 twelwe

you can use UNIONs:
Código SQL [-]
INSERT INTO table1 (col1, col2)
SELECT 10, 'ten ' FROM RDB$DATABASE UNION ALL
SELECT 11, 'eleven' FROM RDB$DATABASE UNION ALL
SELECT 12, 'twelwe' FROM RDB$DATABASE;
Please note that datatypes must match (esp. if you use Firebird 1.x).

Lo encontré aqui.

Gracias.
__________________
Uno es responsable de lo que hace y de lo que omite hacer.
Responder Con Cita
  #12  
Antiguo 24-05-2010
Avatar de santiago14
santiago14 santiago14 is offline
Miembro
 
Registrado: sep 2003
Ubicación: Cerrillos, Salta, Argentina
Posts: 583
Poder: 21
santiago14 Va por buen camino
Unhappy

Al intentar operar con el Insert propuesto, Firebird devuelve el siguiente error:

Invalid token.
Dynamic SQL Error.
SQL error code = -104.
Token unknown - line 3, char 1.
UNION.

line 3, char 1: Es donde empieza el primer "UNION"

Esto SI funciona
Código SQL [-]
INSERT INTO table1 (col1, col2)
SELECT 10, 'ten ' FROM RDB$DATABASE;

Esto NO funciona
Código SQL [-]
INSERT INTO table1 (col1, col2)
SELECT 10, 'ten ' FROM RDB$DATABASE 
UNION ALL
SELECT 11, 'eleven' FROM RDB$DATABASE 
UNION ALL
SELECT 12, 'twelwe' FROM RDB$DATABASE;
Repito, uso Firebird 1.5
__________________
Uno es responsable de lo que hace y de lo que omite hacer.

Última edición por santiago14 fecha: 24-05-2010 a las 00:05:26. Razón: Mejora en la sintaxis
Responder Con Cita
  #13  
Antiguo 24-05-2010
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.040
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Aunque funcione, es un poco engorroso, no?
Responder Con Cita
  #14  
Antiguo 24-05-2010
Avatar de santiago14
santiago14 santiago14 is offline
Miembro
 
Registrado: sep 2003
Ubicación: Cerrillos, Salta, Argentina
Posts: 583
Poder: 21
santiago14 Va por buen camino
Thumbs up

Si, es engorroso pero no encuentro una mejor manera de pasar todos los "detalles" a una tabla de una sola vez.
Actualmente hago un "for" sobre la grilla y voy pasando los valores al Insert y luego lo mando (viaja por la red, LAN en este caso) se inserta y doy otro giro del "for"... así hasta terminar. Al final, cierro la transacción.
Si todo fue bien, un maravilloso cartelito de éxitos, sino, un cartel rojo con problemas.

En una red LAN esto va bien, intento hacer lo mismo con Internet en el medio y la cosa cambia...
Estoy intentando conectar una sucursal con la casa central a través de una VPN usando Internet en el medio. De ahí la cuestión.

Bueno, gracias y sigo esperando...
__________________
Uno es responsable de lo que hace y de lo que omite hacer.
Responder Con Cita
  #15  
Antiguo 24-05-2010
Avatar de santiago14
santiago14 santiago14 is offline
Miembro
 
Registrado: sep 2003
Ubicación: Cerrillos, Salta, Argentina
Posts: 583
Poder: 21
santiago14 Va por buen camino
Post

Bueno, debo decir que tengo novedades...
Para empezar, desinstalé Firebird 1.5 y puse Firebird 2.1, hice la prueba y funcionó sin problemas.
Pude insertar sin drama la expresión:
Código SQL [-]
INSERT INTO table1 (col1, col2)
SELECT 10, 'ten ' FROM RDB$DATABASE UNION ALL
SELECT 11, 'eleven' FROM RDB$DATABASE UNION ALL
SELECT 12, 'twelwe' FROM RDB$DATABASE;

Muchas gracias.
Cualquier cosa, estoy a su disposición.
__________________
Uno es responsable de lo que hace y de lo que omite hacer.
Responder Con Cita
  #16  
Antiguo 24-05-2010
Avatar de santiago14
santiago14 santiago14 is offline
Miembro
 
Registrado: sep 2003
Ubicación: Cerrillos, Salta, Argentina
Posts: 583
Poder: 21
santiago14 Va por buen camino
Cita:
Empezado por santiago14 Ver Mensaje
Esto NO funciona
Código SQL [-]
INSERT INTO table1 (col1, col2)
SELECT 10, 'ten ' FROM RDB$DATABASE 
UNION ALL
SELECT 11, 'eleven' FROM RDB$DATABASE 
UNION ALL
SELECT 12, 'twelwe' FROM RDB$DATABASE;
Repito, uso Firebird 1.5
Le envié un mail a la gente de firebirdfaq.org comentándoles que la expresión propuesta por ellos no funcionaba en Firebird 1.5, esto me respondieron:

"It works on 1.5 as well, make sure you put 3 spaces after "ten"

Algo así como: Si trabaja en Firebird 1.5, asegúrese de poner 3 espacios después de "ten"

En el ejemplo de la página no hay tres espacios, tampocon especifican si es antes o después de la comilla. Bueno, para el que tenga el mismo problema que lo pruebe con los espacios después de "ten" y me cuenta.
Yo ya no tengo Firebird 1.5, con todas estas idas y vueltas lo saqué y puse Firebird 2.1.

Saludos.
__________________
Uno es responsable de lo que hace y de lo que omite hacer.
Responder Con Cita
  #17  
Antiguo 24-05-2010
Avatar de guillotmarc
guillotmarc guillotmarc is offline
Miembro
 
Registrado: may 2003
Ubicación: Huelva
Posts: 2.638
Poder: 23
guillotmarc Va por buen camino
La razón por la que hay que añadir esos tres espacios es para que las cadenas sean todas de la misma longitud. En caso contrario Firebird 1.5 no sabe que tipo debe ser el resultado de la unión.

Una forma más fácil de entender (aunque más larga de escribir) es hacerlo así :

INSERT INTO table1 (col1, col2)
SELECT 10, cast('ten' as varchar(20)) FROM RDB$DATABASE
UNION ALL
SELECT 11, cast('eleven' as varchar(20)) FROM RDB$DATABASE
UNION ALL
SELECT 12, cast('twelve' as varchar(20)) FROM RDB$DATABASE;
__________________
Marc Guillot (Hi ha 10 tipus de persones, els que saben binari i els que no).
Responder Con Cita
  #18  
Antiguo 24-05-2010
Avatar de santiago14
santiago14 santiago14 is offline
Miembro
 
Registrado: sep 2003
Ubicación: Cerrillos, Salta, Argentina
Posts: 583
Poder: 21
santiago14 Va por buen camino
Exactamente guillotmarc, exactamente.

Saludos.
__________________
Uno es responsable de lo que hace y de lo que omite hacer.
Responder Con Cita
  #19  
Antiguo 24-05-2010
Avatar de Chris
[Chris] Chris is offline
Miembro Premium
 
Registrado: abr 2007
Ubicación: Jinotepe, Nicaragua
Posts: 1.678
Poder: 19
Chris Va por buen camino
Pues Santiago, creo que al olvidado la Ley de Costo-Beneficio. Una consulta bien hecha, con parámetros y preparada no va a significar mucha diferencia con respecto a una una inserción masiva. Sin embargo, acabo de imaginar la siguiente técnica: Pasar en formato CSV los valores a insertar a un procedimiento almacenado. Éste último se encargará se hacer las respectivas inserciones. Esta técnica no es muy practica y puede que valga la pena aplicarla si es que necesitas de estás inseciones masivas en un numero limitado de casos.

Saludos.
__________________
Perfil Github - @chrramirez - Delphi Blog - Blog Web
Responder Con Cita
  #20  
Antiguo 24-05-2010
Avatar de santiago14
santiago14 santiago14 is offline
Miembro
 
Registrado: sep 2003
Ubicación: Cerrillos, Salta, Argentina
Posts: 583
Poder: 21
santiago14 Va por buen camino
Smile

Habría que hacer algunas pruebas, pero creo que una inserción masiva es mas eficiente que un for con un insert unitario que vaya metiendo datos en la BD. Vuelvo a insistir, en una LAN la diferencia es mínima, pero si se quiere hacer algo mayor, digamos con Internet en el medio, es diferente.
__________________
Uno es responsable de lo que hace y de lo que omite hacer.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Insert masivo en firebird santiago14 Firebird e Interbase 2 24-05-2010 02:50:29
Envio masivo de mensajes via web supermanpy Varios 5 08-05-2010 19:00:26
Update Masivo... BlueSteel SQL 9 30-10-2007 17:11:59
upload masivo kayetano PHP 12 06-12-2006 16:45:39
Traspaso masivo de datos .DBF eibarra Conexión con bases de datos 1 06-04-2005 16:06:59


La franja horaria es GMT +2. Ahora son las 15:29:14.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi