Home » Beitrag verschlagwortet mit 'SQL'
Schlagwort-Archive: SQL
Logging von Hibernate SQL
Allgemeines Logging:
org.hibernate.SQL=DEBUG
Um die Parameter-Einfügungen in die Query zu loggen:
org.hibernate.type.descriptor.sql.BasicBinder=DEBUG
Oracle SQL Explain – Query Performace
Links:
- Interpreting Explain Plan – Grundbegriffe
- How to Read an Execution Plan
- Explaining and Displaying Execution Plans
- Einführung in Materialized Views
- Refreshing Materialized Views
- Advanced Materialized Views
- CREATE MATERIALIZED VIEW LOG <– Braucht es anscheinend um eine Mat View per Partition up-zu-daten
Oracle SQL – Know how
Concatenate the different row values of the same group into on row per group.
LISTAGG Function, see: Sql PIVOT and string concatenation aggregate
SQL Pivot
Referenzen
Oracle PIVOT – Introduction to Oracle PIVOT
clause
SQL Pivot: Converting Rows to Columns
Sql PIVOT and string concatenation aggregate (Schwierig :-))
Kurz-Erklärung
SQL Pivot kann benutzt werden um Gruppierungen innerhalb eines Resultat-Sets zu machen und pro Gruppe zusätzliche Kolonnen zu extrahieren.
Hätten wir z.B. ein statement:
SELECT MONAT, REGENMENGE FROM REPORT;
Monat | Regenmenge | |
---|---|---|
1 | 100 | |
2 | 212 | |
3 | 322 | |
… | … | |
Wenn man daraus dieseses Format erstellen möchte:
Januar | Februar | März | April | … | ||
100 | 212 | 322 |
… würde man dies mit folgendem Pivot-Statement erreichen:
SELECT MONAT, REGENMENGE FROM REPORT
PIVOT max(REGENMENGE) -- Aggregatsfunktion fuer mehrere werte fuer denselben Monat
FOR MONAT
IN ( '1' as JANUAR, '2' as FEBRUAR, '3' as MÄRZ, '4' as APRIL, ...)
Flask DB Migrations
Links
- Flask-Migrate
- Alembic (used by Flask-Migrate under the hood)
Flask-Migrate ist die Library um DB-Modell-Änderungen, die mit SQLAlchemy ausgedrückt sind zu kontrollieren. Es benutzt dazu die Library Alembic.
Schritte
Aufsetzen Flask Migrate Tool
Steps:
pip3 install Flask-Migrate
Projekt bezüglich Migrations-Handling aufsetzen
flask db init
Das setzt verschiedene Migrations-Script-Folders und Tools im SW-Projekt bereit.
Output:
C:\tmp\Python_Workspace1\task-app>flask db init
Creating directory C:\tmp\Python_Workspace1\task-app\migrations ... done
Creating directory C:\tmp\Python_Workspace1\task-app\migrations\versions ... done
Generating C:\tmp\Python_Workspace1\task-app\migrations\alembic.ini ... done
Generating C:\tmp\Python_Workspace1\task-app\migrations\env.py ... done
Generating C:\tmp\Python_Workspace1\task-app\migrations\README ... done
Generating C:\tmp\Python_Workspace1\task-app\migrations\script.py.mako ... done
Please edit configuration/connection/logging settings in 'C:\\tmp\\Python_Workspace1\\task-app\\migrations\\alembic.ini' before proceeding.
Funktioniert das Kommando nicht, weil die DB noch nicht gestartet ist, dann etwa folgendes absetzen:
pg_ctl -D "C:\Program Files\PostgreSQL\13\data" start
DB-Migrationen durchführen
flask db migrate
Erkennt die Anforderungen an das DB-Modell aus den Python-Scripts (aus den SQLAlchemy Model-Objekt-Definitionen) heraus und erstellt eine Migration (DDL Statements um das erforderliche DB-Model zu erstellen).
Ich gehe schwer davon aus, das dazu FLASK_APP auf das Python-Script mit den Entitätsdefinitionen zeigen muss.
Bsp. einer SQLAlchemy Model-Objekt-Definition im *.py:
class Todo(db.Model):
__tablename__ = 'todos'
id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(), nullable=False)
Falls das erzeugte Script das ganze DB-Modell von Grund auf neu erzeugen soll, dann darf die DB diese Entitäten nicht schon enthalten. Das kann man zum Bsp. erreichen durch:
dropdb --username=postgres todoDB
createdb --username=postgres todoDB
!Stelle sicher, dass das Pyton-Script, nicht schon selbst die DB-Objekte erstellt (Z.B. Kommando db.create_all() darf nicht auch schon im Python-Code enthalten sein).
Durchführung:
C:\tmp\Python_Workspace1\task-app>flask db migrate
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'todos'
Generating C:\tmp\Python_Workspace1\task-app\migrations\versions\70ee48c313e4_.py ... done
C:\tmp\Python_Workspace1\task-app>
Ein Migrations-File wurde erstellt: task-app/migrations/versions/70ee48c313e4_.py
:
"""empty message
Revision ID: 70ee48c313e4
Revises:
Create Date: 2021-07-22 15:15:43.733091
"""
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '70ee48c313e4'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('todos',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('description', sa.String(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table('todos')
# ### end Alembic commands ###
Migration auf die DB spielen:
C:\tmp\Python_Workspace1\task-app>flask db upgrade
INFO [alembic.runtime.migration] Context impl PostgresqlImpl.
INFO [alembic.runtime.migration] Will assume transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> 70ee48c313e4, empty message
Migration rückgängig machen wäre:
flask db downgrade
Prüfung, ob DB-Migrationen auf DB angekommen sind:
C:\tmp\Python_Workspace1\task-app>psql --username=postgres todoDB
Passwort für Benutzer postgres:
todoDB=# \dt
Liste der Relationen
Schema | Name | Typ | Eigent³mer
--------+-----------------+---------+------------
public | alembic_version | Tabelle | postgres
public | todos | Tabelle | postgres
(2 Zeilen)
todoDB=#
Beachte die alembic_version
Tabelle! Beinhaltet die Migrationsinfo. Prinzipiell nicht durch den Programmierer zu verändern.
Wenn nun Änderungen am DB-Modell innerhalb des Python-Scripts gemacht werden (z.B. wird hier das boolean Feld ‚completed‘ neu hinzu gefügt),
class Todo(db.Model):
__tablename__ = 'todos'
id = db.Column(db.Integer, primary_key=True)
description = db.Column(db.String(), nullable=False)
completed = db.Column(db.Boolean(), nullable=False, default=False)
…, dann wird mit flask db migrate
ein neues Update-Script erstellt und mit flask db update
dieser Update auf die DB gespielt.
Beheben der Problematik des Hinzufügens von NOT-NULL Feldern:
Das Migrations-Script folgendermassen anpassen:
from alembic import op
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('todos', sa.Column('completed', sa.Boolean(), nullable=True))
op.execute('update todos set completed=False where completed is null')
op.alter_column('todos', 'completed', nullable=False)
# ### end Alembic commands ###
DB Manipulation with SQLAlchemy
Referenzen:
– Docs for the SQLAlchemy Query API
– SQLAlchemy Doku
Im folgenden eine Kleine Demo,
– wie bestehende SQLAlchemy-Definitionen eines bestehendes Python-Scripts in die interaktive Python-Konsole importier werden können und
– wie SQLAlchemy-Entitäten SQLAlchemy-artig von der abgefragt und hinzu gefügt werden.
Ablauf | Command | Meaning |
---|---|---|
1 | >python | Start Python Console |
2 | >from path/flask_postgres_sql_hello_app import db,Person | Importiert die in flask_postgres_sql_hello_app.py (–> siehe) gemachten Definitionen von db und Person |
3ff | results = Person.query.all() | Holt alle Person Entitäten von der entsprechenden Tabelle |
3ff | results = Person.query.first() | |
3ff | Person.query.filter_by(name=’Hans‘).all() #Alternativ: Person.query.filter(Person.name=’Hans‘).all() #Alternativ: db.session.query(Person).filter(Person.name=’Hans‘).all() | Holt Person Entitäten die dem Filter entsprechen von der entsprechenden Tabelle |
User.query.filter(User.name.like(‚B%‘)).all() ilike(‚b%‘) | Like-Query Like (Case-insensitive) | |
3ff | Person.query.filter(Person.name==‚Hans‘).filter(Person.name==‚Peter‘).all() | Multiple Filters (Method chaining) |
3ff | query.count() query.first() query.get(9) query.get(‚ID1‘) query.limit(2) query.delete() query.order_by(db.desc(Person.name)) | Wird für Grouping benutzt Nur erstes Finding bringen Nur 9tes Finding bringen Primary-Key filter Nur die ersten 2 Löschen des Query-Resultats Order by |
Person.query.join(‚vehicles‘).filter(Vehicle.marke==‚Opel‘).all() | Join-Beispiel | |
3ff | person = Person(name=’Bob‘) db.session.add(person) db.sesssion.commit() | Erstellen eines Person-Objekts und speichern desselben. |
3ff | db.session.add_all([Person(name=’Ada‘), Person(‚Jira‘)]) db.sesssion.commit() | Erstellen mehrerer Person-Objekt und speichern desselben |
3ff | ||
3ff | ||
3ff |