2010-06-08 9 views
5

Necesito código SQL para resolver el problema combinación de tablas, se describe en el apartado siguiente:Necesita un enfoque instrucción SQL en la combinación de mesas pero las entradas siempre con la identificación única

tabla de datos antigua: mesa de edad

name  version status lastupdate  ID 
    A  0.1  on  6/8/2010  1 
    B  0.1  on  6/8/2010  2 
    C  0.1  on  6/8/2010  3 
    D  0.1  on  6/8/2010  4 
    E  0.1  on  6/8/2010  5 
    F  0.1  on  6/8/2010  6 
    G  0.1  on  6/8/2010  7 

tabla nuevos datos: tabla nueva

name  version status lastupdate  ID   
    A  0.1  on  6/18/2010     
                  #B entry deleted 
    C  0.3  on  6/18/2010    #version_updated 
    C1  0.1  on  6/18/2010    #new_added 
    D  0.1  on  6/18/2010     
    E  0.1  off  6/18/2010    #status_updated 
    F  0.1  on  6/18/2010     
    G  0.1  on  6/18/2010     
    H  0.1  on  6/18/2010    #new_added 
    H1  0.1  on  6/18/2010    #new_added 

la diferencia de los nuevos datos y la fecha antigua:

entrada B elimina

versión de entrada C actualiza

nuevo añadido

Lo que quiero siempre es mantener el ID actualizado el estado de la entrada E de entrada

C1/H/H1 - Relación de nombre mapeo de edad tabla de datos sin importar cómo cambiaron los datos más tarde, también conocido como el nombre siempre tiene un número de identificación único vinculado con él.

Si la entrada tiene una actualización, actualice los datos, si la entrada es nueva, inserte en la tabla y luego proporcione una nueva ID única asignada. Si la entrada fue eliminada, elimine la entrada y no reutilice esa identificación más adelante.

Sin embargo, solo puedo usar SQL con una declaración simple de selección o actualización, entonces puede ser muy difícil para mí escribir dicho código, entonces espero que alguien con experiencia pueda dar instrucciones, no se necesitan detalles sobre las diferentes variantes SQL, el código sql estándar como muestra es suficiente.

¡Gracias de antemano!

Rgs

KC

======== me aparece mi proyecto sql aquí, pero no estoy seguro si funciona, alguien con experiencia comentario pls, gracias!

1.duplicate mesa antigua como TMP para almacenar actualizaciones

crean tmp tabla como seleccionar * de edad

2.Update en tmp donde el "nombre" es la misma en la tabla vieja y la nueva

actualización tmp donde el nombre de (seleccione el nombre de nuevo)

3.Inserte "nombre" diferente (viejo contra nuevo) en tmp y asignar nuevo ID

insertar en tmp (nombre de versión de estado lastupdate ID) establecer idvar = max (seleccionar max (id) de tmp) + 1 seleccionar * de (seleccionar nuevo.nombre nuevo.versión nuevo.Estado nuevo.última actualización nuevo.ID de viejo, nuevo donde old.name <> new.name)

4. eliminar las entradas eliminadas de la tabla tmp (tales como B)

eliminar en tmp donde (seleccione ???)

+0

¿No tiene la ID en la nueva tabla de datos? – tzup

+0

Su resultado de muestra no es indicativo de lo que espera dada su descripción. ¿Es el caso que quieres que las ID sigan siendo secuenciales? – Thomas

+0

Además, ¿qué producto de base de datos y versión está usando? – Thomas

Respuesta

1

Nunca se ha mencionado lo DBMS está utilizando, pero si usted está utilizando SQL Server, una muy buena es la instrucción SQL MERGE. Ver: http://www.mssqltips.com/tip.asp?tip=1704

La instrucción MERGE básicamente funciona como inserto separado, actualizar y eliminar declaraciones todo dentro del mismo comunicado. Se especifica una "fuente" conjunto de registros y una mesa de "destino", y la unión entre los dos. A continuación, especifica el tipo de modificación de datos que debe ocurrir cuando los registros entre los dos datos coinciden o no coinciden. MERGE es muy útil, especialmente cuando se trata de cargar tablas de almacenamiento de datos, que pueden ser muy grandes y requieren acciones específicas que deben tomarse cuando las filas son no están presentes.

Ejemplo:

MERGE Products AS TARGET 
USING UpdatedProducts AS SOURCE 
ON (TARGET.ProductID = SOURCE.ProductID) 
--When records are matched, update 
--the records if there is any change 
WHEN MATCHED AND TARGET.ProductName <> SOURCE.ProductName 
OR TARGET.Rate <> SOURCE.Rate THEN 
UPDATE SET TARGET.ProductName = SOURCE.ProductName, 
TARGET.Rate = SOURCE.Rate 
--When no records are matched, insert 
--the incoming records from source 
--table to target table 
WHEN NOT MATCHED BY TARGET THEN 
INSERT (ProductID, ProductName, Rate) 
VALUES (SOURCE.ProductID, SOURCE.ProductName, SOURCE.Rate) 
--When there is a row that exists in target table and 
--same record does not exist in source table 
--then delete this record from target table 
WHEN NOT MATCHED BY SOURCE THEN 
DELETE 
--$action specifies a column of type nvarchar(10) 
--in the OUTPUT clause that returns one of three 
--values for each row: 'INSERT', 'UPDATE', or 'DELETE', 
--according to the action that was performed on that row 
OUTPUT $action, 
DELETED.ProductID AS TargetProductID, 
DELETED.ProductName AS TargetProductName, 
DELETED.Rate AS TargetRate, 
INSERTED.ProductID AS SourceProductID, 
INSERTED.ProductName AS SourceProductName, 
INSERTED.Rate AS SourceRate; 
SELECT @@ROWCOUNT; 
GO 
+0

creo que la tabla de destino no tendrá la ID. Creo que OP tiene una tabla (tabla anterior) con ID y datos asociados. OP obtiene el nuevo conjunto de datos asociados. OP quiere hacer estos cambios en la tabla original haciendo coincidir en la columna de nombre. Por supuesto, podría estar leyendo todo mal :-) – potatopeelings

1

Empezaré desde el final:

En # 4, deberá eliminar todas las filas de tmp; lo que quería decir que hay WHERE tmp.name NOT IN (SELECT name FROM new); Del mismo modo # 3 no es la sintaxis correcta, pero si fue que trataría de insertar todas las filas.

En cuanto a # 2, por qué no usar auto increment en el ID?

Respecto del n. ° 1, si su tabla tmp es la misma que la nueva, las consultas n. ° 2-4 no tienen sentido, a menos que cambie (actualice, inserte, elimine) la tabla new de alguna manera.

Pero (!), Si usted actualizar la tabla new y tiene un campo de incremento automático en ID y si está actualizando correctamente la tabla (utilizando ID) de la aplicación a continuación, todo el procedimiento es innecesaria (!).

Por lo tanto, lo importante es que no se debe diseñar el sistema para que funcione como la de arriba.

Para obtener el concepto de actualización de datos en la base de datos desde la aplicación, eche un vistazo a los ejemplos here (php/mysql).

Además, para obtener la sintaxis correcta en sus consultas, vaya a la versión básica de los comandos SET, INSERT, DELETE y SELECT (no hay forma de evitar esto).

+0

gracias por su corrección, Sinrazón. Para el n. ° 2, si utilizo el incremento automático en el n. ° 2, si alguien insertó entradas que no se espera, también obtendrá una identificación, será difícil averiguar dónde está más tarde y luego jugar seguro. y simple, quiero que los datos se validen antes de que se asigne la ID, porque esos datos se actualizan/insertan sin ID, entonces será mucho más fácil agregar el mecanismo de verificación de alguna manera después de que tenga la idea principal de cómo reproducir la mayoría de SQL para esta historia. –

+0

acepto que no debe aceptar los datos que no se esperan en su base de datos, pero nuevamente, debe verificar los datos antes de insertarlos. puede hacerlo desde la aplicación (en el código de la aplicación) o desde la base de datos (verificaciones y otras reglas de integridad, más desencadenantes); o mejor en ambos lugares - en la capa de aplicación para el rendimiento y en la base de datos para la tranquilidad (aunque un poco más de mantenimiento). esto no tiene nada que ver con tener una mesa temporal. es muy, muy probable que la tabla temporal en su caso no solo sea redundante, sino que conducirá a todo tipo de complejidades. – Unreason

+0

al final básicamente terminará sincronizando dos tablas y eso puede ser muy complicado en multiuso real con escenarios de manejo de errores (especialmente si la atomicidad, consistencia, aislamiento y durabilidad son importantes) o, por otro lado (y esto es lo más probable en su caso) simplemente no es necesario. – Unreason

1

Nota - si usted está preocupado por el rendimiento puede omitir toda esta respuesta :-)

Si se puede rediseñar tener 2 mesas - uno con los datos y otra con el nombre - vinculación de identificación.Algo así como

table_original

name  version status lastupdate 
A  0.1  on  6/8/2010 
B  0.1  on  6/8/2010 
C  0.1  on  6/8/2010 
D  0.1  on  6/8/2010 
E  0.1  on  6/8/2010 
F  0.1  on  6/8/2010 
G  0.1  on  6/8/2010 

y name_id

name  ID 
A  1 
B  2 
C  3 
D  4 
E  5 
F  6 
G  7 

Al obtener el table_new con el nuevo conjunto de datos

  1. TRUNCATE table_original
  2. insertar en name_id (nombres de tabla_nuevo no en nombre_id)
  3. copia table_new a table_original

Nota: Creo que hay un poco de ambigüedad acerca de la supresión aquí

Si se eliminó la entrada, elimine la entrada y no vuelva a usar esa identificación posterior.

