2013-05-09 5 views
9

Esiste un modo "semi-portatile" per ottenere md5() o sha1() di un'intera riga? (O meglio, di un intero gruppo di righe ordinate da tutti i loro campi, ad esempio order by 1,2,3,...,n)? Sfortunatamente non tutti i DB sono PostgreSQL ... Devo occuparmi di almeno Microsoft SQL Server, Sybase e Oracle.Modo SQL per ottenere MD5 o SHA1 di un'intera riga

Idealmente, mi piacerebbe avere un aggregatore (lato server) e usarlo per rilevare le modifiche in gruppi di righe. Ad esempio, nelle tabelle che hanno una colonna timestamp, vorrei memorizzare una firma univoca per, diciamo, ogni mese. Poi ho potuto rilevare rapidamente i mesi che sono cambiati dalla mia ultima visita (sto specchiando certe tabelle a un server che esegue Greenplum) e li ricarico.

Ho esaminato alcune opzioni, ad es. checksum(*) in tsql (horror: è molto soggetto alle collisioni, poiché è basato su un gruppo di XOR e valori a 32 bit) e hashbytes('MD5', field), ma quest'ultimo non può essere applicato a un'intera riga. E questo mi darebbe una soluzione solo per uno dei gusti SQL con cui ho a che fare.

Qualche idea? Anche solo per uno degli idiomi SQL sopra menzionati, sarebbe fantastico.

risposta

8

È possibile calcolare il valore hashbytes per l'intera riga su un trigger di aggiornamento, l'ho utilizzato come parte di un processo ETL in cui in precedenza si confrontavano tutte le colonne nelle tabelle, l'aumento di velocità era enorme.

Hashbytes funziona su varchar, nvarchar o tipi di dati varbinary, e ho voluto confrontare chiavi intere e campi di testo, gettando tutto ciò sarebbe stato un incubo, quindi ho usato la clausola FOR XML in SQL Server come segue:

CREATE TRIGGER get_hash_value ON staging_table 
FOR UPDATE, INSERT AS 
UPDATE staging_table 
SET sha1_hash = (SELECT hashbytes('sha1', (SELECT col1, col2, col3 FOR XML RAW))) 
GO 

in alternativa, è possibile calcolare i valori in modo simile all'esterno di un trigger, se si prevede di eseguire molti aggiornamenti su tutte le righe utilizzando anche una sottoquery con la clausola for xml. Se stai percorrendo questa rotta, puoi persino cambiarla in SELECT *, ma non nel trigger, poiché ogni volta che la eseguirai otterrai un valore diverso perché la colonna sha1_hash sarebbe diversa ogni volta.

Si potrebbe modificare l'istruzione select per ottenere più di 1 fila

3

In MSSQL - È possibile utilizzare HashBytes su tutta la riga utilizzando XML ..

SELECT MBT.id, 
    hashbytes('MD5', 
       (SELECT MBT.* 
       FROM (
         VALUES(NULL))foo(bar) 
       FOR xml auto)) AS [Hash] 
FROM <Table> AS MBT; 

È necessario la clausola from (values(null))foo(bar) a usa xml auto, non serve ad altro scopo ..