Psycopg2: muliple rows mit multiple columns einfügen

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
psycopg2
User
Beiträge: 2
Registriert: Mittwoch 9. Februar 2022, 12:50

Hallo Zusammen,

ich bin neu hier, sowie ein Anfänger mit Python/Datenbankprogrammierung und hoffe auf hilfreiche Ratschläge.

Nun zum Ausgangsszenario:
Ein TDMS-Dokument mit 93 Spalten und 50000 Zeilen, welches ich in meine postgres-Datenbank prozessieren möchte. Dabei habe ich mir überlegt mit einer for-loop zu arbeiten, in dem dann die Iterationsvariable als placeholder-string fungiert.

Zunächst Verbindung und importieren der TDMS-File (Die Database und Table waren schon vorher erzeugt):

Code: Alles auswählen

import psycopg2

name = input("Which Database?: ")
name_table = input("Which Table shows its columns?: ")
#connect to database
conn_tdms = psycopg2.connect(database = f"{name}", user = "xxxxxx", password = "xxxxxx", host = "xxxxxx", port = "xxxxxx")
conn_tdms.autocommit = True
#create cursor object
cur = conn_tdms.cursor()

#import TDMSfile
from nptdms import TdmsFile
FilePath = r"C:\Users\xxxx\xxx\xxxx\xxxx\my_file.tdms"
tdms_file = TdmsFile.read(FilePath)
group = tdms_file['groupname']
channel = group.channels()
print(group)
print(channel)
Erstellen einer Liste für column names:

Code: Alles auswählen

lists = []
for i in group:
    lists.append(i)
    print(type(i))
print(lists)
Danach entferne ich Whitespaces:

Code: Alles auswählen

he = []
for x in lists:
    z = x.replace(' ','')
    he.append(z)
print(he)
Für die columns der SQL-command:

Code: Alles auswählen

for v in he:
    cur.execute("ALTER TABLE %s ADD column %s character varying(50) NOT NULL DEFAULT 'foo';" % (f'{name_table}', v))
Dies hat gut funktioniert und ich kann alle 93 Spalten in pgAdmin4 sehen.

Bei den rows komme ich leider mit dieser Methode nicht weiter. Ich brauche jeweils den ersten Eintrag von jeder Spalte um einen SQL-Befehl für eine row zu erzeugen.

Vielleicht kann jemand sagen ob dieser Ansatz überhaupt funktioniert? Oder einen besseren Vorschlag?

Ich bin mir nicht sicher ob dies die richtige Herangehensweise für große Datenmengen ist.

Mit freundlichen Grüßen

psycopg2
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Die Benennung deiner Variablen ist so verwirrend, da gehört schon raten dazu, zu verstehen was du da tust.

Ich würde im Code auch keine Spalten dynamisch anlegen (und sicher nicht "foo" darin eintragen, wenn kein Wert kommt), sondern die Spalten einmal fest definieren.

50.000 Zeilen halte ich nicht für eine besonders große Datenmenge.

autocommit solltest du nicht verwenden, wenn es darum geht viele Datensätze auf einmal in die Datenbank zu schreiben. Es sei denn, du hast Zeit. Ohne musst du dich natürlich selbst um den Commit kümmern.

Hier gibt es Tipps, wenn es darum geht viel Schnell in die Datenbank zu bringen.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@psycopg2: Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).

Und bitte verwende sinnvolle Namen, nicht irgendwelche kryptischen Abkürzungen oder irreführende oder unvollständige Namen. Also `database_name` und `table_name` statt `name` und `name_table`. Ein Tabellenname ist was anderes als eine Namentabelle.

Was soll ``f"{name}"`` bringen wenn `name` bereits an eine Zeichenkette gebunden ist? Gleiche Frage bei ``f'{name_table}'`` und warum das dann per uraltem ``%``-Operator in eine Zeichenkette formatieren wenn Du doch f-Zeichenkettenliterale schon kennst. Dafür sind die doch da.

`i` als Laufvariablen für etwas anderes als eine ganze Zahl geht gar nicht. `lists`, `he`, `x`, `z`, `v`? Da weiss doch kein Mensch was das soll und was die Werte dahinter bedeuten.

Man muss auch nicht mehrere Listen für jeden kleinen Schritt anlegen und auch nicht jedes Zwischenergebnis an einen Namen binden.

Code: Alles auswählen

   ...
    lists = []
    for i in group:
        lists.append(i)
        print(type(i))
    print(lists)

    he = []
    for x in lists:
        z = x.replace(" ", "")
        he.append(z)
    print(he)

    for v in he:
        cursor.execute(
            "ALTER TABLE %s ADD column %s character varying(50) NOT NULL DEFAULT 'foo';"
            % (f"{table_name}", v)
        )

# =>

    ...
    for column_name in (column_name.replace(" ", "") for column_name in group):
        cursor.execute(
            f"ALTER TABLE {table_name}"
            f" ADD COLUMN {column_name} CHARACTER VARYING(50)"
            f" NOT NULL DEFAULT 'foo';"
        )
Eine Tabelle mit 93 Spalten die dynamisch erzeugt werden riecht komisch. Und der dynamische Tabellenname im Grunde auch.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Da hier postgres genutzt wird ein kleiner aber wichtiger Hinweis aus der postgres Dokumentation:
There is no performance difference among these three types [character varying, character, text], apart from increased storage space when using the blank-padded type [character], and a few extra CPU cycles to check the length when storing into a length-constrained column.
https://www.postgresql.org/docs/current ... acter.html

Von daher würde ich empfehlen einfach "text" zu verwenden, es sei den es ist wirklich wichtig dass Werte nur eine ganz bestimmte Länge haben. "character varying" mit einer Länge die nach dem "wird schon genug sein" Prinzip gewählt ist, ist häufig irgendwann dann doch nicht mehr genug. Kommt man in so eine Situation ist dass schon recht ärgerlich.
psycopg2
User
Beiträge: 2
Registriert: Mittwoch 9. Februar 2022, 12:50

Guten Abend,

vielen Dank für die Beiträge.

Ich konnte mein Problem lösen, indem ich meine File in einen Panda-Dataframe konvertiert habe. Danach konnte ich es mit SQL-Alchemy relativ einfach übertragen.

Mit freundlichen Grüßen

psycopg2
Antworten