it-swarm.com.de

Verwenden Sie temporäre Tabelle mit SQLAlchemy

Ich versuche, eine temporäre Tabelle mit SQLAlchemy zu verwenden und sie mit einer vorhandenen Tabelle zu verbinden. Das habe ich bis jetzt

engine = db.get_engine(db.app, 'MY_DATABASE')
df = pd.DataFrame({"id": [1, 2, 3], "value": [100, 200, 300], "date": [date.today(), date.today(), date.today()]})
temp_table = db.Table('#temp_table',
                      db.Column('id', db.Integer),
                      db.Column('value', db.Integer),
                      db.Column('date', db.DateTime))
temp_table.create(engine)
df.to_sql(name='tempdb.dbo.#temp_table',
          con=engine,
          if_exists='append',
          index=False)
query = db.session.query(ExistingTable.id).join(temp_table, temp_table.c.id == ExistingTable.id)
out_df = pd.read_sql(query.statement, engine)
temp_table.drop(engine)
return out_df.to_dict('records')

Dies gibt keine Ergebnisse zurück, da die Einfügeanweisungen, die to_sql nicht ausgeführt wird, ausgeführt werden (ich denke, das ist, weil sie mit sp_prepexec ausgeführt werden, aber ich bin nicht ganz sicher).

Ich habe dann versucht, einfach die SQL-Anweisung (CREATE TABLE #temp_table..., INSERT INTO #temp_table..., SELECT [id] FROM...) aufzuschreiben und dann pd.read_sql(query, engine) auszuführen. Ich erhalte die Fehlermeldung

Dieses Ergebnisobjekt gibt keine Zeilen zurück. Es wurde automatisch geschlossen.

Ich denke, das liegt daran, dass die Aussage mehr als nur SELECT macht.

Wie kann ich dieses Problem beheben? (Beide Lösungen funktionieren, obwohl die erste Lösung vorzuziehen ist, da hartcodiertes SQL vermieden wird). Um es klar zu sagen: Ich kann das Schema in der vorhandenen Datenbank nicht ändern - es handelt sich um eine Herstellerdatenbank.

7
Kris Harper

Wenn die Anzahl der Datensätze, die in die temporäre Tabelle eingefügt werden sollen, klein/mittel ist, besteht die Möglichkeit, anstelle der Erstellung einer temporären Tabelle einen literal subquery oder einen values CTE zu verwenden.

# MODEL
class ExistingTable(Base):
    __table= 'existing_table'
    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String)
    # ...

Angenommen, folgende Daten sollen in die temp-Tabelle eingefügt werden:

# This data retrieved from another database and used for filtering
rows = [
    (1, 100, datetime.date(2017, 1, 1)),
    (3, 300, datetime.date(2017, 3, 1)),
    (5, 500, datetime.date(2017, 5, 1)),
]

Erstellen Sie einen CTE oder eine Unterabfrage, die diese Daten enthält:

stmts = [
    # @NOTE: optimization to reduce the size of the statement:
    # make type cast only for first row, for other rows DB engine will infer
    sa.select([
        sa.cast(sa.literal(i), sa.Integer).label("id"),
        sa.cast(sa.literal(v), sa.Integer).label("value"),
        sa.cast(sa.literal(d), sa.DateTime).label("date"),
    ]) if idx == 0 else
    sa.select([sa.literal(i), sa.literal(v), sa.literal(d)])  # no type cast

    for idx, (i, v, d) in enumerate(rows)
]
subquery = sa.union_all(*stmts)

# Choose one option below.
# I personally prefer B because one could reuse the CTE multiple times in the same query
# subquery = subquery.alias("temp_table")  # option A
subquery = subquery.cte(name="temp_table")  # option B

Erstellen Sie eine abschließende Abfrage mit den erforderlichen Joins und Filtern:

query = (
    session
    .query(ExistingTable.id)
    .join(subquery, subquery.c.id == ExistingTable.id)
    # .filter(subquery.c.date >= XXX_DATE)
)

# TEMP: Test result output
for res in query:
    print(res)    

Holen Sie sich schließlich Pandas-Datenrahmen:

out_df = pd.read_sql(query.statement, engine)
result = out_df.to_dict('records')
10
van

Sie können versuchen, eine andere Lösung zu verwenden - Process Keyed Table 

Eine Tabelle mit Prozesstasten ist einfach eine permanente Tabelle, die als Temp-Tabelle dient. Damit Prozesse die Tabelle gleichzeitig verwenden können, enthält die Tabelle Eine zusätzliche Spalte, um den Prozess zu identifizieren. Der einfachste Weg zu Ist die globale Variable @@ spid (@@ spid ist die Prozess-ID in SQL Server). 

...

Eine Alternative für den Prozessschlüssel ist die Verwendung eines GUID (Datentyp Uniqueidentifier).

http://www.sommarskog.se/share_data.html#prockeyed

1
Mikhail Lobanov