将保存为 varchar 的日期与 DateTime 进行比较
Compare Date saved as varchar with DateTime
我有一个 table,其列 jsonStr
类型为 varchar
。
这是此列中元素的示例
{"Date":"/Date(1602846000000)/","person":"Laura"}
我想将此日期与静态日期进行比较。这是我的查询:
select *
from mytable
where json_value(jsonStr, '$.Date') >= '2020-10-01T00:00:00'
我希望显示一个元素但没有结果所以我如何转换这个日期以将其与 DateTime 进行比较
我尝试使用子字符串删除 /Date 和 /,然后转换/解析结果 1602846000000 但没有结果
提取的 unixtime 值可能会通过使用
转换为日期时间格式
DATEADD(S, CONVERT(int,LEFT(1602846000000, 10)), '1970-01-01')
如:
WITH t AS
(
SELECT *, JSON_VALUE(jsonStr, '$.Date') AS str
FROM mytable
), t2 AS
(
SELECT t.*,
SUBSTRING(str, PATINDEX('%[0-9]%', str), PATINDEX('%[0-9][^0-9]%', str + 't')
- PATINDEX('%[0-9]%', str) + 1) AS nr
FROM t
)
SELECT t2.jsonStr
FROM t2
WHERE DATEADD(S, CONVERT(int,LEFT(nr, 10)), '1970-01-01') >= '2020-10-01T00:00:00'
我会尽可能扭转这一局面。您为此比较所做的每一点工作都必须针对 table 中的每一行完成,因为在我们完成工作之前我们不知道哪些行将匹配。我们对常量值(而不是所有存储值)做的越多,查询的效率就越高。
从 JSON 中解析日期在数据库中是非常昂贵的。我们不能完全摆脱这项工作,但我们至少可以在包含在 SQL 之前将初始日期字符串转换为 unix 时间格式。所以这个:
'2020-10-01T00:00:00'
变成这样:
1601510400
现在您可以进行一些更简单的字符串操作并比较数字,而无需将每一行的 unix 时间转换为日期值。
根据您拥有的 Sql 服务器版本,字符串操作的外观有很大差异。 Sql Server 2019 添加了一些 new native JSON support,这可以使这更容易。
但无论哪种方式,您最好花时间了解您正在存储的数据。即使保留原始 json 有意义,您也应该有一个至少支持其上的基本元数据的模式。使用索引与不使用索引之间的区别,可以使性能相差多个数量级。
例如,如前所述,此问题中的查询必须提取 table 中每一行的日期值...即使是不匹配的行。如果您构建一个架构,其中日期被标识为元数据并在初始插入期间提取,则索引可以让您只查找所需的行。如果此时您仍然需要从 JSON 条记录中提取值,至少它只是针对相关行。
我使用
解决了这个问题
DATEADD(SECOND, CONVERT(INT, Left(SUBSTRING(JSON_VALUE(jsonStr, '$.EndDate'), 7, 13), 10)), '19700101'
我有一个 table,其列 jsonStr
类型为 varchar
。
这是此列中元素的示例
{"Date":"/Date(1602846000000)/","person":"Laura"}
我想将此日期与静态日期进行比较。这是我的查询:
select *
from mytable
where json_value(jsonStr, '$.Date') >= '2020-10-01T00:00:00'
我希望显示一个元素但没有结果所以我如何转换这个日期以将其与 DateTime 进行比较
我尝试使用子字符串删除 /Date 和 /,然后转换/解析结果 1602846000000 但没有结果
提取的 unixtime 值可能会通过使用
转换为日期时间格式DATEADD(S, CONVERT(int,LEFT(1602846000000, 10)), '1970-01-01')
如:
WITH t AS
(
SELECT *, JSON_VALUE(jsonStr, '$.Date') AS str
FROM mytable
), t2 AS
(
SELECT t.*,
SUBSTRING(str, PATINDEX('%[0-9]%', str), PATINDEX('%[0-9][^0-9]%', str + 't')
- PATINDEX('%[0-9]%', str) + 1) AS nr
FROM t
)
SELECT t2.jsonStr
FROM t2
WHERE DATEADD(S, CONVERT(int,LEFT(nr, 10)), '1970-01-01') >= '2020-10-01T00:00:00'
我会尽可能扭转这一局面。您为此比较所做的每一点工作都必须针对 table 中的每一行完成,因为在我们完成工作之前我们不知道哪些行将匹配。我们对常量值(而不是所有存储值)做的越多,查询的效率就越高。
从 JSON 中解析日期在数据库中是非常昂贵的。我们不能完全摆脱这项工作,但我们至少可以在包含在 SQL 之前将初始日期字符串转换为 unix 时间格式。所以这个:
'2020-10-01T00:00:00'
变成这样:
1601510400
现在您可以进行一些更简单的字符串操作并比较数字,而无需将每一行的 unix 时间转换为日期值。
根据您拥有的 Sql 服务器版本,字符串操作的外观有很大差异。 Sql Server 2019 添加了一些 new native JSON support,这可以使这更容易。
但无论哪种方式,您最好花时间了解您正在存储的数据。即使保留原始 json 有意义,您也应该有一个至少支持其上的基本元数据的模式。使用索引与不使用索引之间的区别,可以使性能相差多个数量级。
例如,如前所述,此问题中的查询必须提取 table 中每一行的日期值...即使是不匹配的行。如果您构建一个架构,其中日期被标识为元数据并在初始插入期间提取,则索引可以让您只查找所需的行。如果此时您仍然需要从 JSON 条记录中提取值,至少它只是针对相关行。
我使用
解决了这个问题DATEADD(SECOND, CONVERT(INT, Left(SUBSTRING(JSON_VALUE(jsonStr, '$.EndDate'), 7, 13), 10)), '19700101'