SQL Server数据插入 #

一、INSERT语句概述 #

1.1 基本语法 #

sql
INSERT [INTO] table_name [(column_list)]
VALUES (value_list) [, (value_list) ...];

-- 或
INSERT [INTO] table_name [(column_list)]
SELECT column_list FROM source_table;

1.2 示例表结构 #

sql
-- 创建示例表
CREATE TABLE users (
    id INT IDENTITY(1,1) PRIMARY KEY,
    name NVARCHAR(50) NOT NULL,
    email VARCHAR(100),
    age INT,
    status BIT DEFAULT 1,
    created_at DATETIME2 DEFAULT SYSDATETIME()
);

CREATE TABLE orders (
    id INT IDENTITY(1,1) PRIMARY KEY,
    user_id INT,
    order_date DATE DEFAULT GETDATE(),
    amount DECIMAL(10,2),
    status NVARCHAR(20) DEFAULT 'pending'
);

二、单行插入 #

2.1 基本插入 #

sql
-- 插入所有列
INSERT INTO users (name, email, age, status)
VALUES ('John', 'john@example.com', 25, 1);

-- 插入部分列(其他使用默认值或NULL)
INSERT INTO users (name, email)
VALUES ('Jane', 'jane@example.com');

-- 省略列名(按顺序插入所有列,不推荐)
INSERT INTO users
VALUES ('Bob', 'bob@example.com', 28, 0, DEFAULT);

2.2 使用DEFAULT #

sql
-- 使用DEFAULT关键字
INSERT INTO users (name, email, age, status, created_at)
VALUES ('Alice', 'alice@example.com', 22, DEFAULT, DEFAULT);

-- 省略有默认值的列
INSERT INTO users (name, email, age)
VALUES ('Charlie', 'charlie@example.com', 35);

2.3 使用NULL #

sql
-- 显式插入NULL
INSERT INTO users (name, email, age, status)
VALUES ('David', NULL, 30, 1);

-- 省略允许NULL的列
INSERT INTO users (name, age)
VALUES ('Eve', 28);

三、多行插入 #

3.1 VALUES多行插入 #

sql
-- 一次插入多行
INSERT INTO users (name, email, age, status)
VALUES 
    ('User1', 'user1@example.com', 25, 1),
    ('User2', 'user2@example.com', 30, 1),
    ('User3', 'user3@example.com', 28, 0),
    ('User4', 'user4@example.com', 22, 1),
    ('User5', 'user5@example.com', 35, 0);

-- 最多支持1000行

3.2 使用UNION ALL #

sql
-- 使用UNION ALL插入多行
INSERT INTO users (name, email, age)
SELECT 'UserA', 'usera@example.com', 25
UNION ALL SELECT 'UserB', 'userb@example.com', 30
UNION ALL SELECT 'UserC', 'userc@example.com', 28;

四、SELECT INTO插入 #

4.1 创建新表并插入 #

sql
-- 创建新表并插入数据
SELECT * INTO users_backup
FROM users;

-- 创建空表结构
SELECT * INTO users_empty
FROM users
WHERE 1 = 0;

-- 选择部分列
SELECT id, name, email INTO users_simple
FROM users
WHERE status = 1;

4.2 从多个表创建 #

sql
-- 从多表查询创建新表
SELECT 
    u.id,
    u.name,
    o.order_date,
    o.amount
INTO user_orders
FROM users u
INNER JOIN orders o ON u.id = o.user_id;

五、INSERT SELECT #

5.1 从查询插入 #

sql
-- 从另一个表插入
INSERT INTO users_backup (name, email, age, status)
SELECT name, email, age, status
FROM users
WHERE status = 1;

-- 从多表查询插入
INSERT INTO user_summary (user_id, user_name, total_orders)
SELECT 
    u.id,
    u.name,
    COUNT(o.id)
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name;

5.2 条件插入 #

sql
-- 只插入不存在的数据
INSERT INTO users (name, email, age)
SELECT name, email, age
FROM new_users n
WHERE NOT EXISTS (
    SELECT 1 FROM users u WHERE u.email = n.email
);

-- 使用EXCEPT
INSERT INTO users (name, email, age)
SELECT name, email, age FROM new_users
EXCEPT
SELECT name, email, age FROM users;

六、批量插入 #

6.1 BULK INSERT #

