SQL Server数据类型 #

一、数据类型概述 #

SQL Server 提供了丰富的数据类型,主要分为以下几类:

text
SQL Server 数据类型
├── 数值类型
│   ├── 整数类型
│   ├── 小数类型
│   └── 货币类型
├── 字符串类型
│   ├── 非Unicode
│   └── Unicode
├── 日期时间类型
├── 二进制类型
├── 其他类型
│   ├── uniqueidentifier
│   ├── XML
│   ├── JSON
│   └── 空间数据
└── 特殊类型
    ├── sql_variant
    ├── hierarchyid
    └── table

二、数值类型 #

2.1 整数类型 #

类型 存储 范围 说明
TINYINT 1字节 0 ~ 255 小整数
SMALLINT 2字节 -32,768 ~ 32,767 短整数
INT 4字节 -2^31 ~ 2^31-1 标准整数
BIGINT 8字节 -2^63 ~ 2^63-1 大整数
sql
-- 创建表
CREATE TABLE numbers (
    tiny_col TINYINT,
    small_col SMALLINT,
    int_col INT,
    big_col BIGINT
);

-- 插入数据
INSERT INTO numbers VALUES (255, 32767, 2147483647, 9223372036854775807);

-- 查询
SELECT * FROM numbers;

tiny_col | small_col | int_col    | big_col
---------|-----------|------------|--------------------
255      | 32767     | 2147483647 | 9223372036854775807

2.2 小数类型 #

DECIMAL/NUMERIC #

sql
-- DECIMAL(p, s) 或 NUMERIC(p, s)
-- p:精度(总位数),1-38
-- s:小数位数,0-p

CREATE TABLE decimals (
    price DECIMAL(10, 2),    -- 10位总长,2位小数
    rate NUMERIC(5, 4)       -- 5位总长,4位小数
);

INSERT INTO decimals VALUES (12345678.90, 1.2345);

-- 存储:根据精度自动分配
-- 1-9位:5字节
-- 10-19位:9字节
-- 20-28位:13字节
-- 29-38位:17字节

FLOAT/REAL #

sql
-- FLOAT(n):近似数值,n为尾数位数
-- REAL = FLOAT(24)

CREATE TABLE floats (
    float_col FLOAT,         -- 双精度
    real_col REAL            -- 单精度
);

INSERT INTO floats VALUES (123456789.123456789, 12345.6789);

-- FLOAT:8字节,约15位精度
-- REAL:4字节,约7位精度

-- 注意:浮点数可能有精度损失
SELECT CAST(0.1 AS FLOAT) + CAST(0.2 AS FLOAT);
-- 结果可能不是精确的0.3

2.3 货币类型 #

类型 存储 范围 精度
SMALLMONEY 4字节 -214,748.3648 ~ 214,748.3647 4位小数
MONEY 8字节 -2^63/10000 ~ 2^63-1/10000 4位小数
sql
CREATE TABLE products (
    id INT,
    name NVARCHAR(100),
    price SMALLMONEY,
    total MONEY
);

INSERT INTO products VALUES 
    (1, 'Product A', 99.99, 999999.99),
    (2, 'Product B', 199.50, 999999999999.99);

-- 货币类型自动保留4位小数
SELECT * FROM products;

三、字符串类型 #

3.1 非Unicode字符串 #

类型 说明 最大长度
CHAR(n) 定长 1-8000字符
VARCHAR(n) 变长 1-8000字符
VARCHAR(MAX) 变长 2^31-1字符
TEXT 已废弃 2^31-1字符
sql
CREATE TABLE strings (
    code CHAR(10),           -- 定长,不足补空格
    name VARCHAR(50),        -- 变长,最多50
    description VARCHAR(MAX) -- 大文本
);

INSERT INTO strings VALUES 
    ('ABC', 'Product Name', 'Very long description...');

-- CHAR定长特性
SELECT LEN(code) AS '实际长度', DATALENGTH(code) AS '存储长度'
FROM strings;
-- 实际长度: 3, 存储长度: 10

3.2 Unicode字符串 #

类型 说明 最大长度
NCHAR(n) 定长Unicode 1-4000字符
NVARCHAR(n) 变长Unicode 1-4000字符
NVARCHAR(MAX) 变长Unicode 2^30-1字符
NTEXT 已废弃 2^30-1字符
sql
CREATE TABLE users (
    id INT,
    name NVARCHAR(50),       -- 支持中文等Unicode
    address NCHAR(100)       -- 定长Unicode
);

