2017-01-26 4 views
0

Ich habe einen wöchentlichen Prozess, der einen vollständigen Ersetzungsvorgang an einigen Tabellen ausführt. Der Prozess erfolgt wöchentlich, da insgesamt große Datenmengen vorliegen. Wir möchten jedoch auch tägliche/stündliche Delta-Aktualisierungen durchführen, damit das System besser mit der Produktion synchronisiert ist.Deduplizieren einer Tabelle, während Datensatzstrukturen beibehalten werden

Wenn wir Daten aktualisieren, erstellen wir Duplikate von Zeilen (Updates einer vorhandenen Zeile), die ich loswerden möchte. Um dies zu erreichen, habe ich einen Python-Skript geschrieben, läuft die folgende Abfrage auf einer Tabelle, die Ergebnisse zurück in sie eingefügt:

QUERY = """#standardSQL 
      select {fields} 
      from (
       select * 
       , max(record_insert_time) over (partition by id) as max_record_insert_time 
       from {client_name}_{environment}.{table} as a 
      ) 
      where 1=1 
      and record_insert_time = max_record_insert_time""" 

Die {fields} Variable mit einer Liste aller Tabellenspalten ersetzt werden; Ich kann * hier nicht verwenden, weil das nur für 1 Lauf funktionieren würde (das nächste wird bereits ein Feld haben, das max_record_insert_time genannt wird und das ein Mehrdeutigkeits-Problem verursachen würde).

Alles funktioniert wie erwartet, mit einer Ausnahme - einige der Spalten in der Tabelle sind von RECORD Datentypen; Obwohl sie keine Aliase für sie verwenden und ihren vollständig qualifizierten Namen auswählen (z. B. record_name.child_name), werden die Ergebnisse bei der Rückkehr der Ausgabe in die Tabelle abgeflacht. Ich habe die flattenResults: False Konfiguration zu meinem Code hinzugefügt, aber das hat das Ergebnis nicht geändert.

Ich würde gerne Gedanken darüber hören, wie dieses Problem gelöst werden kann, indem ich meinen bestehenden Plan, andere Methoden der Deduplizierung oder andere Methoden zur Handhabung von Delta-Updates insgesamt nutze.

Antwort

2

Vielleicht können Sie in der äußeren Anweisung

SELECT * EXCEPT (max_record_insert_time)

Dies sollte die genaue Satzstruktur halten. (Detaillierte Dokumentation https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select-except)

Alternative Ansatz, in {fields} nur Spalten oberster Ebene einschließen würde, auch wenn sie nicht Blätter sind, also nur record_name und nicht record_name.*

+0

Holy Moly! Ist das eine einzigartige BQ-Funktion? Ich bin noch nie auf diese Syntax gestoßen! Sehen Sie es auch nicht in der Dokumentation. –

+2

Sie können darüber das Thema "Query Syntax" lesen (https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select-except). –

0

Below Antwort ist definitiv nicht besser als die Verwendung von einfach SELECT * EXCEPT Modifikator, wollte aber

SELECT t.* 
FROM (
    SELECT 
    id, MAX(record_insert_time) AS max_record_insert_time, 
    ARRAY_AGG(t) AS all_records_for_id 
    FROM yourTable AS t GROUP BY id 
), UNNEST(all_records_for_id) AS t 
WHERE t.record_insert_time = max_record_insert_time 
ORDER BY id 

Was obige Abfrage hat ist es, alternative Version präsentieren - erste Gruppen alle Datensätze fo r jeweils id in array of respective rows zusammen mit max value for insert_time. Dann flacht es für jede ID einfach alle (zuvor aggregierten) Zeilen ab und wählt nur Zeilen mit insert_time, die mit der maximalen Zeit übereinstimmt. Ergebnis ist wie erwartet. No Analytic Function beteiligt aber eher einfach Aggregation. Aber zusätzliche Verwendung von UNNEST ... Immer noch - zumindest andere Option: o)

+0

Dies ist ein interessanter Ansatz. Kleine Klärung - aus meiner Erfahrung mit BigQuery, wenn man eine Tabelle aliasiert und eine Auswahl unter Verwendung des Tabellenalias ohne einen zweiten Alias ​​ausführt, um die ausgewählte Spalte umzubenennen (z. B. "t.field' vs.' t.field as field "), die Ausgabe wird immer 't_' zu jedem Feldnamen führen. Meine Erfahrung beschränkt sich jedoch größtenteils auf das Legacy-SQL, daher wird dies möglicherweise in Standard-SQL anders gehandhabt. Wird das nicht der Fall sein? –

+1

Dies ist korrekt für Legacy-SQL.aber in standard sql t_ wird nicht hinzugefügt. So erhalten Sie genau die originale Struktur/Benennung –

Verwandte Themen