Help us understand the problem. What is going on with this article?

SQLAlchemyでPostgresにスキーマを作成しテーブル作成・操作を生SQLでやってみる

はじめに

最近はデータ分析ばかりでデータベースはご無沙汰していたが(クソ面白くないので避けていたが), そうもいってられなくなったので真面目にやろうと思う。早速Pythonでよく使われるDBライブラリを調べたところSQLAlchemyがよさそうだ。OR Mapperだけでなく、生SQLの実行や、SQLの組み立て等も充実しており、この手のツールにありがちな「ガチガチで融通が利かない」ものではなさそうなところが気に入った。Django等でも使えるそうで、知っておいて損はないということで今後コミットしていく。

まずは生SQLでどれくらいのことができるか知りたかったため、今回はPostgresにスキーマを作成し、そのスキーマ上にテーブルを作成し、データの登録、更新、検索、削除等の操作を一通り確認した。その結果psycopg2で直接ゴリゴリ書くのと全く変わらずに生SQLを実行することができることが分かった。

環境

  • Windows10
  • Postgres 12
  • Python 3.X
  • SQLalchemy 1.3.6

ソース

ソースは以下の通りである。見てもらえれば分かる思うので、説明は省略する。

Test.py
from sqlalchemy.schema import CreateSchema
from sqlalchemy import *
from sqlalchemy.sql import text

def main():

    # データベース接続
    engine = create_engine("postgresql://kimisyo:kimisyo@localhost:5433/chemsyo")

    # コネクションを獲得
    conn = engine.connect()

    # スキーマを作成する
    if not conn.dialect.has_schema(conn, "common"):
        engine.execute(CreateSchema("common"))

    # 前回作成したテーブルを一旦削除しておく
    try:
        conn.execute("DROP TABLE common.all_data")
    except:
        pass

    # 作成したスキーマを参照するよう変更
    conn.execute("SET search_path TO common")

    # テーブルを作成する
    conn.execute("CREATE TABLE all_data(id INTEGER, name TEXT, data TEXT)")

    # トランザクションを開始する
    trans = conn.begin()

    # テーブルにデータを登録する
    sql = text("INSERT INTO all_data(id, name, data) VALUES (:id, :name, :data)")
    for i in range(1000):
        conn.execute(sql, id=i, name="name"+str(i), data="text"+str(i))

    # データを更新する
    sql = text("UPDATE all_data SET name=:name WHERE id = :id")
    for i in range(1000):
        conn.execute(sql, id=i, name="name_upd"+str(i), data="text"+str(i))

    # トランザクションを一旦commitする
    trans.commit()

    # データを検索する(1件)
    sql = text("SELECT name FROM all_data WHERE id = :id")
    result = conn.execute(sql, id=3)
    for row in result:
        print("name:{0}".format(row['name']))

    # データを検索する(like検索)
    sql = text("SELECT id, name FROM all_data WHERE name LIKE :keyword")
    result = conn.execute(sql, keyword="%33%") # "33"を部分一致として含むものを検索
    for row in result:
        print("id:{0}, name:{1}".format(row['id'], row['name']))

    # トランザクションを開始する
    trans = conn.begin()

    # データを削除する(全件)
    sql = text("DELETE FROM all_data")
    result = conn.execute(sql)

    # commitする
    trans.commit()

    # コネクションをクローズする
    conn.close()


if __name__ == "__main__":
    main()

今後の展望

今回は泥臭い使い方ができることが分かったため、今後は以下のようにもう少しエレガントな使い方を試してみたい。
- 複雑なクエリを、SQL組み立て機能を使ってエレガントに作成、実行する。
- SQLの実行ログを、エレガントに一元的に出力する。
- ソース上に記載したテーブル定義や、DBに作成済のテーブルから、OR-Mapper機能を用いてエレガントにテーブルの操作を行う。

柔軟かつエレガントであることが今後の変化に耐え抜くために重要なのだ。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away