使用Spark JDBC读取Azure SQL的LoadDate字段全为1900-01-01问题
问题描述
通过JDBC将Azure SQL数据库中的表读取到Databricks时,datetime类型的LoadDate字段返回值全为1900-01-01T00:00:00.000+0000。尝试在TSQL中创建视图转换该字段(比如用Year(f.LoadDate)提取年份),返回值却为0。其他同类型datetime字段可正常获取值,且LoadDate字段设置了MASKED WITH (FUNCTION = 'default()')。
相关代码
Databricks 读取代码
dbcHostName = "myserver.database.windows.net" jdbcPort = "1433" jdbcDatabase = "mydb" connectionProperties = { "user":"myuser", "password":"mypwd", "driver" : "com.microsoft.sqlserver.jdbc.SQLServerDriver" } jdbcUrl = "jdbc:sqlserver://{0}:{1};database={2}".format(jdbcHostName,jdbcPort,jdbcDatabase) pushdown_query = """( select top 100 * from dbo.vwExportTable ) t""" df = spark.read.jdbc(url=jdbcUrl, table=pushdown_query, properties=connectionProperties) display(df)
TSQL 视图定义
alter view vwExportTable as select f.LoadDate, f.*, Year(f.LoadDate) y from edw.Fact f where f.LoadDate > '2015-01-01' ;
表结构
CREATE TABLE [edw].[Fact]( [BookingId] [int] NOT NULL, ... [BookingStartDate] [datetime] NOT NULL, ... [LoadDate] [datetime] MASKED WITH (FUNCTION = 'default()') NOT NULL, ) ON [PRIMARY]
原因分析
- 掩码函数生效机制:
default()掩码函数针对datetime类型会返回该类型的默认值1900-01-01 00:00:00,这就是所有LoadDate返回值一致的原因。 - 过滤条件失效:视图中的
where f.LoadDate > '2015-01-01'是基于掩码后的值判断的,而掩码后的值都是1900-01-01,根本不满足过滤条件。但因为使用了top 100,数据库仍然返回了掩码后的默认值,Year()作用在该值上自然得到0。 - 其他字段正常的原因:其他datetime字段没有配置掩码,所以能返回真实数据。
解决方案
- 获取真实值:如果需要读取
LoadDate的真实数据,需给当前数据库用户授予UNMASK权限,执行以下SQL:GRANT UNMASK TO myuser; - 调整掩码规则:如果不能授予
UNMASK权限,可根据脱敏需求更换掩码函数,比如使用partial()保留部分日期信息:ALTER TABLE [edw].[Fact] ALTER COLUMN [LoadDate] MASKED WITH (FUNCTION = 'partial(1, "-", 10)'); - 修正过滤逻辑:如果不需要真实值但要正确过滤,需确保过滤逻辑作用在真实数据上,比如使用拥有
UNMASK权限的账号执行查询,或者在数据脱敏前完成过滤(如在数据库端用有权限的用户创建预处理视图)。
内容的提问来源于stack exchange,提问作者DejanS
相关产品推荐
相关产品推荐

