LinuxからODBC Driverを利用したMS SQLServerへの接続時のポート指定方法(pyodbc)

## 概要
タイトルが長くなってしまいましたが、pyodbcでMS SQL Serverへ接続時のポート指定方法で詰まってしまったため、記録します。

## 環境
- Linux
- MS SQLServerのドライバはversion17
- Python 3.11.4

## 結論

いきなり結論ですが、pyodbcの公式ドキュメントにある通り、デフォルト (1433) 以外のポートに接続する場合は、Serverの引数にコンマを付けて追加します。

例:

```
Server      = mydbserver.mycompany.com,49242
```


https://github.com/mkleehammer/pyodbc/wiki/Connecting-to-SQL-Server-from-Linux


## コードの例

詰まってしまったコードは下記です。
これはポートを**PORTパラメータで指定**していますが、ちゃんと動かずデフォルトのポート(1433)に接続されます。

:::note info
この書き方はQiitaなどでは見かけたのですが、MSの公式ドキュメントでも見つけられませんでした。
もしかしたらドライバのバージョン18だと動くのかもしれませんが、検証できていません。ご存知の方がいましたらコメントいただければと思います。
:::

```python:ポートをパラメータで指定
import pyodbc

SERVER = '127.0.0.1'
PORT = '14334'
DATABASE = 'dbname'
USERNAME = 'username'
PASSWORD = 'password'

connectionString = f'DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={SERVER};PORT={PORT};DATABASE={DATABASE};UID={USERNAME};PWD={PASSWORD}'

try:
    # MS SQLServerに接続
    conn = pyodbc.connect(connectionString)
    print("Connection successful")
    
    # 接続したサーバー名を確認
    cursor = conn.cursor()
    cursor.execute("SELECT @@SERVERNAME AS ServerName;")
    row = cursor.fetchone()

    if row:
        print(f"Server Name: {row.ServerName}")

    cursor.close()
    conn.close()

except pyodbc.Error as ex:
    sqlstate = ex.args[1]
    print(f"Connection failed: {sqlstate}")
```

実行結果1
```shell
Connection successful
Server Name: Server1 #デフォルトのポートに接続
```
正しいコードは下記です。
```diff_python:ポートをServerのあとにカンマで指定
import pyodbc

SERVER = '127.0.0.1'
PORT = '14334'
DATABASE = 'dbname'
USERNAME = 'username'
PASSWORD = 'password'

-connectionString = f'DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={SERVER};PORT={PORT};DATABASE={DATABASE};UID={USERNAME};PWD={PASSWORD}'
+connectionString = f'DRIVER={{ODBC Driver 17 for SQL Server}};SERVER={SERVER},{PORT};DATABASE={DATABASE};UID={USERNAME};PWD={PASSWORD}'

try:
    # MS SQLServerに接続
    conn = pyodbc.connect(connectionString)
    print("Connection successful")
    
    # 接続したサーバー名を確認
    cursor = conn.cursor()
    cursor.execute("SELECT @@SERVERNAME AS ServerName;")
    row = cursor.fetchone()

    if row:
        print(f"Server Name: {row.ServerName}")

    cursor.close()
    conn.close()

except pyodbc.Error as ex:
    sqlstate = ex.args[1]
    print(f"Connection failed: {sqlstate}")
```

実行結果2
```shell
Connection successful
Server Name: Server2 #接続したいポートに接続できた
```

## おまけ:MS SQL Serverドライバのバージョンの確認

MSSQLServerに接続したいときは、ドライバーのバージョンを確認しておいたほうが良いと思います。
`odbcinst`コマンドで確認できます。
```shell
$ odbcinst -j
unixODBC 2.3.1
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /home/step/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8

$ cat /etc/odbcinst.ini
[ODBC Driver 17 for SQL Server]
Description=Microsoft ODBC Driver 17 for SQL Server
Driver=/opt/microsoft/msodbcsql17/lib64/libmsodbcsql-17.10.so.2.1
UsageCount=1
```

## バージョン17.4より前では動的ポートによる接続は動かない

ちなみに、下記のドキュメントによると、バージョン17.4より前では、動的ポートの接続はサポートされていないようなので注意してください。

https://learn.microsoft.com/ja-jp/sql/connect/odbc/linux-mac/connection-string-keywords-and-data-source-names-dsns?view=sql-server-ver16

>**静的ポートの名前付きインスタンスに接続するには、Server=servername,port_number を使用します。 バージョン 17.4 より前では、動的ポートへの接続はサポートされていません。**