INSERT INTO users VALUES 
    (1, N'张三', N'北京市朝阳区'),
    (2, N'李四', N'上海市浦东新区');

-- Unicode字符串前缀 N
SELECT * FROM users WHERE name = N'张三';

-- 存储:每个字符2字节
SELECT name, LEN(name) AS '字符数', DATALENGTH(name) AS '字节数'
FROM users;
-- 字符数: 2, 字节数: 4

3.3 字符串类型选择 #

text
选择建议:
├── 存储英文/数字
│   ├── 固定长度 → CHAR
│   └── 可变长度 → VARCHAR
│
├── 存储中文/多语言
│   ├── 固定长度 → NCHAR
│   └── 可变长度 → NVARCHAR
│
├── 大文本
│   ├── 英文 → VARCHAR(MAX)
│   └── 多语言 → NVARCHAR(MAX)
│
└── 避免使用 TEXT/NTEXT(已废弃)

四、日期时间类型 #

4.1 日期时间类型对比 #

类型 存储 范围 精度
DATE 3字节 0001-01-01 ~ 9999-12-31 1天
TIME 3-5字节 00:00:00 ~ 23:59:59 100ns
DATETIME2 6-8字节 0001-01-01 ~ 9999-12-31 100ns
DATETIME 8字节 1753-01-01 ~ 9999-12-31 3.33ms
SMALLDATETIME 4字节 1900-01-01 ~ 2079-06-06 1分钟
DATETIMEOFFSET 8-10字节 带时区 100ns

4.2 DATE类型 #

sql
CREATE TABLE events (
    id INT,
    event_date DATE
);

INSERT INTO events VALUES 
    (1, '2024-01-15'),
    (2, GETDATE()),
    (3, CURRENT_TIMESTAMP);

-- DATE格式
SELECT 
    event_date,
    CONVERT(VARCHAR(10), event_date, 120) AS '格式化日期',
    YEAR(event_date) AS '年',
    MONTH(event_date) AS '月',
    DAY(event_date) AS '日'
FROM events;

4.3 TIME类型 #

sql
CREATE TABLE schedules (
    id INT,
    start_time TIME(0),      -- 秒精度
    end_time TIME(7)         -- 100纳秒精度
);

INSERT INTO schedules VALUES 
    (1, '09:00:00', '17:30:00'),
    (2, '14:30:45.1234567', '18:00:00');

-- TIME精度
SELECT 
    start_time,
    end_time,
    DATEPART(HOUR, start_time) AS '小时',
    DATEPART(MINUTE, start_time) AS '分钟'
FROM schedules;

4.4 DATETIME2类型 #

sql
CREATE TABLE orders (
    id INT,
    order_date DATETIME2(3),  -- 毫秒精度
    created_at DATETIME2      -- 默认7位精度
);

INSERT INTO orders VALUES 
    (1, '2024-01-15 10:30:45.123', '2024-01-15 10:30:45.1234567'),
    (2, SYSDATETIME(), SYSDATETIME());

-- 日期时间函数
SELECT 
    order_date,
    SYSDATETIME() AS '当前时间',
    SYSUTCDATETIME() AS 'UTC时间',
    GETDATE() AS 'DATETIME类型'
FROM orders;

4.5 DATETIMEOFFSET类型 #

sql
CREATE TABLE meetings (
    id INT,
    meeting_time DATETIMEOFFSET
);

INSERT INTO meetings VALUES 
    ('2024-01-15 10:00:00 +08:00'),  -- 北京时间
    ('2024-01-15 02:00:00 +00:00');  -- UTC时间

-- 时区转换
SELECT 
    meeting_time,
    SWITCHOFFSET(meeting_time, '+00:00') AS 'UTC',
    SWITCHOFFSET(meeting_time, '+08:00') AS '北京时间'
FROM meetings;

4.6 日期时间格式化 #

sql
DECLARE @dt DATETIME = '2024-01-15 10:30:45';

-- CONVERT格式化
SELECT 
    CONVERT(VARCHAR(30), @dt, 120) AS 'YYYY-MM-DD HH:MI:SS',
    CONVERT(VARCHAR(10), @dt, 23) AS 'YYYY-MM-DD',
    CONVERT(VARCHAR(8), @dt, 108) AS 'HH:MI:SS',
    CONVERT(VARCHAR(30), @dt, 101) AS 'MM/DD/YYYY',
    CONVERT(VARCHAR(30), @dt, 103) AS 'DD/MM/YYYY';

