zplCloud Blog
zplCloud CLI でローカルの SQL Server をラベルのデータソースとして接続する
接続文字列がご自分のマシンから出ることはありません。フィルター、並べ替え、ページングは、パラメーター化された T-SQL としてお客様のサーバー上で実行されます。
エクスポートの繰り返しと、それが破綻する理由
ラベルのデータは ERP、WMS、あるいは Azure SQL データベースの中にあります。一般的な手順は、CSV にエクスポートし、列名を直し、アップロードして印刷する、というものです。そして CSV はすでに古くなっているため、翌日にはまた同じことを繰り返します。
zplCloud のデータハブは、このエクスポートそのものをなくします。お客様のネットワーク内にある CLI エージェントが SQL Server の接続文字列を保持し、プラットフォームはそのエージェントにクエリの内容を送り、返ってくるのは結果の行だけです。データベースがインターネットに公開されることはなく、資格情報がクラウドに保存されることもありません。
この記事では、その仕組みを正確に説明します。どこで何が動くのか、どのような SQL が生成されるのか、そして厳密な上限は何かを扱います。
アーキテクチャを一段落で
zplcloud proxy は api.zplcloud.com への送信方向の TLS 接続を 1 本開きます (SignalR)。受信ポートも、NAT ルールも、VPN も必要ありません。プラットフォームでデータソースを開くと、バックエンドはエージェントにリクエストオブジェクト、つまりベースクエリ、フィルター、並べ替え、オフセット、上限を送ります。エージェントはそれを T-SQL に変換し、お客様のデータベースユーザーで SQL Server に対して実行し、行を返します。接続文字列はエージェントのプロセスメモリとそのローカル設定の中にしか存在しません。
手順 1: 1 台以上のサーバーを指定してエージェントを起動する
# Multiple --sql flags are allowed; the NAME is what you pick in the platform.
zplcloud proxy --agent "Lager" \
--sql PROD="Server=127.0.0.1;Database=erp;User Id=zplcloud;Password=…;Encrypt=True;TrustServerCertificate=True" \
--sql WAREHOUSE="Server=sql-wh.internal.lan,1433;Database=logistik;User Id=zplcloud;Password=…;Encrypt=True;TrustServerCertificate=True"
コマンドラインに秘密情報を書かない同等の方法です (書くとシェルの履歴に残ってしまいます)。
# Windows PowerShell - one variable per server, name in the middle
$env:ZPLCLOUD_SQL_PROD_CONNECTION = "Server=127.0.0.1;Database=erp;User Id=zplcloud;Password=…;Encrypt=True;TrustServerCertificate=True"
zplcloud proxy --agent "Lager"
起動時のバナーには検出された内容が表示されます。SQL servers: PROD, WAREHOUSE のような形です。プラットフォームに対する認証には --api-key <key> または ZPLCLOUD_API_KEY を使います。
無人運用のために設定を永続化します。
- Windows:
setx ZPLCLOUD_SQL_PROD_CONNECTION "…"、またはzplcloud proxy --agent "Lager" --service-install --api-key sk_zplcloud_… - Linux/Raspberry Pi: 同じ
--service-installフラグを使います。Restart=alwaysを含む systemd ユニットzplcloud-agent.serviceが書き出されます - 環境変数の代わりにファイル: バイナリと同じ場所または
~/.zplcloud/にsqlservers.jsonを置きます。形式は{ "sqlServers": { "PROD": "Server=…" } }です - Docker:
docker-compose.agent.ymlの中でZPLCLOUD_SQL_PROD_CONNECTIONを指定します
1 時間を失いがちな接続文字列の注意点
Encrypt=True;TrustServerCertificate=Trueは、自己署名証明書の社内サーバーに対する現実的な組み合わせです。正式な証明書を用意できたらTrustServerCertificateは外してください。- 名前付きインスタンスには
Server=host\\INSTANCEが必要です。既定以外のポートはServer=host,1433と書きます。コロンではなくカンマです。 - ラベルに必要なテーブルだけに
SELECT権限を持つ専用の SQL ログインを使ってください。エージェントはすべてをそのユーザーとして実行するため、権限の境界はプラットフォームではなくデータベース側にあります。
手順 2: データソースを作成する
データソース では、実行中のエージェントが Remote SQL Server の下に表示され、設定した名前ごとにチップが 1 つ並びます。チップをクリックするとフォームに値が入力されます。
| 項目 | 値 |
|---|---|
| 名前 | Lager-Artikel |
| 種類 | SQL Server |
| サーバー | PROD (--sql PROD=… で指定した名前) |
| クエリ | SELECT ean, name, price FROM artikel |
テスト は SELECT 1 を実行し、server · database を返します。項目 は CommandBehavior.SchemaOnly を指定した SELECT TOP 1 * で列のメタデータを読み取ります。データを取得せずにスキーマだけを取得する方法です。入れ子が深いクエリでスキーマが返らない場合、エージェントは SingleRow で 1 回だけ再試行します。
手順 3: エージェントが実際に実行する内容
ベースクエリはサブクエリとして包まれます。フィルター、並べ替え、ページングはエージェントが付け加えます。
SELECT * FROM ( SELECT ean, name, price FROM artikel ) AS ds
WHERE ean LIKE @p0
ORDER BY name
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
ここには二度読む価値のある点が 3 つあります。
1. 値はパラメーターであり、文字列連結ではありません。 フィルタービルダーは @p0、@p1 などを生成し、値は SqlCommand.Parameters を通じてバインドされます。ユーザーが入力した値が SQL のテキストになる箇所はどこにもありません。
2. ページングはネイティブです。 limit 10 は FETCH NEXT 10 ROWS ONLY になります。処理は SQL Server が行い、100 万行ではなく 10 行だけがネットワークを流れます。
3. 行数の取得は別のクエリです。 合計件数を求めると、エージェントは同じ WHERE と同じパラメーターで SELECT COUNT(*) FROM (<base>) AS ds を実行します。
厳密な上限 (エージェントのソースより)
| 上限 | 値 | 適用範囲 |
|---|---|---|
| 1 リクエストあたりの行数 | 1000 (RowCap) | limit は 1…1000 に丸められます。未指定時の既定値は 100 です |
| コマンドのタイムアウト | 15 秒 | テスト、スキーマ取得、クエリ、件数取得 |
| ステートメントの種類 | SELECT のみ | ベースクエリは検証され、複数ステートメントは拒否されます |
| 並べ替えとフィルターの列 | 検証済みの識別子 | 自由形式の SQL としてそのまま渡されることはありません |
1 つのビューで 1000 行を超えるデータが必要な場合、たとえばバッチ印刷や全カタログの表示では、プラットフォームが OFFSET を増やしながら結果セットをページ送りします。各ページはお客様のサーバーに対する独立した 1000 行のリクエストであるため、総件数にかかわらずメモリ使用量は一定のままです。
15 秒のタイムアウトは意図的なものです。ベースクエリが 15 秒以内に応答できないのであれば、それはラベルのデータソースではなく、インデックス付きビューか適切なインデックスを持つテーブルで解決すべき問題です。
手順 4: デザイナーと Print View で使う
- デザイナー → テストデータ タブ → データソース: データソースを選んで 読み込む を押します。フィールドのバインドはプレースホルダーではなく実際の行で描画されるため、プリンターに送る前に実際の文字数を確認できます。
- Print View → 設定 → データソース(データハブ): そのビューのプレビューと印刷でライブクエリが使われます。オペレーターは常に最新のデータを見ることになり、CSV を再アップロードする人は誰もいません。
失敗のパターンとその意味
| 症状 | 原因 |
|---|---|
| エージェントは起動するがチップが表示されない | --sql の名前が指定されていない、またはエージェントが別のワークスペースのキーで認証されている |
テスト が即座に失敗する | 接続文字列が誤っている (インスタンス、ポート、資格情報)。エラーは SQL Server からそのまま返されます |
テスト が応答せず、その後失敗する | 15 秒のタイムアウトです。エージェントのマシンからサーバーに到達できないか、ファイアウォールがパケットを黙って破棄しています |
項目 が何も返さない | ベースクエリの入れ子が深すぎて SchemaOnly が使えません。エージェントは SingleRow にフォールバックしますが、これには行が最低 1 件必要です |
| クエリは動くのに Print View が空になる | ビューが別のデータソースに紐付いているか、フィルターですべての行が除外されています |
プラン
データハブ (CLI エージェント経由の SQL Server および MongoDB データソース) は Pro プランに含まれます。詳細は料金ページをご覧ください。