sql
-- 从CSV文件批量插入
BULK INSERT users
FROM 'D:\Data\users.csv'
WITH (
    FIELDTERMINATOR = ',',
    ROWTERMINATOR = '\n',
    FIRSTROW = 2,           -- 跳过标题行
    TABLOCK
);

-- 完整选项
BULK INSERT orders
FROM 'D:\Data\orders.txt'
WITH (
    FIELDTERMINATOR = '|',
    ROWTERMINATOR = '0x0a',
    FIRSTROW = 1,
    LASTROW = 1000,
    MAXERRORS = 10,
    ERRORFILE = 'D:\Data\errors.txt',
    CODEPAGE = '65001',     -- UTF-8
    DATAFILETYPE = 'char',
    TABLOCK,
    CHECK_CONSTRAINTS
);

6.2 OPENROWSET #

sql
-- 使用OPENROWSET读取文件
INSERT INTO users (name, email, age)
SELECT name, email, age
FROM OPENROWSET(
    BULK 'D:\Data\users.csv',
    FORMATFILE = 'D:\Data\users_format.xml',
    FIRSTROW = 2
) AS t;

-- 直接查询文件
SELECT * FROM OPENROWSET(
    BULK 'D:\Data\users.csv',
    SINGLE_CLOB
) AS contents;

6.3 格式文件 #

xml
<!-- users_format.xml -->
<?xml version="1.0"?>
<BCPFORMAT xmlns="http://schemas.microsoft.com/sqlserver/2004/bulkload/format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<RECORD>
  <FIELD ID="1" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="50"/>
  <FIELD ID="2" xsi:type="CharTerm" TERMINATOR="," MAX_LENGTH="100"/>
  <FIELD ID="3" xsi:type="CharTerm" TERMINATOR="\r\n"/>
</RECORD>
<ROW>
  <COLUMN SOURCE="1" NAME="name" xsi:type="SQLNVARCHAR"/>
  <COLUMN SOURCE="2" NAME="email" xsi:type="SQLVARCHAR"/>
  <COLUMN SOURCE="3" NAME="age" xsi:type="SQLINT"/>
</ROW>
</BCPFORMAT>

七、表值参数插入 #

7.1 创建表类型 #

sql
-- 创建表类型
CREATE TYPE UserType AS TABLE (
    name NVARCHAR(50),
    email VARCHAR(100),
    age INT
);

7.2 使用表值参数 #

sql
-- 创建存储过程
CREATE PROCEDURE usp_InsertUsers
    @users UserType READONLY
AS
BEGIN
    INSERT INTO users (name, email, age)
    SELECT name, email, age FROM @users;
END
GO

-- 调用存储过程
DECLARE @newUsers AS UserType;
INSERT INTO @newUsers VALUES 
    ('UserX', 'userx@example.com', 25),
    ('UserY', 'usery@example.com', 30);

EXEC usp_InsertUsers @newUsers;

八、OUTPUT子句 #

8.1 返回插入的数据 #

sql
-- 返回插入的数据
INSERT INTO users (name, email, age)
OUTPUT inserted.id, inserted.name, inserted.email
VALUES ('Test', 'test@example.com', 25);

-- 输出结果
-- id | name | email
-- 10 | Test | test@example.com

8.2 输出到表 #

sql
-- 创建审计表
CREATE TABLE users_audit (
    action NVARCHAR(10),
    id INT,
    name NVARCHAR(50),
    action_time DATETIME DEFAULT GETDATE()
);

-- 插入并记录到审计表
INSERT INTO users (name, email, age)
OUTPUT 'INSERT', inserted.id, inserted.name INTO users_audit
VALUES ('AuditTest', 'audit@example.com', 30);

8.3 多行输出 #

sql
-- 批量插入并输出
INSERT INTO users (name, email, age)
OUTPUT inserted.id, inserted.name, inserted.email
VALUES 
    ('Multi1', 'multi1@example.com', 25),
    ('Multi2', 'multi2@example.com', 30),
    ('Multi3', 'multi3@example.com', 28);

九、IDENTITY处理 #

9.1 获取标识值 #

sql
-- 插入后获取标识值
INSERT INTO users (name, email) VALUES ('NewUser', 'new@example.com');
SELECT SCOPE_IDENTITY() AS [NewID];

-- 使用OUTPUT获取
INSERT INTO users (name, email)
OUTPUT inserted.id
VALUES ('NewUser2', 'new2@example.com');

