2016-10-08 5 views
1

Ich habe eine „Schlüssel“ Datei (Mächtigkeit Reihenfolge), die wie folgt aussieht:Need UPDATE-Anweisung forumulate basierend auf entsprechenden Wert

ID 
Name 
Job 

Dann habe ich eine bearbeitete bin.log aus einer fehlerhaften Update-Anweisung in der folgendes Format:

1 
'Joe' 
'Grocer' 
2 
'Bill' 
'Mason' 

Was muss ich tun, um die entsprechenden „Schlüssel“ Datei, Update-Anweisungen zu formulieren, so das Ergebnis ist wie folgt:

update database.table set Name='Joe', Job='Grocer' WHERE ID=1; 
update database.table set Name='Bill', Job='Mason' WHERE ID=2; 

Diese müssen jedoch für mehrere Datenspalten arbeiten. Das erste Feld in der Schlüsseldatei wird immer ein einzelner Primärschlüssel sein. Mit anderen Worten, die WHERE-Klausel in der update-Anweisung verwendet immer diese Zeile in der Schlüsseldatei. Alles unter der ersten Zeile in der Schlüsseldatei sind die Spalten, die in der Reihenfolge, in der sie auftreten, "SET" sein müssen.

In diesem Beispiel wird ID die Spalte in der WHERE-Klausel sein, und "Name" wird zuerst auf die entsprechende Zeile in bin.log und dann auf "Job" usw. gesetzt. Nur in diesem Beispiel hat drei Zeilen in der Schlüsseldatei, kann es eine beliebige Anzahl von Zeilen geben. Die erste Zeile wird jedoch immer die Spalte sein, die für das Ende der WHERE-Anweisung der Update-Anweisung verwendet wird.

+0

Konzeptionell habe ich versucht, Zeilenanzahl von beiden Dateien zu bekommen und eine Weile innerhalb einer Weile zu laufen, aber ich kann nicht die richtige Logik bekommen. Um ehrlich zu sein. Ich habe einige Beispiele angeführt, bei denen ich genau wusste, wie viele Zeilen ich bekam, aber diese willkürliche Menge verursacht mir einige Verwirrung. Ich habe auch darüber nachgedacht, Text vor jeder Zeile anzuhängen und dann awk zu verwenden, um die Felder in verschiedenen Positionen einzufügen, aber keine davon scheint eine gute Idee zu sein. – user3299633

Antwort

1

hier ein Rohentwurf eines Skripts ist, das tut, was Sie wollen. Wenn Sie es mögen, können wir es für Effizienz, Stil, Korrektheit verbessern.

generate_statement.sh:

