【sqlalchemy】データ取得方法と返り値（SELECT, WHERE, JOIN)

## これは何の記事
以下をまとめました
- `sqlalchemy` でデータを取得する方法
- `SELECT`，`WHERE`，`JOIN` の扱い方
- 取得データの参照方法

## 早めの結論
### SELECT
- `query()` を使用
- `execute()` と `text()` で `SQL` を実行

### WHERE, JOIN
- `WHERE` : `filter()` を使用
- `JOIN` : `join()` を使用

### 取得データの参照方法
`.` で参照可能

```Python
result = session.query(tbl_a).all()
result.id_a

result = session.query(tbl_b.id_b).all()
result.id_b
```

## 本記事で使うテーブルとモデル
![table.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294646/5fe5d064-b293-47aa-8b24-11c4eae38a8e.png)

モデルは，
テーブルのデータを Python で扱うために，
用意するクラスです

![model.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294646/0f3636aa-e102-4c57-bc6f-1632dafc669d.png)

## データ取得方法
今回は 2 つ取り上げます

### 1. query
モデルで定義したカラムを取得します
モデルの `tbl_a` を取得する例がこちら
```Python
# カラムを指定しないで全てのカラムを取得
session.query(tbl_a).all()

# カラムを指定して全てのカラムを取得
session.query(
    tbl_a.id_a,
    tbl_a.name_a,
    tbl_a.where_a,
).all()
```

### 2. execute と text
直接 SQL を書いてデータを取得する方法です
```Python
from sqlalchemy import text

# カラムを指定しないで全てのカラムを取得
session.execute(
    text("SELECT * FROM tbl_a")
).all()
```

## 全件取得か1件取得か
データの取得方法には
`all()` と `first()` があります

![all_and_first.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294646/b5f7b766-ce81-446b-b15c-16d297dee7b3.png)

## 取得データ（返り値）
取得の仕方によって，
`model` で返ってくるか
`sqlalchemy.engine.row.Row` で返って来ます
![取得データ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294646/deea04ba-3afd-43ed-a66c-a1460a15fb43.png)

### model.model.tbl_a
テーブルのデータを,
Python で扱えるように用意したクラスです

```Python
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String

Base = declarative_base()


class tbl_a(Base):
    __tablename__ = "tbl_a"

    id_a = Column(Integer, primary_key=True, index=True)
    name_a = Column(String(100), nullable=True)
    where_a = Column(String(100), nullable=True)
```

この型で返ってきます
各カラムのデータは `.` で参照できます

```Python
result = session.query(tbl_a).first()
result.id_a # カラム「id_a」の値を参照できます 
```

### sqlalchemy.engine.row.Row
行のデータを表す，
Python の名前付きタプル (NamedTuple) に，
よく似ているタプルです

https://pydoc.dev/sqlalchemy/latest/sqlalchemy.engine.row.Row.html

各カラムのデータは `.` で参照できます

```Python
result = session.query(tbl_a.id_a).first()
result.id_a # カラム「id_a」の値を参照できます 
```

## WHEREとJOIN
`WHERE` は `filter()` ，
`JOIN` は `join()` を使います

例で見ていきましょう
以下の結合をしたいとします

`tbl_a` の `where_a` が `Yes` のデータと，
`tbl_b` の `where_b` が `Yes` のデータを，
`tbl_a` の `id_a` と `tbl_b` の `id_a` で結合

![filter_join.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/294646/6894f3ef-0ba3-4962-a6d6-bfb7d8a73490.png)

```SQL
SELECT
	tbl_a.id_a, tbl_a.name_a, tbl_a.where_a,
	tbl_b.id_b, tbl_b.id_a, tbl_b.name_b, tbl_b.where_b
FROM(
	SELECT *
	FROM tbl_a
	WHERE tbl_a.where_a = 'Yes'
) AS tbl_a
INNER JOIN (
	SELECT *
	FROM tbl_b
	WHERE tbl_b.where_b = 'Yes'
) AS tbl_b
ON tbl_a.id_a = tbl_b.id_a
```

`query`，`filter`，`join` を使うとこうです

```Python
result = (
        session.query(
            tbl_a.id_a,
            tbl_a.name_a,
            tbl_a.where_a,
            tbl_b.id_b,
            tbl_b.id_a,
            tbl_b.name_b,
            tbl_b.where_b,
        )
        .filter(tbl_a.where_a == "Yes")
        .filter(tbl_b.where_b == "Yes")
        .join(
            tbl_b,
            tbl_a.id_a == tbl_b.id_a
        )
        .all()
    )
```