Si el nombre A se borra, y vuelve a aparecer en un conjunto posterior de actualizaciones, ¿desea a. reutilizar la identificación original etiquetada a A, o b. generar una nueva identificación?

Si es b. necesitas una columna eliminada? en name_id y un último paso

4. establecido eliminado? = Y donde el nombre no está en table_original

y 2. ¿Excluiría eliminado? = Registros Y

También podría hacer lo mismo sin la tabla name_id en base a la lógica de que lo único que necesita de table_old es el nombre - Enlaces de ID. Todo lo que necesita está en table_new,

+0

gracias, ¿podría tomar un tiempo para leer mi comentario a continuación cuando sea libre? –

0

un enfoque elaborado, no tengo ni idea de si funciona bien ......

CREATE TRIGGER auto_next_id después del cuadro INSERTAR EN FILA PARA CADA COMENZAR UPDATE tabla SET uid = max (uid) + 1; END;

1

Esto funciona en Informix y proporciona exactamente la pantalla que necesita. Igual o similar debería funcionar en MySQL, uno pensaría. El truco aquí es obtener la unión de todos los nombres en una tabla temporal y dejarla unir para que se puedan comparar los valores de los otros dos.

 
SELECT DISTINCT name FROM old 
UNION 
SELECT DISTINCT name FROM new 
INTO TEMP _tmp; 

SELECT 
    CASE WHEN b.name IS NULL THEN '' 
     ELSE aa.name 
     END AS name, 
    CASE WHEN b.version IS NULL THEN '' 
     WHEN a.version = b.version THEN a.version 
     ELSE b.version 
     END AS version, 
    CASE WHEN a.status = b.status THEN a.status 
     WHEN b.status IS NULL THEN '' 
     ELSE b.status 
     END AS status, 
    CASE WHEN a.lastupdate = b.lastupdate THEN a.lastupdate 
     WHEN b.lastupdate IS NULL THEN null 
     ELSE b.lastupdate 
     END AS lastupdate, 
    CASE WHEN a.name IS NULL THEN '#new_added' 
     WHEN b.name IS NULL THEN '#' || aa.name || ' entry deleted' 
     WHEN a.version b.version THEN '#version_updated' 
     WHEN a.status b.status THEN '#status_updated' 
     ELSE '' 
    END AS change 
    FROM _tmp aa 
    LEFT JOIN old a 
     ON a.name = aa.name 
    LEFT JOIN new b 
     ON b.name = aa.name; 
0

Si he entendido bien lo que necesita sobre la base de los comentarios en las dos tablas, creo que se puede simplificar mucho su problema si no se fusionan o actualizar la tabla de edad, porque lo que necesita es nueva tabla con los ID en la tabla anterior cuando existen y nuevos ID cuando no existen, ¿verdad?

Nuevos registros: mesa de nueva cuenta los nuevos registros ya - OK (pero necesitan un nuevo ID) Registros borrados: ellos no están en la tabla nueva - OK registros actualizados: ya actualizado en la tabla nueva - Aceptar (necesidad de copiado de identificación de la mesa de edad) registros no modificados: ya en la tabla nueva - Aceptar (necesidad de copiar Identificación de la mesa de edad)

Así que lo único que tiene que hacer es: (a) copiar los ID de la mesa de edad para hacer una tabla nueva cuando existen (b) cree nuevos ID en la tabla nueva cuando no existan en la tabla anterior (c) copie la tabla nueva en la tabla anterior.

(a) ACTUALIZAR nuevo IDENTIFICACIÓN = IFNULL ((SELECCIONAR ID FROM antiguo DONDE new.name = old.name), 0);

(b) ACTUALIZAR nuevo ID SET = FUNCIÓN_TO GENERATE_ID (new.name) WHERE ID = 0;

(c) Drop table old; CREAR TABLA antigua (selecciona * de nuevo);

Como no sé qué base de datos SQL está utilizando, en (b) puede usar una función sql para generar la identificación única en función de la base de datos. Con SQL Server, newid(), con postgresql (versiones no demasiado antiguas), ahora() parece una buena opción ya que su precisión parece suficiente (pero no en otras bases de datos como MySQL, por ejemplo, ya que creo que la precisión está limitada a segundos)

Editar: Lo siento, no había visto que está usando sqlite y python. En este caso, puede usar la función str (uuid.uuid4()) (módulo uuid) en python para generar el uuid y completar el ID en la nueva tabla donde ID = 0 en el paso (b). De esta forma, podrá unir 2 bases de datos independientes si es necesario sin conflictos en los ID.

0

¿Por qué no utiliza un UUID para esto? Genere una vez para un complemento, e incorpórelo/guárdelo en el complemento, no en el DB. Ahora que lo mencionas pitón, aquí es cómo generar es:

import uuid 
UID = str(uuid.uuid4()) # this will yield new UUID string 

Claro que no garantiza la unicidad global, pero lo más probable se obtiene la misma cadena en su proyecto es bastante bajo.

Cuestiones relacionadas