#!/usr/bin/bash 
read -r -a cnames <<< "$(echo $(cat cnames))" 
numcols=${#cnames[@]} 

counter=0; sclause="" 

while read -r cvalue 
do 
    if (($counter == 0)) 
    then 
     keys_value=$cvalue 
    elif (($counter == $numcols-1)) 
    then 
     sclause="$sclause, ${cnames[$counter]}=$cvalue" 
     read -r sclause <<< "$(echo $sclause | sed 's/,//')" 
     echo "update database.table set $sclause where ${cnames[0]}=$keys_value;" 
     sclause="" 
    else 
     sclause="$sclause, ${cnames[$counter]}=$cvalue" 
    fi 
    ((counter = ++counter % numcols)) 
done <<< "$(cat cvalues)" 

cnames:

ID 
Name 
Job 
Height 
Weight 

cvalues:

1 
'Joe' 
'Grocer' 
60 
160 
2 
'Bill' 
'Mason' 
61 
170 
3 
'John' 
'Engineer' 
65 
180 
4 
'Jack' 
'Doctor' 
69 
190 

Ausgang:

update database.table set Name='Joe', Job='Grocer', Height=60, Weight=160 where ID=1; 
update database.table set Name='Bill', Job='Mason', Height=61, Weight=170 where ID=2; 
update database.table set Name='John', Job='Engineer', Height=65, Weight=180 where ID=3; 
update database.table set Name='Jack', Job='Doctor', Height=69, Weight=190 where ID=4; 
+0

potong und deine Antwort funktionieren genau so, wie ich es möchte. Ich werde wahrscheinlich Ihre verwenden, weil ich verstehen kann, was es tut. Ich wünschte, ich könnte den Kredit zwischen euch teilen, aber ich denke, ich muss es der Person geben, die zuerst mit der richtigen Lösung geantwortet hat. – user3299633

+0

Es tut mir leid, dass ich die Zeiten erneut überprüft habe und Sie waren in der Tat zuerst zu antworten, also werde ich Ihre Antwort richtig markieren. – user3299633

+0

Das wird auf seltsame und wunderbare Weise scheitern, wenn man verschiedene mögliche Eingabewerte, Umgebungsvariablen und Verzeichnisinhalte, aus denen Sie es ausführen, angibt. Siehe [why-is-using-a-shell-loop-to-process-text-built-bad-practice] (http://unix.stackexchange.com/questions/169716/why-is-using-a-shell) -loop-to-process-text-built-practice), um einige, aber nicht alle, Gründe dafür zu verstehen, dies nicht zu tun. Und nein, ich würde definitiv nicht vorschlagen, dass du einen Haufen Runen verwendest, die dem Wort "sed" folgen. –

3
awk ' 
    NR==FNR { a[++m]=$0; next } 
    { 
     n = ((FNR-1) % m) + 1 
     v[n] = $0 
    } 
    n == m { 
     printf "update database.table set %s=%s, %s=%s WHERE %s=%s;\n", a[2], v[2], a[3], v[3], a[1], v[1] 
    } 
' file bin.log 
update database.table set Name='Joe', Job='Grocer' WHERE ID=1; 
update database.table set Name='Bill', Job='Mason' WHERE ID=2; 

Wenn Ihr Problem wirklich as @blackpen guessed ist dann die zwicken, um es Arbeit wäre:

$ cat tst.awk 
NR==FNR { a[++m]=$0; next } 
{ 
    n = ((FNR-1) % m) + 1 
    v[n] = $0 
} 
n == m { 
    printf "update database.table set" 
    for(i=2; i<=n; i++) { 
     printf "%s %s=%s", (i>2 ? "," : ""), a[i], v[i] 
    } 
    printf " WHERE %s=%s;\n", a[1], v[1] 
} 

$ awk -f tst.awk file bin.log 
update database.table set Name='Joe', Job='Grocer' WHERE ID=1; 
update database.table set Name='Bill', Job='Mason' WHERE ID=2; 
+0

Wo zieht es die zwei Dateinamen? Und es sieht so aus, als würde das nur mit einer bestimmten Anzahl von Spalten funktionieren ... – user3299633

+0

Ich meine, es könnte mehr geben als nur Name und Job - es könnte eine beliebige Anzahl von Spalten wie Adresse, Suite usw. geben. – user3299633

+0

Die Datei erfordert manuelle Eingabe von Spalten. Zum Beispiel gibt der Benutzer ID, Name, Job ein - aber das Binlog, das ebenfalls enthalten ist, hat jede Spalte, die in der Tabelle verfügbar ist. Basierend auf einer Anzahl von Zeilen in der ersten Datei wird der binlog so zugeschnitten, dass nur die entsprechenden Informationen aufgelistet werden. Vor dem Schritt zum Verarbeiten der Update-Anweisungen wird daher bereits eine "bereinigte" binlog-Datei vorliegen. – user3299633

1

Dies könnte für Sie arbeiten (GNU sed):

sed -r 's#.*#s/.*/&=\&/#;1s#$#;h#;1!s#.*#n;&;H#;$s#$#;x;s/^([^\\n]*)\\n(.*)/update.database.table set \\2 WHERE \\1;/;s/\\n/, /gp#' file | 
sed -nrf - log 

die Datei in ein sed-Skript drehen sie dann gegen das Protokoll laufen.

+0

Das macht genau das, was ich will. Ich kann es auf keinen Fall verstehen (laut lachen), aber es funktioniert. Vielleicht kann ich in ein paar Jahren sed besser (hoffentlich) interpretieren. – user3299633