SQL使用OFFSET/FETCH搭配GROUP BY拆分表导入报OFFSET语法错误如何解决
错误根因说明
OFFSET/FETCH语法强制要求搭配ORDER BY子句,缺失固定排序规则会直接触发OFFSET附近语法报错,还会导致分片数据重复/遗漏FETCH NEXT N ROWS ONLY中的N是本次分片要读取的行数,不是累计行数,原第二分片写@row_to_get*2会导致单次读取行数翻倍,分片逻辑完全错误- 原
@row_to_get变量计算逻辑错误:SELECT *返回的是多行结果集,不能直接做除法,必须用COUNT(*)取符合过滤条件的总行数
修正后的实现代码
步骤1:修正分片行数变量计算
declare @row_to_get int set @row_to_get = ( select COUNT(*) from [AAA].[tablename] where datepart(ss, [tempo]) = 0 and datepart(mi, [tempo]) % 3 = 0 and DateKey > @startDateKey_Extended ) / 4 -- 若总行数不能被4整除,可改成CEILING(COUNT(*)/4.0)避免最后一页漏数据
步骤2:修正分片查询逻辑
每个分片仅调整OFFSET参数即可,FETCH NEXT固定为单分片行数,必须加ORDER BY保证排序规则一致
- 第一分片
select [Id] ,[Datekey] ,[tempo] ,max(coalesce([othercolumn], 1)) as [othercolumn] from [AAA].[tablename] where datepart(ss, [tempo]) = 0 and datepart(mi, [tempo]) % 3 = 0 and DateKey > @startDateKey_Extended group by [Id] ,[Datekey] ,[tempo] ORDER BY [Id], [Datekey], [tempo] OFFSET 0 ROWS FETCH NEXT @row_to_get ROWS ONLY
- 第二分片
select [Id] ,[Datekey] ,[tempo] ,max(coalesce([othercolumn], 1)) as [othercolumn] from [AAA].[tablename] where datepart(ss, [tempo]) = 0 and datepart(mi, [tempo]) % 3 = 0 and DateKey > @startDateKey_Extended group by [Id] ,[Datekey] ,[tempo] ORDER BY [Id], [Datekey], [tempo] OFFSET @row_to_get ROWS FETCH NEXT @row_to_get ROWS ONLY
- 第三分片替换OFFSET为
@row_to_get*2,第四分片替换OFFSET为@row_to_get*3即可,第四分片也可以直接写FETCH NEXT 100 PERCENT ROWS ONLY避免剩余行数不足导致漏数
低版本SQL Server兼容方案
如果使用SQL Server 2008及更早版本(不支持OFFSET/FETCH语法),可以改用ROW_NUMBER()窗口函数实现,逻辑完全一致,同样不需要读取全表:
SELECT * FROM ( select [Id] ,[Datekey] ,[tempo] ,max(coalesce([othercolumn], 1)) as [othercolumn] ,ROW_NUMBER() OVER(ORDER BY [Id], [Datekey], [tempo]) AS rn from [AAA].[tablename] where datepart(ss, [tempo]) = 0 and datepart(mi, [tempo]) % 3 = 0 and DateKey > @startDateKey_Extended group by [Id] ,[Datekey] ,[tempo] ) t -- 第N分片的行号范围替换对应数值即可,比如第二片就是 BETWEEN @row_to_get+1 AND @row_to_get*2 WHERE rn BETWEEN 1 AND @row_to_get
内容的提问来源于stack exchange,提问作者Giuditta Davini
相关产品推荐
相关产品推荐

