質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQLAlchemy

SQLAlchemyとはPython 用のORMライブラリです。MIT Licenceのオープンソースとして提供されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

5742閲覧

SQLAlchemyでサブクエリで取得したカラムで絞り込めない

fuuga

総合スコア28

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQLAlchemy

SQLAlchemyとはPython 用のORMライブラリです。MIT Licenceのオープンソースとして提供されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/09/04 18:23

前提・実現したいこと

テーブルの名前毎の最新データを取得したいです。
これよりもいい実装があればクエリ自体は変わっても問題ありません。
linesテーブルのもとからあるカラム(id, name等)であればlatest_linesのカラムが使用されるのですが、maxなどの関数を使用して取得したデータがうまく使用されないという状況です。

発生している問題・エラーメッセージ

pythonでlatest_lines.created_atと書いている部分が、なぜか実際のSQLではlinesのcreated_atに置き換わっています。
なので実際には最新ではないデータが返却されます。

python

1from sqlalchemy import desc, func 2from sqlalchemy.orm import aliased 3 4from app.database import session 5from app.models import Line 6 7latest_lines = aliased( 8 Line, 9 session.query( 10 Line.name.label("name"), 11 func.max(Line.created_at).label("created_at"), 12 ) 13 .group_by(Line.name) 14 .subquery("latest_lines"), 15) 16 17lines = ( 18 session.query(Line, latest_lines) 19 .filter(Line.name == latest_lines.name) 20 .filter(Line.created_at == latest_lines.created_at) 21 .group_by(Line.name) 22 .order_by(desc(Line.created_at)) 23 .all() 24)

↓実際に発行されているSQL(必要ないselectのカラムは削除してあります)

sql

1SELECT 2 `lines`.id AS lines_id, 3 `lines`.name AS lines_name, 4 `lines`.created_at AS lines_created_at, 5 latest_lines.name AS latest_lines_name 6FROM 7 `lines`, 8 ( 9 SELECT 10 `lines`.name AS name, 11 max(`lines`.created_at) AS created_at 12 FROM 13 `lines` 14 GROUP BY 15 `lines`.name 16 ) AS latest_lines 17WHERE 18 `lines`.name = latest_lines.name 19AND `lines`.created_at = `lines`.created_at 20GROUP BY 21 `lines`.name

補足情報(FW/ツールのバージョンなど)

Python 3.9.7
SQLAlchemy 1.4.23
MySQL 5.7.35

理想は以下のようなクエリを発行したいのですがjoinのサブクエリの記述方法がいまいちわからず上記のような書き方になっています。

sql

1select 2 id, 3 `lines`.name, 4 `lines`.created_at 5from 6 `lines` 7 join 8 ( 9 select 10 name, 11 max(created_at) as created_at 12 from 13 `lines` 14 group by 15 name 16 ) as `latest_lines` 17 on `lines`.name = latest_lines.name 18 and `lines`.created_at = latest_lines.created_at 19group by 20 `lines`.name 21order by 22 `lines`.name

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

バグでしょうけど、つまらないバグを回避するためにも、もう少しわかり易いネーミングにすることも考えては?

SQL

1 max(created_at) as created_at 23 max(created_at) as max_at

SQL

1 and `lines`.created_at = latest_lines.created_at 23 and `lines`.created_at = latest_lines.max_at

動作確認はしていません。

投稿2021/09/04 22:26

Orlofsky

総合スコア16415

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fuuga

2021/09/05 09:46

回答ありがとうございます。 名前を変えて試してみましたが、Python側でエラーが発生してしまいます。 ``` Traceback (most recent call last): File "/usr/src/app/test.py", line 37, in <module> .filter(Line.created_at == latest_lines.max_at) File "/usr/src/app/.venv/lib/python3.9/site-packages/sqlalchemy/orm/util.py", line 546, in __getattr__ attr = getattr(target, key) AttributeError: type object 'Line' has no attribute 'max_at' ```
Orlofsky

2021/09/05 10:07

SQLAlchemy ってSQLのスキルがなくても使えるってのがウリだけど、なかなかバグが解消しないから、使わないって選択肢もあるのでは?
fuuga

2021/09/05 11:50

なるほど、ありがとうございます。 ただPythonのORMでは一番良さそうなのと、今やってるプロジェクト全体で使用しているのでできればSQLAlchemyで実装できればと思っている次第です。
guest

0

自己解決

解決できました。
原因はaliased関数の使い方を間違えていたようです。
第一引数にモデルを渡していたのでそちらが使用されていたようです。
どこかで見た記事ではそのようになっていたので勘違いしておりました。

python

1from sqlalchemy import desc, func 2from sqlalchemy.orm import aliased 3 4from app.database import session 5from app.models import Line 6 7latest_lines = aliased( 8 session.query( 9 Line.name.label("name"), 10 func.max(Line.created_at).label("created_at"), 11 ) 12 .group_by(Line.name) 13 .subquery(), 14 name="latest_lines", 15) 16 17lines = ( 18 session.query(Line, latest_lines) 19 .filter(Line.name == latest_lines.c.name) 20 .filter(Line.created_at == latest_lines.c.created_at) 21 .group_by(Line.name) 22 .order_by(desc(Line.created_at)) 23 .all() 24)

投稿2021/09/05 12:16

fuuga

総合スコア28

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問