WEB問題集
Contoso は Azure SQL Database の 1 つのデータベースに、従業員情報を保持するテーブルを新規に作成します。メール アドレスと電話番号の形式は、アプリケーションではなくデータベース側で検証する方針です。
開発者が次のステートメントを実行したところ、「'REGEXP_LIKE' は認識されない組み込み関数名です。」というエラーが返りました。
CREATE TABLE dbo.Employees
(
employee_id INT IDENTITY (1, 1) PRIMARY KEY,
email VARCHAR (320)
CHECK (REGEXP_LIKE (email, '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$')),
phone_number NVARCHAR (20)
CHECK (REGEXP_LIKE (phone_number, '^(\d{3})-(\d{3})-(\d{4})$'))
);正規表現による検証をこのステートメントのまま使用できるようにするには、どうすればよいですか。
解説
【正解: C】の理由
REGEXP_LIKE はデータベースの互換性レベル 170 以上を必要とします。互換性レベルが 170 未満のデータベースでは REGEXP_LIKE が公開されず、組み込み関数名として認識されないためエラーになります。ALTER DATABASE の SET COMPATIBILITY_LEVEL = 170 で引き上げれば、CHECK 制約でも WHERE 句でも使用できます。REGEXP_LIKE は真偽値を返す述語関数なので、CHECK 制約の条件式としてそのまま記述でき、テーブル定義だけで形式の検証を完結できます。なお互換性レベル 170 を要求するのはREGEXP_LIKE であり、REGEXP_REPLACE などその他の正規表現スカラー関数はすべての互換性レベルで使用できます。
【他選択肢が違う理由】
- A: REGEXP_LIKE は真偽値を返すため CHECK 制約の条件式に直接記述でき、トリガーへの置き換えは不要です。
- B: T-SQL の文字列リテラルではバックスラッシュはエスケープ文字ではないため、二重にすると正規表現の意味が変わります。
- D: 検証をアプリケーション側に戻すと、データベース側で不正な値を防ぐという方針を満たせません。
【参考】
Contoso は Azure SQL Database の 1 つのデータベースで、注文をドキュメント形式で保持します。注文全体を 1 つの JSON ドキュメントとして 1 列に格納し、参照時にはスカラー値の取り出しと、明細の配列の表形式への展開の両方を行います。
CREATE TABLE dbo.Orders
(
order_id INT IDENTITY (1, 1) PRIMARY KEY,
order_info {{BLANK1}} NOT NULL
);
GO
-- 顧客名を 1 つのスカラー値として取り出す
SELECT order_id,
{{BLANK2}} (order_info, '$.customer.name') AS customer_name
FROM dbo.Orders;
GO
-- 明細の配列を行と列に展開する
SELECT o.order_id, d.sku, d.qty
FROM dbo.Orders AS o
CROSS APPLY {{BLANK3}} (CAST (o.order_info AS NVARCHAR (MAX)), '$.items')
WITH (sku VARCHAR (20) '$.sku', qty INT '$.qty') AS d;各空欄に当てはまるものを選択してください。
| ステートメント | 選択 |
|---|---|
|
BLANK1: 注文ドキュメントを格納する列のデータ型
|
|
|
BLANK2: パスで指定したスカラー値を 1 つ返す関数
|
|
|
BLANK3: JSON の配列を行と列に展開する関数
|
解説
【正解マッチング】
| 空欄 | 当てはまるもの |
|---|---|
| BLANK1: 注文ドキュメントを格納する列のデータ型 | json |
| BLANK2: パスで指定したスカラー値を 1 つ返す関数 | JSON_VALUE |
| BLANK3: JSON の配列を行と列に展開する関数 | OPENJSON |
【ポイント】
json データ型は JSON ドキュメントをネイティブなバイナリ形式で格納し、解析済みのため読み取りが効率的です。Azure SQL Database と Azure SQL Managed Instance では一般提供ですが、SQL Server 2025 と SQL database in Microsoft Fabric ではプレビューであるため、どのプラットフォームの話かを必ず確認します。列定義の書き方は他のデータ型と同じです。JSON_VALUE はパス式で指定した位置のスカラー値を 1 つ返すため、SELECT 句にそのまま置けます。OPENJSON は配列を行に展開するテーブル値関数で、WITH 句でスキーマを指定すると各要素が列に割り当てられます。OPENJSON は一部のプラットフォームで json データ型を直接受け取れないため、NVARCHAR (MAX) へ明示的に変換してから渡します。
【参考】
Contoso は 1 つのデータベースの中で、性質の異なる 4 つのデータ セットを扱います。それぞれの要求に最も適したテーブルの種類を対応付けてください。
- テンポラル テーブル
- グラフ テーブル
- 台帳テーブル
- メモリ最適化テーブル
解説
【正解マッチング】
| 要求 | テーブルの種類 |
|---|---|
| 行の変更履歴を期間で照会 | テンポラル テーブル |
| 改ざんの有無を暗号学的に検証 | 台帳テーブル |
| ノードとエッジの関係を照会 | グラフ テーブル |
| 高頻度の同時更新をロックなしで処理 | メモリ最適化テーブル |
【ポイント】
テンポラル テーブルはシステム バージョン管理により行の変更履歴を履歴テーブルへ自動的に保持し、FOR SYSTEM_TIME 句で任意の時点や期間の状態を照会できます。台帳テーブルは行の変更をハッシュとして連鎖させ、データベース ダイジェストと突き合わせることで改ざんの有無を暗号学的に検証できます。グラフ テーブルはノード テーブルとエッジ テーブルとして定義し、MATCH 述語で関係のパターンを照会します。メモリ最適化テーブルは行をメモリ上のデータ構造で保持し、ラッチもロックも使わない同時実行制御によって、高頻度の更新でも競合を抑えます。4 つは用途が重ならないため、履歴、改ざん検出、関係の照会、同時更新のどの要求かを読み取れば、選ぶべきテーブルの種類が一意に決まります。
【参考】
Contoso は会員情報を保持するテーブルを新規に作成します。会員の氏名は日本語、タイ語、アラビア語など複数の言語で登録され、最大 100 文字まで許可しますが、実際の値は 20 文字前後が大半です。データベースの既定の照合順序は日本語向けのものです。
開発者は次の定義を提案しました。
CREATE TABLE dbo.Members
(
member_id INT IDENTITY (1, 1) NOT NULL PRIMARY KEY,
full_name CHAR (100) NOT NULL,
country CHAR (2) NOT NULL,
joined_at DATE NOT NULL
);full_name 列の定義をどのように見直すべきですか。
解説
【正解: A】の理由
nvarchar は Unicode を格納するデータ型で、列の照合順序に依存せずに日本語、タイ語、アラビア語の文字をコード ポイントのまま保持できます。可変長であるため、宣言した最大長ではなく実際に格納した文字数に応じた記憶域だけを使い、20 文字前後の値が大半を占めるこの列では1 ページに収まる行数が増えて読み取り量も抑えられます。固定長の char や nchar は短い値でも宣言した長さまで空白で埋めるため、記憶域の面で不利になります。照合順序は列に 1 つしか指定できず、格納する言語に合わせて行ごとに切り替えることはできないので、複数の言語を1 つの列で扱うなら Unicode を格納できる型を選びます。括弧内に指定するのはバイト数ではなく文字数です。
【他選択肢が違う理由】
- B: 照合順序は列に 1 つしか指定できず、行ごとに言語へ合わせて切り替えることはできません。
- C: アプリケーションで変換しても char 列は非 Unicode のままで、コード ページにない文字は失われます。
- D: 固定長にしても検索は速くならず、短い値が多い列では空白の埋め込みで記憶域と読み取り量が増えます。
【参考】
Fabrikam の dbo.SalesHistory は 8 億行の履歴テーブルで、これまでは単一行の検索が中心でしたが、現在は集計を伴う分析クエリが大半を占めるようになりました。データベース管理者は、このテーブルをクラスター化列ストア インデックスへ移行し、夜間の一括ロードも継続できるようにします。
次の操作を正しい順序に並べ替えてください。
- 一意検索用の非クラスター化インデックスを追加
- 既存の行ストア インデックスを棚卸し
- DROP_EXISTING で列ストアに置き換え
- 分析主体になったクエリの傾向を確認
- 一括ロードのバッチ サイズを調整
解説
【正しい順序】
- 分析主体になったクエリの傾向を確認
- 既存の行ストア インデックスを棚卸し
- DROP_EXISTING で列ストアに置き換え
- 一意検索用の非クラスター化インデックスを追加
- 一括ロードのバッチ サイズを調整
【ポイント】
クラスター化列ストア インデックスは、集計と大量の走査が中心のテーブルに向く格納形式なので、まず実際のクエリが分析主体へ変わったことを確かめます。次に既存の行ストア インデックスを洗い出し、置き換える対象と残す対象を決めます。移行では、既存のクラスター化インデックスを削除してから作り直す代わりに DROP_EXISTING を指定して 1 つのステートメントで置き換えると、非クラスター化インデックスの再構築を避けられます。列ストアでも単一行の検索は残るため、その後に一意検索用の非クラスター化インデックスを追加します。最後に一括ロードを見直し、1 回あたり 102,400 行以上をまとめて渡すと、行が差分ストアを経由せず圧縮された行グループへ直接書き込まれます。