-- FORMAT函数(SQL Server 2012+)
SELECT 
    FORMAT(@dt, 'yyyy-MM-dd') AS '日期',
    FORMAT(@dt, 'HH:mm:ss') AS '时间',
    FORMAT(@dt, 'yyyy年MM月dd日') AS '中文格式';

五、二进制类型 #

5.1 二进制类型对比 #

类型 说明 最大长度
BINARY(n) 定长二进制 1-8000字节
VARBINARY(n) 变长二进制 1-8000字节
VARBINARY(MAX) 大二进制 2^31-1字节
IMAGE 已废弃 2^31-1字节
sql
CREATE TABLE files (
    id INT,
    hash BINARY(32),           -- MD5哈希
    data VARBINARY(MAX)        -- 文件数据
);

-- 插入二进制数据
INSERT INTO files (id, hash, data)
VALUES (
    1, 
    HASHBYTES('MD5', 'test'), 
    CAST('Hello World' AS VARBINARY(MAX))
);

-- 读取
SELECT 
    id,
    CONVERT(VARCHAR(64), hash, 1) AS 'Hash',
    CONVERT(VARCHAR(MAX), data) AS 'Data'
FROM files;

六、其他类型 #

6.1 UNIQUEIDENTIFIER #

sql
-- GUID类型,16字节
CREATE TABLE sessions (
    id UNIQUEIDENTIFIER DEFAULT NEWID(),
    user_id INT,
    created_at DATETIME DEFAULT GETDATE()
);

-- 插入
INSERT INTO sessions (id, user_id)
VALUES (NEWID(), 1);

-- 或使用默认值
INSERT INTO sessions (user_id) VALUES (2);

-- 查询
SELECT * FROM sessions;

-- NEWID() vs NEWSEQUENTIALID()
-- NEWID(): 随机GUID
-- NEWSEQUENTIALID(): 顺序GUID(更适合索引)

6.2 XML类型 #

sql
CREATE TABLE docs (
    id INT,
    content XML
);

-- 插入XML
INSERT INTO docs VALUES 
    (1, '<root><item id="1">Item 1</item></root>');

-- 查询XML
SELECT 
    content,
    content.query('/root/item') AS 'Item',
    content.value('(/root/item/@id)[1]', 'INT') AS 'ItemID'
FROM docs;

-- XML方法
DECLARE @xml XML = '<root><item id="1">A</item><item id="2">B</item></root>';

SELECT 
    @xml.query('/root/item') AS 'query',
    @xml.value('(/root/item)[1]', 'VARCHAR(10)') AS 'value',
    @xml.exist('/root/item[@id="1"]') AS 'exist',
    @xml.nodes('/root/item') AS T(c);

6.3 JSON支持 #

sql
-- SQL Server 2016+ 支持JSON
-- 使用NVARCHAR存储JSON

CREATE TABLE settings (
    id INT,
    config NVARCHAR(MAX)
);

-- 插入JSON
INSERT INTO settings VALUES 
    (1, '{"name": "test", "values": [1, 2, 3]}');

-- 解析JSON
SELECT 
    config,
    JSON_VALUE(config, '$.name') AS 'Name',
    JSON_QUERY(config, '$.values') AS 'Values'
FROM settings;

-- OPENJSON解析
DECLARE @json NVARCHAR(MAX) = '[{"id":1,"name":"A"},{"id":2,"name":"B"}]';

SELECT *
FROM OPENJSON(@json)
WITH (
    id INT '$.id',
    name NVARCHAR(50) '$.name'
);

6.4 空间数据 #

sql
-- GEOMETRY:平面空间数据
-- GEOGRAPHY:地理空间数据

CREATE TABLE locations (
    id INT,
    point GEOMETRY,
    area GEOGRAPHY
);

-- 插入空间数据
INSERT INTO locations VALUES 
    (1, 
     GEOMETRY::Point(1, 1, 0),
     GEOGRAPHY::Point(39.9, 116.4, 4326));  -- 北京坐标

-- 空间方法
SELECT 
    id,
    point.ToString() AS 'Point',
    point.STX AS 'X',
    point.STY AS 'Y',
    area.Lat AS 'Latitude',
    area.Long AS 'Longitude'
FROM locations;

七、特殊类型 #

7.1 SQL_VARIANT #

sql
-- 可以存储各种类型的数据
CREATE TABLE mixed (
    id INT,
    value SQL_VARIANT
);

INSERT INTO mixed VALUES 
    (1, 100),
    (2, 'Hello'),
    (3, GETDATE()),
    (4, 123.45);

