PostgreSQLで日本語が文字化けする件について

:::note warn
本記事は、postgreSQL、特に書籍「SQL 第2版: ゼロからはじめるデータベース操作」で躓いたエラーについての記事です。
:::

最近、インターン先の研修でSQLを勉強し始めました。
そこで、界隈では評価の高い[SQL 第2版: ゼロからはじめるデータベース操作](https://www.amazon.co.jp/SQL-%E7%AC%AC2%E7%89%88-%E3%82%BC%E3%83%AD%E3%81%8B%E3%82%89%E3%81%AF%E3%81%98%E3%82%81%E3%82%8B%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E6%93%8D%E4%BD%9C-%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E5%AD%A6%E7%BF%92%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E3%83%9F%E3%83%83%E3%82%AF/dp/4798144452)を購入して、書籍通りに進めていたところ、**日本語のデータをテーブルに挿入する際にエラーが出て躓きました泣**




よって筆者が実際に解決した、エラー解決プロセスについて記録しておきます。

もし、本記事で紹介している方法よりももっと簡単な解決方法があるといった場合や、誤って解説している箇所があればどしどしコメントください！！

## 問題点 ##
↓のように、テーブル内に日本語を含むデータを挿入したところ、、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3871898/f516e0ae-74c0-8da2-7d1a-b8d4d3bbbb97.png)

↓のように、日本語の部分が??と文字化けする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3871898/7658b832-ba6b-add6-1d40-0ba66ebc1fd9.png)


## 解決策 ##
### 1. コマンドプロンプトでエンコーディングを設定する ###
**1-1. まずは、Windowsのコマンドプロンプトを開き、UTF-8に設定する**
```bash
chcp 65001
```
これにより、コマンドプロンプトのエンコーディングが UTF-8 になります。

:::note info
最終的には、端末のencodingとpsql内でのencodingを一致させる必要がありますが、この段階では端末のencodingを"UTF-8"への設定を完了しています。
:::
これを設定することで、日本語の入力や表示が正しく行われます。

**1-2. psql シェルを開く**
cmd で chcp 65001 を実行した後、同じウィンドウでpsql シェルを起動します。
```bash
psql -U postgres -d shop #アクセスしたいデータベース名がshopの場合
```
:::note warn
この際、SQL Shell上ではなく、cmd上で実行することに注意してください。そのため、SQl Shellは利用しません。
:::

**1-3. データベースを作成する際は、ロケールとエンコーディング設定を UTF-8 に設定する**

日本語データの取り扱いが適切に行われるように、データベースを次のコマンドで作成します。

```diff_sql
CREATE DATABASE shop
WITH ENCODING 'UTF8'
LC_COLLATE='ja_JP.UTF-8'
LC_CTYPE='ja_JP.UTF-8'
TEMPLATE=template0;
```
ENCODING 'UTF8' と LC_COLLATE='ja_JP.UTF-8'、LC_CTYPE='ja_JP.UTF-8' により、日本語を含むマルチバイト文字が適切に扱えるようになります。

**1-4. 作業中にエンコーディング設定が正しいか確認する。**
↓のコードを実行し、どちらも UTF8 になっていることを確認してください。
```diff_sql
SHOW client_encoding;
SHOW server_encoding;
```
もし、UTF8になっていない場合は、↓のコードを実行してUTF8に設定しなおしてください。
```diff_sql
SET client_encoding='UTF8';
```

**1-5. ここまで上手くいくと、、、**
データベースshopから、↓をタイプし、テーブルshohinを抽出してみましょう。
```diff_sql
select * from shohin;
```
すると、、しっかり日本語で表示されているのがわかります！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3871898/0d1f1bb7-43d2-e9be-6be6-93fb79f43726.png)


:::note info
**重要なポイント**
・エンコーディングとロケールを一致させることで、日本語を含むマルチバイト文字を適切に扱えるようになります。
・cmdのエンコーディング (chcp 65001) を設定した後に psql を起動することが、文字化けを防ぐための重要な手順です。
:::

### 2．もし、うまくいかない場合は？
筆者も、なかなかうまくいかず色々試行錯誤しました。筆者が実際にうまくいかなかった例を以下に紹介しておきます。
**2-1. 日本語を含むデータをテーブルに挿入時にすでにエラーが出る場合➡1-3へ**
shohinテーブルに↓を挿入すると、、、
```diff_sql
shop=# begin transaction;
BEGIN
shop=*# INSERT INTO Shohin VALUES ('0001', 'Tシャツ', '衣服', 1000, 500, '2009-09-20');
```
↓のようなエラーが実際に表示されました。
```bash
ERROR:  é╪?è╪a?-a?Ya,-aƒ¼å?a?_ä,?æ,?æ?å^ç',"shohin_pkey"é?å??a?"a?ªa,Sa?_a?T
```
この場合、データベース自体のロケール設定自体に問題がある可能性があります。
よって一度↓を実行して、データベースのロケール確認してみましょう。
```bash
\l
```
すると、↓が表示されると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3871898/93b92447-13f7-8409-4cd5-f10386dcc6db.png)

これは現在のロケールが Japanese_Japan.932 になっています。この「932」というコードは、Windowsの Shift_JIS エンコーディングを指しています。

よってエンコーディングが UTF-8 であっても、ロケールが Shift_JIS に設定されているため、データの扱いに問題が発生する可能性があります。

従って、**1-3へ戻り、ロケールを UTF-8 に設定**しましょう。

## 個人的な疑問点 ##
### １．今うまく日本語表記できているテーブルは、このcmdを閉じてもリセットされずに保存されるのか？ ###

➡結論、されるそうです。↓chatgpt4-oの回答です。
>データベースに保存されたデータは、cmd を閉じても永久的に PostgreSQL サーバー内に保存されます。INSERT 文でデータを挿入し、COMMIT した場合、そのデータはデータベースの一部として保存されるため、cmd を閉じたり、システムを再起動してもデータは残ります。

### ２．一回cmdを閉じて、またcmdを開けるときさっきの1-1~4の操作をまたしなければいけないのですか？もしそうであればもっと効率的な方法はないの？ ###
➡結論、1-1の`chcp 65001`と`SET server_encoding='UTF8'`は保存されないそうです。しかし、データベースのロケールの設定は保存されています。この保存されない部分、毎回cmdを開くたびに設定するのはとても面倒、、、どのように効率的にすればいいのでしょうか？？（有識者の方々、教えてください泣き）