将JSON数据导入SQL Server时指定列返回Null如何解决
问题原因
你出现空值的核心原因有两点:
- 你的JSON字段为嵌套结构,
OPENJSON的WITH子句默认仅读取根级字段,你没有指定嵌套层级的访问路径 - 你原有
WITH子句里出现了重复的date字段名,没有对应映射_id.$oid、createdDate.$date、lastLogin.$date这几个嵌套字段,同时$date存储的是Unix毫秒级时间戳,需要额外做类型转换才能得到标准 datetime 格式
修复后的代码
你可以直接调整OPENJSON的WITH子句,给嵌套字段指定JSON路径,同时处理时间戳转换即可:
SELECT users.oid, users.state, users.role, users.signUpSource, users.active, -- 转换Unix毫秒时间戳为SQL Server标准datetime类型 DATEADD(MILLISECOND, createdDateTimestamp % 1000, DATEADD(SECOND, createdDateTimestamp / 1000, '19700101')) AS createdDate, DATEADD(MILLISECOND, lastLoginTimestamp % 1000, DATEADD(SECOND, lastLoginTimestamp / 1000, '19700101')) AS lastLogin FROM OPENROWSET ( BULK 'C:\Users\shahk\OneDrive\Desktop\FetchAssgn\users.json', FORMATFILE= 'C:\Users\shahk\OneDrive\Desktop\FetchAssgn\csv.fmt', CODEPAGE = '65001' -- 如果你的JSON文件为UTF-8编码,添加该参数避免乱码 ) AS [Json] CROSS APPLY OPENJSON (json) WITH ( oid varchar(50) '$."_id"."$oid"', -- 明确指定嵌套路径获取oid值 state varchar(5) '$.state', createdDateTimestamp BIGINT '$.createdDate."$date"', -- 先读取数字类型的创建时间戳 lastLoginTimestamp BIGINT '$.lastLogin."$date"', -- 先读取数字类型的最后登录时间戳 role varchar(10) '$.role', signUpSource varchar(10) '$.signUpSource', active bit '$.active' -- 布尔类型直接映射为bit类型更合理 ) AS users
额外注意事项
- 如果你的JSON文件是每行一个独立JSON对象(即你提供的扩展样例格式),需要确保你的fmt格式文件配置为按行读取,也可以给
OPENROWSET添加SINGLE_CLOB参数一次性读取整个文件再拆分处理 - 以上时间戳转换逻辑兼容SQL Server 2016及以上所有版本,无需额外自定义函数
- 字段名包含
$这类特殊符号时,JSON路径中需要用双引号包裹避免解析错误
内容的提问来源于stack exchange,提问作者user16669095
相关产品推荐
相关产品推荐

