SQL Server 中 INSERT 使用 OFFSET/FETCH 为什么报错?
数据阿明
直接去掉 SELECT 外层的括号
可以直接使用 INSERT ... SELECT ... ORDER BY ... OFFSET ... FETCH,去掉 SELECT 外层的括号即可:
DECLARE @company_ids TABLE(id BIGINT);
INSERT INTO @company_ids (id)
SELECT ca.company_id
FROM company_account AS ca
ORDER BY ca.id DESC
OFFSET 0 ROWS
FETCH NEXT 500000 ROWS ONLY;
这条语句按 ca.id DESC 选择最多 500000 行,并将这些行的 company_id 插入 @company_ids。
为什么加括号后会报错?
INSERT INTO @company_ids (id) 后面可以直接接一条 SELECT 作为数据来源,无需用括号包住整个查询。
原写法中的括号使内部查询进入了不同的语法解析上下文。带有 ORDER BY 和 OFFSET/FETCH 的内容在该位置无法按预期解析,因此出现 ORDER 附近的语法错误。后面的 FETCH NEXT 错误可能是前面解析失败引发的连带报错。
OFFSET/FETCH 并非一概不能用于子查询,但当前需求无需构造子查询,直接使用上面的 INSERT ... SELECT 即可。
OFFSET 为 0 时,也可以使用 TOP
如果始终从第一行开始取,TOP (500000) 可以表达相同的取数需求,但必须保留排序条件:
DECLARE @company_ids TABLE(id BIGINT);
INSERT INTO @company_ids (id)
SELECT TOP (500000) ca.company_id
FROM company_account AS ca
ORDER BY ca.id DESC;
原问题中能够执行的 TOP 示例没有 ORDER BY,因此无法保证取得的是按 ca.id 降序排列后的前 500000 行。
如果以后需要跳过一定数量的行,再获取下一批数据,继续使用 OFFSET/FETCH 更直接。
复用这些 ID 时需要注意什么?
DECLARE @company_ids TABLE(...)声明的是表变量。如果需要临时表,应使用#company_ids等临时表名称及相应的建表语句。- 插入时的
ORDER BY用于决定选中哪些行,不保证后续读取@company_ids时的返回顺序。后续查询需要特定顺序时,仍须显式写出ORDER BY。 - 查询限制的是源数据行数。如果
company_account中存在重复的company_id,表变量中也可能保存重复值;这里没有执行去重。 - 如果
ca.id不是唯一值,排序边界处可能存在并列行。需要每次稳定选出同一批数据时,应在ORDER BY中追加实际存在且能够打破并列的唯一排序列。
备注:内容仅供参考。
