oracle 是否可以通过查询来查找给定日期的所有JSON类型的记录?

jum4pzuy  于 2023-05-06  发布在  Oracle
关注(0)|答案(2)|浏览(164)

在过去的某个时候,数据列值(CLOB)从CSV切换到JSON。没有文件说明这是何时发生的。
我不能在select上执行orderby,因为记录可能会被更新,值会被JSON替换。因此,最早的记录可能出现在该日期,但如果我搜索当天的所有记录,我可以看到当天的CSV和JSON数据的混合。
有没有一种方法可以在SQL中找到所有记录都是JSON的那一天,因为这很可能是发生切换的日期?或者搜索CONTENT中的所有数据都是JSON类型的日期范围?
例如DB列和虚拟数据

DATE_CREATED | DATE_UPDATED | CONTENT
01-APR-12      01-APR-12      <XML STUFF>
01-APR-12      01-APR-12      <XML STUFF>
01-APR-12      21-JUN-20      {JSON STUFF}
05-APR-12      05-APR-12      <XML STUFF>
01-APR-14      08-MAR-20      {JSON STUFF}
01-APR-16      21-JUN-21      <XML STUFF>
01-APR-14      11-SEP-22      {JSON STUFF}
01-APR-14      01-JAN-21      {JSON STUFF}
01-APR-17      21-JUN-19      <XML STUFF>
11-FEB-23      11-FEB-20      {JSON STUFF}
11-FEB-23      11-FEB-20      {JSON STUFF}
11-FEB-23      11-FEB-20      {JSON STUFF}

当CONTENT的所有数据都是JSON时,我需要一种方法来查询数据库以找到DATE_CREATED
输出:

DATE_CREATED | DATE_UPDATED | CONTENT
11-FEB-23      11-FEB-20      {JSON STUFF}
11-FEB-23      11-FEB-20      {JSON STUFF}
11-FEB-23      11-FEB-20      {JSON STUFF}
lf3rwulv

lf3rwulv1#

可以使用IS JSON操作符:

SELECT *
FROM   table_name
WHERE  content IS JSON;

如果不支持,则可以创建一个用户定义函数,通过尝试解析CONTENT值并捕获任何异常来检查CONTENT值是否是有效的JSON:

CREATE FUNCTION is_json(value IN CLOB) RETURN NUMBER
  IS
    json JSON_ELEMENT_T;
  BEGIN
    json := JSON_ELEMENT_T.parse(value);
    RETURN 1;
  EXCEPTION
    WHEN OTHERS THEN
      RETURN 0;
  END;
/

然后用途:

SELECT *
FROM   table_name
WHERE  is_json(content) = 1;
  • 注意:在Oracle的后续版本中,您可以在子查询因式分解子句中声明函数;但是,在这些版本中可能会支持IS JSON。*

其中,对于样本数据:

create table table_name(date_created DATE, content CLOB);

INSERT INTO table_name(date_created, content)
  SELECT DATE '2023-01-01', 'abcde'   FROM DUAL UNION ALL
  SELECT DATE '2023-01-02', '{}'      FROM DUAL UNION ALL
  SELECT DATE '2023-01-03', 'xyz{}'   FROM DUAL UNION ALL
  SELECT DATE '2023-01-04', '["abc"]' FROM DUAL UNION ALL
  SELECT DATE '2023-01-05', '{}'      FROM DUAL;

输出:
| 创建日期|联系我们|
| --------------|--------------|
| 2019 -01- 22 00:00:00|我的天|
| 2019 -01- 14 00:00:00|[“abc”]|
| 2019 -01-05 00:00:00|我的天|
如果你想获取最早的一行,并且这一行和之后创建的所有行都是有效的JSON,那么你可以使用MATCH_RECOGNIZE进行模式匹配:

SELECT *
FROM   table_name
MATCH_RECOGNIZE(
  ORDER BY date_created
  ALL ROWS PER MATCH
  PATTERN ( valid_json {- valid_json* -} $ )
  DEFINE valid_json AS content IS JSON
)

其中,输出:
| 创建日期|联系我们|
| --------------|--------------|
| 2019 -01- 14 00:00:00|[“abc”]|
如果你想包含date_updated,那么取消日期列的透视,并使用相同的技术。
fiddle

更新:

如果你想要第一个日期,在这一整天和以后的所有日子里,content都是有效的JSON,那么只需使用上一个查询并检查第一个匹配的行是否在上一行的后面一天:

