無料のAzure SQL Databaseを試してみたメモ

## 概要

[Azure SQL Database を無料で試す (プレビュー)](https://learn.microsoft.com/ja-jp/azure/azure-sql/database/free-offer?view=azuresql)を試してみた。


## データベースの作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/7c35dad7-7688-9702-8f29-b7eee4f8f48c.png)

基本はデフォルトの設定。認証方法は両方を使用するようにした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/88ad67ef-fde8-4b6c-eb9c-e591c634ce77.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/cb8d00b3-8876-656b-ffce-8140152ae0ca.png)

その月の無料枠を超えたら止まるように設定（デフォルト）。次の月になって無料枠ができたら使えるようになるもよう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/8c2d3f59-2dbd-067c-a962-82258eb9e087.png)

コストはちゃんと0になっている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/5f13bb95-9ef6-7303-0561-130e0f43e331.png)

日本語を扱うので[照合順序](https://learn.microsoft.com/ja-jp/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-ver16)は`Japanese_CS_AS_KS_WS`に変更した。([参考](https://www.w2solution.co.jp/corporate/tech/%E5%90%8C%E3%81%98sql%E3%81%A7%E3%82%82%E7%92%B0%E5%A2%83%E3%81%A7%E7%B5%90%E6%9E%9C%E3%81%8C%E7%95%B0%E3%81%AA%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AE%E5%AF%BE%E5%87%A6%E6%B3%95/) [*2](https://coogi-memo.hatenablog.com/entry/2018/10/09/174515))

対象|区別する(`Sensitive`)|区別しない(`Insensitive`)
--|--|--
大文字と小文字(`Case`)|CS|CI
アクセント(`Accent`)|AS|AI
ひらがなとカタカナ(`Kana`)|KS|KI
半角と全角(`Width`)|WS|WI

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/d165abfc-d226-7854-a938-1333eabfcd64.png)

### テスト用のテーブル作成

テスト用にテーブルを作成し、データを挿入した。

```sql
CREATE TABLE TestTable (
    ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
    Name NVARCHAR(20) NOT NULL,
);
INSERT INTO TestTable VALUES ('test');
INSERT INTO TestTable VALUES ('日本語テストです');
SELECT * FROM TestTable ;
```
### Firewallの設定
もしもFirewallの穴あけをしなかった場合、関数実行時に下記のようなエラーとなる。
```
Cannot open server 'my-free-sqldbserver' requested by the login. Client with IP address 'x.xxx.xxx.xx' is not allowed to access the server. To enable access, use the Azure Management Portal or run sp_set_firewall_rule on the master database to create a firewall rule for this IP address or address range. It may take up to five minutes for this change to take effect.
```

SQL Serverのネットワークで「Azureサービスおよびリソースにこのサーバへのアクセスを許可する」にチェックを入れて、Functionsからアクセスできるようにする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/358f8c5c-e46a-31ff-1b17-80d1b5a52216.png)


## 関数からSQLを発行する
[Azure Functions の Azure SQL 入力バインド](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-azure-sql-input?tabs=isolated-process%2Cnodejs-v4&pivots=programming-language-typescript)の手順に従ってSQLを発行する。


### 関数アプリの作成
[関数の作成](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-create-function-app-portal?pivots=programming-language-typescript)はポータルから行った。
#### 基本設定

プロパティ|値
--|--
OS|Linux
ランタイムバージョン|4.31.1.1
発行モデル|コード
コンテナイメージ|Node-20

#### 環境変数
環境変数にSQL Serverの接続文字列を格納する必要がある。
環境変数にいれずに直接ソースに書くと、`ConnectionStringSetting 'hoge' is missing in your function app settings, please add the setting with a valid SQL connection string.`のエラーとなる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/30628876-1292-87ae-fe3c-a299f30db433.png)

##### SQLデータベースから接続文字列取得

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/76e41808-ddb8-0c8b-8f24-c1594be4bc3a.png)

今回はSQL認証で接続する。接続文字列をコピーし、`{your_password}`をデータベース作成時に決めたパスワードに置き換える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/26b75f2d-3793-cb4e-9250-f382af84fa59.png)
##### Functionsアプリに設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/3c115004-0abd-b0c8-592b-b62d8014a704.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/ac760fec-290d-b1df-12b0-7780c510aca3.png)

保存ボタンを押さないと反映されないので注意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/df451008-3d5c-5168-76fc-dd3f7809d921.png)



### 関数のデプロイ

[Typescript](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-reference-node?tabs=typescript%2Cwindows%2Cazure-cli&pivots=nodejs-model-v4)を[VSCodeの拡張](https://learn.microsoft.com/ja-jp/azure/azure-functions/create-first-function-vs-code-node?pivots=nodejs-model-v4)経由でデプロイした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/e0bddad1-22ec-c78a-801a-13e5f0d54fe8.png)

#### ソースコード

[Azure Functions の Azure SQL 入力バインド](https://learn.microsoft.com/ja-jp/azure/azure-functions/functions-bindings-azure-sql-input?tabs=isolated-process%2Cnodejs-v4&pivots=programming-language-typescript)より

```typescript:src/functions/httpTrigger1.ts
import { app, HttpRequest, HttpResponseInit, InvocationContext,input } from "@azure/functions";
const sqlInput = input.sql({
    commandText: 'select [ID], [Name] from TestTable',
    commandType: 'Text',
    connectionStringSetting: 'MyConnectionString',
});
export async function httpTrigger1(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    context.log(`Http function processed request for url "${request.url}"`);
    const toDoItems = context.extraInputs.get(sqlInput);
    return {
        jsonBody: toDoItems,
    };
};

app.http('httpTrigger1', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    extraInputs: [sqlInput],
    handler: httpTrigger1
});

```

## テスト実行
無事、取得できることを確認できた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/e785e705-aaf8-f290-ca74-1190aaed8e27.png)

## Prismaでモデルファースト 2024.04.27 追記

[続き。](https://qiita.com/hibohiboo/items/8598d44e64562ce37ebd)

## mssqlで接続 2024.05.04 追記

[mssql](https://qiita.com/hibohiboo/items/1ad92039cb080e2ea226)