SELECT 
    id,
    value,
    SQL_VARIANT_PROPERTY(value, 'BaseType') AS 'Type',
    SQL_VARIANT_PROPERTY(value, 'MaxLength') AS 'Length'
FROM mixed;

7.2 HIERARCHYID #

sql
-- 表示层次结构
CREATE TABLE employees (
    id INT,
    name NVARCHAR(50),
    org_path HIERARCHYID
);

-- 插入层级数据
INSERT INTO employees VALUES 
    (1, 'CEO', HIERARCHYID::GetRoot()),
    (2, 'Manager', '/1/'),
    (3, 'Employee', '/1/1/');

-- 层级查询
SELECT 
    id,
    name,
    org_path.ToString() AS 'Path',
    org_path.GetLevel() AS 'Level'
FROM employees;

7.3 TABLE类型 #

sql
-- 表类型(用于表值参数)
CREATE TYPE UserTableType AS TABLE (
    id INT,
    name NVARCHAR(50)
);

-- 在存储过程中使用
CREATE PROCEDURE usp_InsertUsers
    @users UserTableType READONLY
AS
BEGIN
    INSERT INTO users (id, name)
    SELECT id, name FROM @users;
END

八、数据类型转换 #

8.1 CAST和CONVERT #

sql
-- CAST:ANSI标准
SELECT CAST(123.45 AS INT) AS 'Int';
SELECT CAST('2024-01-15' AS DATE) AS 'Date';
SELECT CAST(123 AS VARCHAR(10)) AS 'String';

-- CONVERT:SQL Server特有,支持格式
SELECT CONVERT(VARCHAR(30), GETDATE(), 120) AS 'DateTime';
SELECT CONVERT(INT, '123') AS 'Int';
SELECT CONVERT(DECIMAL(10,2), '123.456') AS 'Decimal';

8.2 TRY_CAST和TRY_CONVERT #

sql
-- 转换失败返回NULL而不是错误
SELECT TRY_CAST('abc' AS INT) AS 'Result';  -- NULL
SELECT TRY_CAST('123' AS INT) AS 'Result';  -- 123

SELECT TRY_CONVERT(INT, 'abc') AS 'Result';  -- NULL
SELECT TRY_CONVERT(DATE, '2024-01-15') AS 'Result';  -- 2024-01-15

-- 安全转换
SELECT 
    value,
    TRY_CAST(value AS INT) AS 'IntValue',
    CASE 
        WHEN TRY_CAST(value AS INT) IS NULL AND value IS NOT NULL 
        THEN 'Invalid'
        ELSE 'Valid'
    END AS 'Status'
FROM (VALUES ('123'), ('abc'), (NULL)) AS T(value);

8.3 隐式转换 #

sql
-- SQL Server自动转换
DECLARE @int INT = 123;
DECLARE @varchar VARCHAR(10) = '456';

-- 隐式转换
SELECT @int + @varchar;  -- 579(varchar转int)

-- 优先级规则
-- DATETIME > FLOAT > DECIMAL > INT > VARCHAR

九、NULL处理 #

9.1 NULL特性 #

sql
-- NULL表示未知或缺失
-- NULL不等于任何值,包括NULL本身

SELECT 
    CASE WHEN NULL = NULL THEN 'Equal' ELSE 'Not Equal' END AS 'Result';
-- Result: Not Equal

SELECT 
    CASE WHEN NULL <> NULL THEN 'Not Equal' ELSE 'Equal' END AS 'Result';
-- Result: Equal

9.2 NULL函数 #

sql
-- ISNULL:替换NULL
SELECT ISNULL(NULL, 'Default');  -- Default
SELECT ISNULL(name, 'Unknown') FROM users;

-- COALESCE:返回第一个非NULL值
SELECT COALESCE(NULL, NULL, 'Third', 'Fourth');  -- Third

-- NULLIF:相等返回NULL
SELECT NULLIF(10, 10);  -- NULL
SELECT NULLIF(10, 20);  -- 10

-- IIF:条件表达式
SELECT IIF(1 = 1, 'True', 'False');  -- True

十、总结 #

数据类型选择指南:

场景 推荐类型
主键ID INT IDENTITY 或 BIGINT
字符串(英文) VARCHAR
字符串(中文) NVARCHAR
金额 DECIMAL(18,2) 或 MONEY
日期 DATE
日期时间 DATETIME2
布尔值 BIT
大文本 NVARCHAR(MAX)
文件数据 VARBINARY(MAX)
GUID UNIQUEIDENTIFIER

下一步,让我们学习数据库操作!

最后更新:2026-03-27