Script-Migration で生成した SQL スクリプトを Docker コンテナ内で実行する

# はじめに

過去に書いた[こちら記事](https://qiita.com/t13801206/items/10e486ad6fb5ecce23f4#sql-%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8Bscript-migration)では、以下のことを行った

1. Entity Framework Core のコマンドラインツール`Script-Migration`を使って **SQL スクリプト（`.sql`ファイル）を生成した**
1. 生成した SQL スクリプト（`.sql`ファイル）を[SSMS](https://docs.microsoft.com/ja-jp/sql/ssms/download-sql-server-management-studio-ssms)で開いて実行した

## この記事では

生成した SQL スクリプト（`.sql`ファイル）を**SSMSではなく、コマンドラインから実行する**

生成した SQL スクリプト（`.sql`ファイル）の内容については、[過去の記事の付録](https://qiita.com/t13801206/items/10e486ad6fb5ecce23f4#%E4%BB%98%E9%8C%B2)を参照のこと

### 環境

- Windows 10 Home
- Docker version **20.10.8**, build 3967b7d
- Microsoft.EntityFrameworkCore **5.0.9**

# SQL スクリプトを準備する

SQLスクリプトは[生成済みのもの](https://qiita.com/t13801206/items/10e486ad6fb5ecce23f4#sql-%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8Bscript-migration)を使う

`.sql`ファイルの場所と名前は`{.slnファイルがあるディレクトリ}\Intro\obj\Debug\netcoreapp3.1\jzy0rczc.sql`である

## Docker にマウントするフォルダをつくる

ホームディレクトリにフォルダ`DockerShare`を新規作成する

```powershell:Powershell
cd ~
mkdir DockerShare
```

## マウントするフォルダに`.sql`ファイルを配置する

生成済みのSQL スクリプト（`.sql`ファイル）を、Docker にマウントするディレクトリに配置する

```powershell:Powershell
cp {.slnファイルがあるディレクトリ}\Intro\obj\Debug\netcoreapp3.1\jzy0rczc.sql .\DockerShare\
```

# Dokcer の SQL Server コンテナ内で作業する

[SQL サーバーのイメージ](https://hub.docker.com/_/microsoft-mssql-server)はあらかじプルしてあるものとする
ここでは`2019-latest`をつかう

## コンテナをたてる

[過去に試した記事](https://qiita.com/t13801206/items/cf61c5e62ade2f2e12ed#%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%83%BC%E3%81%AE%E4%B8%AD%E3%81%AB%E5%85%A5%E3%82%8B)を参考に、ホームディレクトリにつくった**`DockerShare`をマウントしてコンテナをたてる**

```powershell:Powershell
docker run -itv /C/Users/t1380/DockerShare:/DockerShare --name sql2 -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=SqlPass1234' -p 21433:1433 -d mcr.microsoft.com/mssql/server:2019-latest
```

ポート`21433`で通信する`sql2`という名前の`Microsoft SQL Server 2019`コンテナが生成される

:::note warn
検証なのでパスワードが見えているが、ふつうは公開すべきものではないと思う
:::

## 実行中のコンテナを表示する

`sql2`という名前のコンテナが実行中であることがわかる

```powershell:Powershell
docker ps
# CONTAINER ID   IMAGE                                        COMMAND                  CREATED        STATUS         PORTS                                         NAMES
# 7220012a9cbc   mcr.microsoft.com/mssql/server:2019-latest   "/opt/mssql/bin/perm…"   1 second ago   Up 2 seconds   0.0.0.0:21433->1433/tcp, :::21433->1433/tcp   sql2
```

## コンテナに入る

コンテナに入ると Powershell の入力受付が`>`から`/$`に変わる

```powershell:Powershell
docker exec -it sql2 "bash"
```

## SQL スクリプトの所在を確認する

ルートディレクトリ直下の`DockerShare`の中に、さきほど`cp`した`jzy0rczc.sql`がある

```bash:bash
cd /DockerShare
ls
# jzy0rczc.sql
```

# SQL Sever のコマンド`sqlcmd`でスクリプトを実行する

この章が本題となる

データベースを作り、そのデータベースに対して SQL スクリプトを実行する

## データベースをつくる

[以前とほぼ同じ手順](https://qiita.com/t13801206/items/10e486ad6fb5ecce23f4#%E7%A7%BB%E8%A1%8C%E5%85%88%E3%81%AE%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E3%82%92%E3%81%A4%E3%81%8F%E3%82%8B)で`Blogging`データベースをつくる
※ 新しくコンテナを立てたばかりなので、**`DROP DATABASE`は必要ない**

```sql:bash
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -W
Password:
```

データベースを作ったら、`QUIT`で抜ける

```sql:sqlcmd
1> CREATE DATABASE Blogging;
2> GO
1> QUIT
```

## 【本題】SQLスクリプトを実行する

SQL スクリプトが置かれているディレクトリにいることを確認した後
`sqlcmd ... -i jzy0rczc.sql`で SQL スクリプトを実行する

```bash:bash
pwd
# /DockerShare

/opt/mssql-tools/bin/sqlcmd -U "sa" -S "localhost" -d Blogging -i jzy0rczc.sql -o script.log
```

## SQL スクリプトを実行した結果

再度`sqlcmd`を実行する

```bash:bash
$ /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -W
Password:
```

`Blogging`データベースに`Blogs`テーブルと`Posts`テーブルが生成され、
各テーブルの内容も期待したとおりの結果になっていることがわかる

```sql:sqlcmd
1> USE Blogging;
2> GO
Changed database context to 'Blogging'.
1> SELECT * FROM Blogs;
2> GO
BlogId Url Rating
------ --- ------
11 http://one.com 0
22 http://two.com 0

(2 rows affected)
1> SELECT * FROM Posts;
2> GO
PostId Title Content BlogId
------ ----- ------- ------
11 title11 content11 11
22 title12 content12 11
33 title23 content23 22
44 title24 content24 22

(4 rows affected)
```

### （おまけ）script.log の中身は？

SQL スクリプトを実行したときに`-o`オプションでログを指定した

```bash:bash
cat /DockerShare/script.log

(1 rows affected)

(1 rows affected)

(1 rows affected)

(4 rows affected)

(1 rows affected)
```

[SSMSで実行したときの出力](https://qiita.com/t13801206/items/10e486ad6fb5ecce23f4#sql-%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B)と同じであることがわかる

# おわりに

以前 SSMS で実行した SQL スクリプトを CLI から実行することができた

[こちらの記事「自己流の手順書フォーマットを公開してみた」](https://dev.classmethod.jp/articles/non-97-operation-manual/#toc-9)でも言及されているが
同じことを GUI でやるより CLI でやったほうが
**手順書に落とすときなどに説明分の省スペース化が期待できる**

# 参考にさせていただいた記事

https://haronoid.hatenablog.com/entry/2018/02/09/141843