SELECT *
FROM   table_name
MATCH_RECOGNIZE(
  ORDER BY date_created
  ALL ROWS PER MATCH
  PATTERN ( first_valid_json {- valid_json* -} $ )
  DEFINE
    first_valid_json AS  content IS JSON
                     AND (  PREV(date_created) IS NULL
                         OR PREV(date_created) < TRUNC(date_created) ),
    valid_json       AS content IS JSON
);

fiddle

mo49yndu

mo49yndu2#

问题的文本与提供的样本数据相结合,结果有点令人困惑。示例数据中有一些行在创建之前已更新,但如果您需要:
quote:“I need a way to query the database to find the DATE_CREATED when all data for the CONTENT was JSON”然后你可以使用Not Exists来做选择,尽管结果与你预期的结果有点不同。

WITH          -- Sample data
    tbl (DATE_CREATED, DATE_UPDATED, CONTENT) AS
    (   Select To_Date('01-APR-12', 'dd-MON-yy'), To_Date('01-APR-12', 'dd-MON-yy'), '<XML STUFF>'  From Dual Union All
        Select To_Date('01-APR-12', 'dd-MON-yy'), To_Date('01-APR-12', 'dd-MON-yy'), '<XML STUFF>'  From Dual Union All
        Select To_Date('01-APR-12', 'dd-MON-yy'), To_Date('21-JUN-20', 'dd-MON-yy'), '{JSON STUFF}' From Dual Union All
        Select To_Date('05-APR-12', 'dd-MON-yy'), To_Date('05-APR-12', 'dd-MON-yy'), '<XML STUFF>'  From Dual Union All
        Select To_Date('01-APR-14', 'dd-MON-yy'), To_Date('08-MAR-20', 'dd-MON-yy'), '{JSON STUFF}' From Dual Union All
        Select To_Date('01-APR-16', 'dd-MON-yy'), To_Date('21-JUN-21', 'dd-MON-yy'), '<XML STUFF>'  From Dual Union All
        Select To_Date('01-APR-14', 'dd-MON-yy'), To_Date('11-SEP-22', 'dd-MON-yy'), '{JSON STUFF}' From Dual Union All
        Select To_Date('01-APR-14', 'dd-MON-yy'), To_Date('01-JAN-21', 'dd-MON-yy'), '{JSON STUFF}' From Dual Union All
        Select To_Date('01-APR-17', 'dd-MON-yy'), To_Date('21-JUN-19', 'dd-MON-yy'), '<XML STUFF>'  From Dual Union All
        Select To_Date('11-FEB-20', 'dd-MON-yy'), To_Date('11-FEB-23', 'dd-MON-yy'), '{JSON STUFF}' From Dual Union All
        Select To_Date('11-FEB-20', 'dd-MON-yy'), To_Date('11-FEB-23', 'dd-MON-yy'), '{JSON STUFF}' From Dual Union All
        Select To_Date('11-FEB-20', 'dd-MON-yy'), To_Date('11-FEB-23', 'dd-MON-yy'), '{JSON STUFF}' From Dual 
        )
--  
--   Main SQL
Select  t.DATE_CREATED, t.DATE_UPDATED, t.CONTENT
From    tbl t
Where   SubStr(t.CONTENT, 1, 1) || SubStr(CONTENT, -1) = '{}' And 
        Not Exists (Select 1 From tbl 
                    Where DATE_CREATED = t.DATE_CREATED And SubStr(t.CONTENT, 1, 1) || SubStr(CONTENT, -1) !=  '{}')
--
--  R e s u l t :
DATE_CREATED DATE_UPDATED CONTENT     
------------ ------------ ------------
11-FEB-23    11-FEB-20    {JSON STUFF}
11-FEB-23    11-FEB-20    {JSON STUFF}
11-FEB-23    11-FEB-20    {JSON STUFF}
01-APR-14    01-JAN-21    {JSON STUFF}
01-APR-14    11-SEP-22    {JSON STUFF}
01-APR-14    08-MAR-20    {JSON STUFF}

注意:表达式SubStr(t.CONTENT,1,1)||SubStr(CONTENT,-1)= '{}'不会测试内容是否正确的JSON-如果您也需要检查,那么您应该使用其他方法,具体取决于您正在使用的Oracle版本。

相关问题