Sql-Abfrage flexibel gestalten

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Benutzeravatar
16_Bit
User
Beiträge: 21
Registriert: Donnerstag 26. März 2020, 14:14

Hallo,

ich habe mehrere Tabellen die unter anderem eine Spalte mit der Bezeichnung 'dateinummer' enthalten. Nun möchte ich bei genannter Spalte feststellen, ob es Lücken bei den Nummern gibt. Zum Beispiel:

Code: Alles auswählen

1001
1002
1005
1006
1008
Hier muss dann 1003, 1004 und 1007 gefunden werden.

Diese Aufgabe erfüllt diese Abfrage bereits.

Code: Alles auswählen

SELECT A.X FROM (
WITH RECURSIVE
     cnt(X) AS (VALUES(28491) UNION ALL SELECT X+1 FROM cnt WHERE X < (32709)) 
SELECT X FROM cnt ) A LEFT JOIN ( SELECT CAST( dateinummer AS NUMBER ) AS dateinummer FROM tabellenname_platzhalter WHERE dateinummer >= 28491 and dateinummer <= 32709 ) B
ON A.X = B.DATEINUMMER
WHERE B.DATEINUMMER IS NULL
LIMIT ( 32709 - 28491 + 1 )
Wenn ihr eine andere elegantere Variante für SQLite kennt, könnt ihr diese gerne mitteilen.

Mein Problem ist jetzt jedoch ein anderes. Die Zahlen 32709 und 28491 und der Tabellenname (tabellenname_platzhalter) sollen veränderbar sein. Ich habe leider keinen blassen Schimmer, wie ich das nach Python 3 übersetze.

Wie kann ich diese drei Variablen in das SQL einbauen?

Code: Alles auswählen

number_from
number_to
tablename
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Nein, Tabellennamen sollen nicht veränderbar sein, alles andere geht über Platzhalter. Welche hängt von der verwendeten Datenbankanbindung ab.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Dazu müsstest du string formatting nutzen, wobei du natürlich schauen musst wie du SQL Injection verhinderst.

@Sirius3: Ich glaub man kann davon ausgehen dass jemand von recursive CTEs nicht nur gehört hat sondern sie auch einsetzen kann auch schon mal von SQL Injection gehört hat und sich den Risiken bewusst ist.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@DasIch: Stringformatierung ist ja nur nötig, wenn tatsächlich jemand den Tabellennamen variabel machen will. Aber dann ist das Datenbank-Design schon kaputt.

Ich denke, den SQL-Ausdruck kann man sich irgendwoher ergoogeln,
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Variable Tabellennamen sind sicherlich eine red flag aber es gibt dafür durchaus legitime Gründe. Partitioning wäre so ein Grund.

Ich hab übrigens festgestellt dass SQLAlchemy nicht nur Variable Spaltennamen unterstützt sondern auch Variable Tabellennamen: https://docs.sqlalchemy.org/en/13/core/ ... ion-column
Benutzeravatar
16_Bit
User
Beiträge: 21
Registriert: Donnerstag 26. März 2020, 14:14

Zum testen habe ich diesen Code erst mal geschrieben.

Code: Alles auswählen

def suche_luecken(mandant):
    sql_vp = 'SELECT A.X FROM (WITH RECURSIVE cnt(X) AS (VALUES((SELECT MIN(dateinummer) FROM VP)) \
        UNION ALL SELECT X+1 FROM cnt WHERE X < ((SELECT MAX(dateinummer) FROM VP))) \
        SELECT X FROM cnt ) A LEFT JOIN ( SELECT CAST( dateinummer AS NUMBER ) AS dateinummer \
        FROM VP WHERE dateinummer >= (SELECT MIN(dateinummer) FROM VP) and dateinummer <= (SELECT MAX(dateinummer) FROM RUV) ) \
        B ON A.X = B.DATEINUMMER WHERE B.DATEINUMMER IS NULL LIMIT ( (SELECT MAX(dateinummer) FROM VP) - (SELECT MIN(dateinummer) FROM VP) + 1 )'

    if mandant == 'VP':
        connection = sqlite3.connect(db_file)
        cursor = connection.cursor()
        cursor.execute(sql_vp)
        result = cursor.fetchall()
        connection.close()
Leider bekomme ich diese Fehlermeldung.

Code: Alles auswählen

Traceback (most recent call last):
  File "/usr/local/bin/mdk-check.py", line 183, in <module>
    main()
  File "/usr/local/bin/mdk-check.py", line 179, in main
    suche_luecken('VP')
  File "/usr/local/bin/mdk-check.py", line 80, in suche_luecken
    datenbank_zeiger.execute(sql_vp)
sqlite3.OperationalError: near "cnt": syntax error
In DBeaver funktioniert das SQL, nur innerhalb von Python nicht. Kann der Fehler am Modul sqlite3 liegen???
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@16_Bit: Ich glaube nicht dass das irgenwo anders funktioniert, denn ich weiss nicht was der Teilausdruck ``WHERE X < ((SELECT MAX(dateinummer) FROM VP))) SELECT X FROM cnt) A`` bedeuten sollte. Dieses ``SELECT X FROM cnt`` macht an der Stelle keinen Sinn und dürfte syntaktisch falsch sein.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten