sqlserver について
SQL Server の利用者向けに、データ型、クエリ構成、インデックス、トラブルシューティングをまとめた基本知識スキルです。SQL の例と一般的な指針も掲載しています。
主な機能
- 01データ型リファレンス
- 02日付・文字列関数
- 03JSON クエリ例
- 04インデックスとパーティションの例
- 05よくある問題のトラブルシューティング
活用シーン
- 01SQL Server のデータ型を調べる
- 02日付や JSON のクエリを書く
- 03インデックスとクエリ性能を確認する
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ claude-dev-suite/ claude-dev-suite --skill sqlserverインストール後、Claude Code で/sqlserverを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
quick-ref/datatypes.mdindexes.mdpartitioning.md詳細
SQL Server のコア知識
深い知識:包括的なドキュメントを参照するには、technology に
sqlserverを指定してmcp__documentation__fetch_docsを使用してください。
データ型
数値型
| 型 | 説明 | 範囲 |
|---|---|---|
BIT | ブール値(0/1) | 0, 1, NULL |
TINYINT | 1 バイト整数 | 0~255 |
SMALLINT | 2 バイト整数 | -32,768~32,767 |
INT | 4 バイト整数 | -2^31~2^31-1 |
BIGINT | 8 バイト整数 | -2^63~2^63-1 |
DECIMAL(p,s) | 固定精度 | p:1~38 桁 |
NUMERIC(p,s) | DECIMAL と同じ | p:1~38 桁 |
FLOAT | 8 バイト浮動小数点数 | 精度約 15 桁 |
REAL | 4 バイト浮動小数点数 | 精度約 7 桁 |
MONEY | 8 バイト通貨型 | ±922 兆 |
SMALLMONEY | 4 バイト通貨型 | ±214,748 |
文字列型
| 型 | 説明 | 最大サイズ |
|---|---|---|
CHAR(n) | 固定長 | 8,000 バイト |
VARCHAR(n) | 可変長 | 8,000 バイト |
VARCHAR(MAX) | 大容量の可変長 | 2 GB |
NCHAR(n) | Unicode 固定長 | 4,000 文字 |
NVARCHAR(n) | Unicode 可変長 | 4,000 文字 |
NVARCHAR(MAX) | 大容量の Unicode | 1 GB |
TEXT | レガシーの大容量型(非推奨) | 2 GB |
NTEXT | レガシーの Unicode 型(非推奨) | 1 GB |
日付/時刻型
| 型 | 説明 | 範囲 |
|---|---|---|
DATE | 日付のみ | 0001-01-01~9999-12-31 |
TIME(n) | 時刻のみ(精度 n=0~7) | 00:00:00~23:59:59 |
DATETIME | 日付+時刻 | 1753-01-01~9999-12-31 |
DATETIME2(n) | 拡張日時 | 0001-01-01~9999-12-31 |
DATETIMEOFFSET(n) | タイムゾーン付き | 同じ範囲+タイムゾーン |
SMALLDATETIME | 精度が低い日時 | 1900-01-01~2079-06-06 |
その他の型
| 型 | 説明 |
|---|---|
UNIQUEIDENTIFIER | 16 バイトの GUID |
BINARY(n) | 固定長バイナリ |
VARBINARY(n) | 可変長バイナリ |
VARBINARY(MAX) | 大容量バイナリ(2 GB) |
XML | XML データ |
JSON | JSON(NVARCHAR として保存) |
GEOGRAPHY | 空間データ |
GEOMETRY | 幾何データ |
HIERARCHYID | 階層内の位置 |
CREATE TABLE example (
id INT IDENTITY(1,1) PRIMARY KEY,
uuid UNIQUEIDENTIFIER DEFAULT NEWID(),
name NVARCHAR(100) NOT NULL,
price DECIMAL(10,2),
quantity INT DEFAULT 0,
is_active BIT DEFAULT 1,
created_at DATETIME2 DEFAULT SYSDATETIME(),
metadata NVARCHAR(MAX), -- For JSON
document VARBINARY(MAX) -- For files
);
IDENTITY 列
-- Auto-increment
CREATE TABLE employees (
id INT IDENTITY(1,1) PRIMARY KEY,
name NVARCHAR(100)
);
-- Get last identity
SELECT SCOPE_IDENTITY(); -- Current scope
SELECT @@IDENTITY; -- Any scope (avoid)
SELECT IDENT_CURRENT('employees'); -- Specific table
-- Insert with identity off
SET IDENTITY_INSERT employees ON;
INSERT INTO employees (id, name) VALUES (100, 'Admin');
SET IDENTITY_INSERT employees OFF;
-- Reseed identity
DBCC CHECKIDENT ('employees', RESEED, 0);
シーケンス(2012 以降)
-- Create sequence
CREATE SEQUENCE dbo.OrderSeq
AS INT
START WITH 1
INCREMENT BY 1
MINVALUE 1
NO MAXVALUE
NO CYCLE
CACHE 20;
-- Use sequence
INSERT INTO orders (id, customer_id)
VALUES (NEXT VALUE FOR dbo.OrderSeq, 1);
-- In DEFAULT
ALTER TABLE orders
ADD CONSTRAINT df_order_id DEFAULT (NEXT VALUE FOR dbo.OrderSeq) FOR id;
-- Get current without incrementing
SELECT current_value FROM sys.sequences WHERE name = 'OrderSeq';
-- Reset sequence
ALTER SEQUENCE dbo.OrderSeq RESTART WITH 1;
日付/時刻関数
-- Current date/time
SELECT GETDATE(); -- DATETIME
SELECT SYSDATETIME(); -- DATETIME2 (more precise)
SELECT GETUTCDATE(); -- UTC datetime
SELECT SYSUTCDATETIME(); -- UTC datetime2
SELECT SYSDATETIMEOFFSET(); -- With timezone
-- Date parts
SELECT YEAR(GETDATE());
SELECT MONTH(GETDATE());
SELECT DAY(GETDATE());
SELECT DATEPART(QUARTER, GETDATE());
SELECT DATENAME(WEEKDAY, GETDATE()); -- 'Monday'
-- Date arithmetic
SELECT DATEADD(DAY, 7, GETDATE()); -- Add 7 days
SELECT DATEADD(MONTH, -1, GETDATE()); -- Subtract 1 month
SELECT DATEDIFF(DAY, '2024-01-01', GETDATE()); -- Days between
-- Format (2012+)
SELECT FORMAT(GETDATE(), 'yyyy-MM-dd');
SELECT FORMAT(GETDATE(), 'dd/MM/yyyy HH:mm:ss');
-- Parse
SELECT CAST('2024-01-15' AS DATE);
SELECT CONVERT(DATETIME, '01/15/2024', 101); -- US format
SELECT PARSE('15 January 2024' AS DATE);
-- First/last of month
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0); -- First of month
SELECT EOMONTH(GETDATE()); -- Last of month (2012+)
文字列関数
-- Concatenation
SELECT 'Hello' + ' ' + 'World';
SELECT CONCAT('Hello', ' ', 'World');
SELECT CONCAT_WS(' ', 'Hello', 'World', NULL); -- With separator, ignores NULL
-- Substring
SELECT SUBSTRING('Hello World', 1, 5); -- 'Hello'
SELECT LEFT('Hello World', 5); -- 'Hello'
SELECT RIGHT('Hello World', 5); -- 'World'
-- Length
SELECT LEN('Hello'); -- 5 (chars, trims trailing spaces)
SELECT DATALENGTH('Hello'); -- 5 (bytes)
-- Case
SELECT UPPER('hello');
SELECT LOWER('HELLO');
-- Trim
SELECT TRIM(' hello ');
SELECT LTRIM(' hello');
SELECT RTRIM('hello ');
SELECT TRIM('x' FROM 'xxxhelloxxx'); -- 2017+
-- Replace
SELECT REPLACE('hello', 'l', 'L');
SELECT STUFF('Hello World', 7, 5, 'SQL'); -- 'Hello SQL'
-- Position
SELECT CHARINDEX('o', 'Hello World'); -- 5
SELECT CHARINDEX('o', 'Hello World', 6); -- 8 (start from 6)
-- Padding
SELECT RIGHT('0000000000' + '123', 10); -- '0000000123'
SELECT FORMAT(123, '0000000000'); -- 2012+
-- Split (2016+)
SELECT value FROM STRING_SPLIT('a,b,c', ',');
-- Aggregate strings (2017+)
SELECT STRING_AGG(name, ', ') FROM employees;
SELECT STRING_AGG(name, ', ') WITHIN GROUP (ORDER BY name) FROM employees;
JSON サポート
-- JSON functions (2016+)
DECLARE @json NVARCHAR(MAX) = '{"name":"John","age":30,"address":{"city":"NYC"}}';
-- Extract values
SELECT JSON_VALUE(@json, '$.name'); -- 'John'
SELECT JSON_VALUE(@json, '$.address.city'); -- 'NYC'
SELECT JSON_QUERY(@json, '$.address'); -- '{"city":"NYC"}'
-- Check if valid JSON
SELECT ISJSON(@json); -- 1
-- Modify JSON
SELECT JSON_MODIFY(@json, '$.age', 31);
SELECT JSON_MODIFY(@json, '$.email', '[email protected]');
-- Parse JSON array
DECLARE @arr NVARCHAR(MAX) = '[{"id":1,"name":"A"},{"id":2,"name":"B"}]';
SELECT * FROM OPENJSON(@arr) WITH (id INT, name NVARCHAR(50));
-- Generate JSON
SELECT id, name, email
FROM employees
FOR JSON AUTO; -- Auto-structure
SELECT id, name, email
FROM employees
FOR JSON PATH, ROOT('employees'); -- Custom structure
インデックスの種類
-- Clustered index (one per table, defines physical order)
CREATE CLUSTERED INDEX IX_emp_id ON employees(id);
-- Non-clustered index
CREATE NONCLUSTERED INDEX IX_emp_email ON employees(email);
-- Unique index
CREATE UNIQUE INDEX IX_emp_email ON employees(email);
-- Composite index
CREATE INDEX IX_emp_dept_name ON employees(department_id, last_name);
-- Included columns (covering index)
CREATE INDEX IX_emp_email ON employees(email)
INCLUDE (first_name, last_name, phone);
-- Filtered index
CREATE INDEX IX_active_emp ON employees(email)
WHERE is_active = 1;
-- Columnstore index (analytics)
CREATE COLUMNSTORE INDEX IX_sales_cs ON sales(product_id, amount, sale_date);
-- Or clustered columnstore
CREATE CLUSTERED COLUMNSTORE INDEX IX_sales_ccs ON sales;
-- Full-text index
CREATE FULLTEXT CATALOG ft_catalog;
CREATE FULLTEXT INDEX ON documents(content) KEY INDEX PK_documents;
テーブルのパーティション分割
-- 1. Create partition function
CREATE PARTITION FUNCTION pf_sales_date (DATE)
AS RANGE RIGHT FOR VALUES ('2022-01-01', '2023-01-01', '2024-01-01');
-- 2. Create partition scheme
CREATE PARTITION SCHEME ps_sales_date
AS PARTITION pf_sales_date
TO (fg_2021, fg_2022, fg_2023, fg_2024);
-- 3. Create partitioned table
CREATE TABLE sales (
id INT IDENTITY(1,1),
sale_date DATE,
amount DECIMAL(10,2),
CONSTRAINT PK_sales PRIMARY KEY (id, sale_date)
) ON ps_sales_date(sale_date);
-- View partitions
SELECT
$PARTITION.pf_sales_date(sale_date) AS partition_number,
COUNT(*) AS row_count
FROM sales
GROUP BY $PARTITION.pf_sales_date(sale_date);
-- Split partition (add new)
ALTER PARTITION SCHEME ps_sales_date NEXT USED fg_2025;
ALTER PARTITION FUNCTION pf_sales_date() SPLIT RANGE ('2025-01-01');
-- Merge partitions
ALTER PARTITION FUNCTION pf_sales_date() MERGE RANGE ('2022-01-01');
-- Switch partition (instant move)
ALTER TABLE sales SWITCH PARTITION 1 TO sales_archive;
システムバージョン管理テンポラルテーブル(2016 以降)
-- Create temporal table
CREATE TABLE employees (
id INT PRIMARY KEY,
name NVARCHAR(100),
salary DECIMAL(10,2),
-- System time columns
valid_from DATETIME2 GENERATED ALWAYS AS ROW START,
valid_to DATETIME2 GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (valid_from, valid_to)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.employees_history));
-- Query historical data
SELECT * FROM employees FOR SYSTEM_TIME AS OF '2024-01-01';
SELECT * FROM employees FOR SYSTEM_TIME BETWEEN '2024-01-01' AND '2024-06-01';
SELECT * FROM employees FOR SYSTEM_TIME ALL;
-- Disable versioning for maintenance
ALTER TABLE employees SET (SYSTEM_VERSIONING = OFF);
-- ... maintenance ...
ALTER TABLE employees SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.employees_history));
共通テーブル式
-- Basic CTE
;WITH emp_stats AS (
SELECT department_id, COUNT(*) AS emp_count, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
)
SELECT d.name, es.emp_count, es.avg_salary
FROM departments d
JOIN emp_stats es ON d.id = es.department_id;
-- Recursive CTE
;WITH hierarchy AS (
-- Anchor
SELECT id, name, manager_id, 0 AS level
FROM employees WHERE manager_id IS NULL
UNION ALL
-- Recursive
SELECT e.id, e.name, e.manager_id, h.level + 1
FROM employees e
JOIN hierarchy h ON e.manager_id = h.id
)
SELECT * FROM hierarchy OPTION (MAXRECURSION 100);
ページネーション
-- OFFSET-FETCH (2012+)
SELECT id, name, email
FROM employees
ORDER BY id
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY;
-- With variable
DECLARE @PageNum INT = 3, @PageSize INT = 10;
SELECT id, name, email
FROM employees
ORDER BY id
OFFSET (@PageNum - 1) * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;
-- ROW_NUMBER (older method)
;WITH numbered AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM employees
)
SELECT * FROM numbered WHERE rn BETWEEN 21 AND 30;
このスキルを使用しない場合
- T-SQL プログラミング - ストアドプロシージャ、関数、トリガーには
tsqlスキルを使用してください - PostgreSQL - PostgreSQL 固有の機能には
postgresqlスキルを使用してください - Oracle - Oracle の機能には
oracleスキルを使用してください - 基本的な SQL - ANSI SQL の基本には
sql-fundamentalsを使用してください
アンチパターン
| アンチパターン | 問題 | 解決策 |
|---|---|---|
| SET NOCOUNT ON を使用しない | ネットワークのオーバーヘッド | すべてのストアドプロシージャに追加する |
| カーソルを使用する | パフォーマンスが低下する | セットベースの操作を使用する |
| クラスター化インデックスがない | ヒープスキャンが発生する | クラスター化インデックスを追加する |
| インデックスで INCLUDE を使用しない | キールックアップが発生する | カバリングインデックスを使用する |
| 非推奨の TEXT/NTEXT を使用する | 互換性の問題が発生する | VARCHAR(MAX)/NVARCHAR(MAX) を使用する |
| SCOPE_IDENTITY の代わりに @@IDENTITY を使用する | 誤った IDENTITY 値が返る | SCOPE_IDENTITY() を使用する |
よくある問題のトラブルシューティング
| 問題 | 診断 | 修正 |
|---|---|---|
| クエリが遅い | SET STATISTICS IO ON | インデックスを追加し、実行プランを確認する |
| ブロッキング | sp_who2 またはアクティビティモニター | ブロッキングしているプロセスを終了し、最適化する |
| デッドロック | 拡張イベント、トレースフラグ 1222 | 一貫したアクセス順序を保ち、トランザクションを短くする |
| IDENTITY の問題 | DBCC CHECKIDENT | 再シードするか、SCOPE_IDENTITY を使用する |
| TempDB の競合 | 待機統計を確認する | TempDB ファイルを追加し、クエリを最適化する |
参考ドキュメント
コメント
Markdown 対応