9.2 插入指定标识值 #

sql
-- 启用标识插入
SET IDENTITY_INSERT users ON;

INSERT INTO users (id, name, email)
VALUES (1000, 'Special', 'special@example.com');

SET IDENTITY_INSERT users OFF;

十、特殊插入 #

10.1 使用函数 #

sql
-- 使用内置函数
INSERT INTO users (name, email, created_at)
VALUES ('FuncTest', 'func@example.com', GETDATE());

-- 使用NEWID()
INSERT INTO sessions (id, user_id)
VALUES (NEWID(), 1);

-- 使用序列
INSERT INTO users (id, name)
VALUES (NEXT VALUE FOR seq_user_id, 'SeqUser');

10.2 使用表达式 #

sql
-- 使用计算表达式
INSERT INTO products (name, price, discounted_price)
VALUES ('Product', 100.00, 100.00 * 0.9);

-- 使用CASE
INSERT INTO users (name, status)
VALUES ('Test', CASE WHEN 1=1 THEN 1 ELSE 0 END);

10.3 使用子查询 #

sql
-- 使用子查询
INSERT INTO user_stats (user_id, order_count)
SELECT 
    u.id,
    (SELECT COUNT(*) FROM orders WHERE user_id = u.id)
FROM users u;

十一、插入性能优化 #

11.1 批量插入优化 #

sql
-- 使用TABLOCK提示
INSERT INTO users WITH (TABLOCK) (name, email, age)
SELECT name, email, age FROM staging_users;

-- 禁用约束和索引(大数据量)
ALTER TABLE users NOCHECK CONSTRAINT ALL;
-- 执行批量插入
ALTER TABLE users CHECK CONSTRAINT ALL;

-- 使用最小日志模式
-- 在简单或大容量日志恢复模式下

11.2 使用临时表 #

sql
-- 先导入临时表
SELECT * INTO #temp_users
FROM OPENROWSET(BULK 'D:\Data\users.csv', FORMATFILE = 'D:\Data\format.xml') AS t;

-- 再插入目标表
INSERT INTO users (name, email, age)
SELECT name, email, age FROM #temp_users;

DROP TABLE #temp_users;

十二、错误处理 #

12.1 TRY-CATCH #

sql
BEGIN TRY
    INSERT INTO users (name, email)
    VALUES ('Test', 'test@example.com');
    
    PRINT '插入成功';
END TRY
BEGIN CATCH
    PRINT '插入失败: ' + ERROR_MESSAGE();
    
    -- 可以选择回滚事务
END CATCH

12.2 忽略错误继续 #

sql
-- 使用INSERT...SELECT过滤错误数据
BEGIN TRY
    INSERT INTO users (name, email, age)
    SELECT name, email, age
    FROM source_users
    WHERE age BETWEEN 0 AND 150;  -- 过滤不满足约束的数据
END TRY
BEGIN CATCH
    PRINT '部分数据插入失败';
END CATCH

十三、插入验证 #

13.1 检查插入结果 #

sql
-- 使用@@ROWCOUNT
INSERT INTO users (name, email)
VALUES ('Test', 'test@example.com');

IF @@ROWCOUNT > 0
    PRINT '插入成功,影响 ' + CAST(@@ROWCOUNT AS VARCHAR) + ' 行';
ELSE
    PRINT '插入失败';

13.2 验证数据 #

sql
-- 插入后验证
DECLARE @name NVARCHAR(50) = 'VerifyTest';
DECLARE @email VARCHAR(100) = 'verify@example.com';

INSERT INTO users (name, email) VALUES (@name, @email);

IF EXISTS (SELECT 1 FROM users WHERE name = @name AND email = @email)
    PRINT '数据验证成功';
ELSE
    PRINT '数据验证失败';

十四、总结 #

插入数据要点:

方法 说明 适用场景
VALUES 单行/多行插入 少量数据
INSERT SELECT 从查询插入 表间复制
SELECT INTO 创建新表插入 备份、复制
BULK INSERT 批量文件导入 大数据量
表值参数 批量程序插入 应用程序

最佳实践:

  1. 始终指定列名
  2. 大数据量使用批量插入
  3. 使用事务保证数据完整性
  4. 使用OUTPUT获取插入结果
  5. 考虑禁用约束和索引提高性能

下一步,让我们学习数据更新!

最后更新:2026-03-27