仅使用 LIKE 运算符记录大于纪元时间戳的记录

Eli*_*298 5 sql-server json sql-server-2014 like date-math

到目前为止,我有以下查询,不幸的是,我无法使用正则表达式大于运算符,我只能使用LIKE关键字。

整个列都在 json 字符串中,我无法使用json_value或 regexp,因为我在 SQL Server 上,所以我只能使用LIKE. 它是 SQL Server 2014,json_value直到 2016 年才受支持。

SELECT * FROM DataTableOne 
WHERE update_date LIKE '%1645290000%'
Run Code Online (Sandbox Code Playgroud)

我想仅使用 SQL 关键字检索纪元 unix 时间戳大于 1645290000 的所有记录LIKE(甚至使用 SQLLIKE运算符在 1645290000 和 9999999999 之间)。

任何帮助将不胜感激,因为这是一个非常困难的独特案例,我只能使用关键字LIKE

下面的示例表/数据:

CREATE TABLE DataTableOne (
    ID int,
    DATA varchar(MAX)
);

INSERT INTO DataTableOne (ID, DATA)
VALUES (1, '{"name":"Cole", "update_date":"2855290000"}'),
(2, '{"name":"Peter", "update_date":"1222290000"}') ;
Run Code Online (Sandbox Code Playgroud)

此类数据可能有一千行,而我只需要 update_date 大于 1645290000 的行。

在我给出的上表上运行查询应该只返回第一行,因为 update_date 2855290000在数字上确实大于 1645290000。

Len*_*art 9

我认为最好将问题分成两部分,找到 update_date 然后使用“>”进行过滤:

select * from DataTableOne
where cast ( substring( data
           , charindex('"update_date":', data)+15
           , len(data)- (charindex('"update_date":', data)+15) -1 )
      as bigint ) > 1645290000
Run Code Online (Sandbox Code Playgroud)

请注意,如果表中存在格式错误的 JSON,查询将会失败。如果是这种情况,您可能希望将提取封装在具有错误处理功能的函数/过程中。

小提琴

或者,由于TRY_CAST在 SQL Server 2014 中实现,如果转换失败,将返回 null ,这永远不会满足>,所以我们可以简单地执行以下操作:

select * from DataTableOne
where TRY_CAST ( substring( data
           , charindex('"update_date":', data)+15
           , len(data)- (charindex('"update_date":', data)+15) -1 )
         as bigint ) > 1645290000;
Run Code Online (Sandbox Code Playgroud)

更新了小提琴


Pau*_*ite 8

实际上,如果没有显式 JSON 支持,您不应该在 SQL Server 版本中直接处理 JSON 数据。理想情况下,JSON 源会在导入过程中转换为关系格式。查询数据就变得很容易。

也就是说,如果您确实必须按照您所说的去做,那么有很多选择。

一种是将(简单的)JSON 转换为 XML,然后使用 XQuery:

SELECT
    DTO.*
FROM dbo.DataTableOne AS DTO
CROSS APPLY 
(
    SELECT 
        TRY_CONVERT(xml,
            REPLACE(
                REPLACE(
                    REPLACE(
                        REPLACE(DTO.[DATA], 
                            '"name":', 'name='),
                        ', "update_date":', ' update_date='),
                    '{', '<r '),
                '}', '/>'))
) AS X (x)
WHERE
    1 = X.x.exist('r[1][@update_date ge 1645290000]');
Run Code Online (Sandbox Code Playgroud)

那里没有必要,但在每行[1]只有一个update_date 的情况下会产生一个稍微好一点的执行计划。

它也几乎可以LIKE专门使用,但我不推荐它:

SELECT * 
FROM dbo.DataTableOne AS DTO
WHERE 
    DTO.[DATA] COLLATE Latin1_General_BIN2 
        LIKE '%"update_date":"164529[0-9][0-9][0-9][0-9]"%'
    OR DTO.[DATA] COLLATE Latin1_General_BIN2 
        LIKE '%"update_date":"1645[3-9][0-9][0-9][0-9][0-9][0-9]"%'
    OR DTO.[DATA] COLLATE Latin1_General_BIN2 
        LIKE '%"update_date":"164[6-9][0-9][0-9][0-9][0-9][0-9][0-9]"%'
    OR DTO.[DATA] COLLATE Latin1_General_BIN2 
        LIKE '%"update_date":"16[5-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]"%'
    OR DTO.[DATA] COLLATE Latin1_General_BIN2 
        LIKE '%"update_date":"1[7-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]"%'
    OR DTO.[DATA] COLLATE Latin1_General_BIN2 
        LIKE '%"update_date":"[2-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]"%';
Run Code Online (Sandbox Code Playgroud)

db<>fiddle在线演示

如果您理解LIKE其中的逻辑,您将能够将其推广到其他值。如果您想解决难题或提出某种类型的问题,这应该可以帮助您入门。