AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 239180
Accepted
Michael Green
Michael Green
Asked: 2019-05-28 22:57:18 +0800 CST2019-05-28 22:57:18 +0800 CST 2019-05-28 22:57:18 +0800 CST

从 JSON 中查找祖先

  • 772

我有一个看起来像这样的层次结构:

在此处输入图像描述

作为 TSQL 中的 JSON,它是这样的:

declare @Employees nvarchar(max) =
'{
  "person": "Amy",
  "staff": [
    { "person": "Bill" },
    {
      "person": "Chris",
      "staff": [
        { "person": "Dan" },
        { "person": "Emma" }
      ]
    }
  ]
}';

这只是一个例子。实际数据可以是任何深度或宽度不确定的树。

我发现的文档和所有示例都显示了自上而下的遍历。每个 JSON 路径都从根节点开始,并通过已知节点名称导航到所需节点。我没有发现从层次结构中的不确定深度开始向上工作。我觉得我需要像传递闭包这样的东西。

给定一个名字,我想得到这个名字的祖先。例如,给定“Emma”,结果将是“Emma / Chris / Amy”。给定“Bill”,答案将是“Bill / Amy”。输出格式不重要;它可以是 JSON、字符串或结果集。名字是独一无二的。

这是我自己的学习练习。可以将原始 JSON 表示更改为任何等效的表示,只要它仍然是 JSONy。在层次结构的邻接列表表示上的 JSON_QUERY 不会达到我的目标。

sql-server t-sql
  • 2 2 个回答
  • 362 Views

2 个回答

  • Voted
  1. Best Answer
    Peter Vandivier
    2019-05-29T04:19:10+08:002019-05-29T04:19:10+08:00

    在我看来,这似乎是一个非常普通的递归查询,只要您动态地解开 JSON。

    db<>fiddle
    以前,更简单的 db<>fiddle

    declare @json nvarchar(max) =
    '{
      "person": "Amy",
      "staff": [
        { "person": "Bill" },
        {
          "person": "Chris",
          "staff": [
            { "person": "Dan" },
            { "person": "Emma" }
          ]
        }
      ]
    }';
    
    with level_0 as (
        select
            convert(int,0) as [Level],
            convert(nvarchar(4000),N'$') as [Key],
            @json as [Value],
            convert(
                int,
                case left(@json,1)
                    when N'[' then 4
                    when N'{' then 5
                    else 0
                end
            ) as [Type]
    )
    , key_value_unwrap as(
        select 
            l0.[Level] + 1 as [Level],
            convert(nvarchar(max),null) as Parent,
            l0.[Key] + iif(l0.[Type] = 5, '.' + oj.[Key], quotename(-1 + row_number() over (order by (select null)))) collate database_default as [Key],
            oj.[Value],
            oj.[Type]
        from level_0 l0
        outer apply openjson(l0.[Value]) as oj
        where l0.[Value] is not null 
        union all
        select 
            kvu.[Level] + 1 as [Level],
            convert(nvarchar(max),kvu.[Key]) as Parent,
            kvu.[Key] + iif(kvu.[Type] = 5, '.' + oj.[Key], quotename(-1 + row_number() over (order by (select null)))) as [Key],
            oj.[Value],
            oj.[Type]
        from key_value_unwrap as kvu
        outer apply openjson(kvu.[Value], 'lax $') as oj
        where kvu.[Type] in (4,5)
    ), _union as (
        select 
            l0.[Level],
            convert(nvarchar(max),null) as Parent,
            l0.[Key] + N'.' as [Key],
            l0.[Value],
            l0.[Type]
        from level_0 as l0
        union all
        select 
            kvu.[Level],
            kvu.Parent,
            kvu.[Key],
            kvu.[Value],
            kvu.[Type]
        from key_value_unwrap as kvu
    ) 
    select 
        u.[Level],
        iif(u.[Level]=1,N'$.',u.Parent) as Parent,
        u.[Key],
        u.[Value],
        u.[Type]
    from _union as u
    where u.[Type] not in (4,5);
    

    内联或捆绑到函数中运行,您可以解析出每个节点的 JSON 路径以及相应的父路径。

    select * 
    from dbo.json_shred(@Employees)
    where [Type] not in (4,5);
    
    等级 家长 钥匙 价值 类型
    1 美元。 $.person 艾米 1
    3 $.员工[1] $.staff[1].person 克里斯 1
    5 $.staff[1].staff[1] $.staff[1].staff[1].person 艾玛 1
    5 $.staff[1].staff[0] $.staff[1].staff[0].person 担 1
    3 $.staff[0] $.staff[0].person 账单 1
    • 7
  2. HandyD
    2019-05-29T00:09:28+08:002019-05-29T00:09:28+08:00

    您可以使用OPENJSON和 CTE 来提取每个人及其相关人员:

    declare @Employees nvarchar(max) =
    '{
      "person": "Amy",
      "staff": [
        { "person": "Bill" },
        {
          "person": "Chris",
          "staff": [
            { "person": "Dan" },
            { "person": "Emma" }
          ]
        }
      ]
    }';
    
    ;WITH Level1 AS (
        SELECT 1 AS Level, NULL AS Parent, l1.person, l1.staff
        FROM OPENJSON(@Employees)
        WITH
        (
            person NVARCHAR(255),
            staff NVARCHAR(MAX) AS JSON
        ) l1
    ), Level2 AS (
        SELECT 2 AS Level, l1.person AS Parent, l2.person, l2.staff
        FROM Level1 l1
        CROSS APPLY OPENJSON(l1.staff)
        WITH
        (
            person NVARCHAR(255),
            staff NVARCHAR(MAX) AS JSON
        ) l2
    ), Level3 AS (
        SELECT 3 AS Level, l2.person AS Parent, l3.person, l3.staff
        FROM Level2 l2
        CROSS APPLY OPENJSON(l2.staff)
        WITH
        (
            person NVARCHAR(255),
            staff NVARCHAR(MAX) AS JSON
        ) l3
    )
    
    SELECT Level, Parent, Person FROM Level1
    UNION
    SELECT Level, Parent, Person FROM Level2
    UNION
    SELECT Level, Parent, Person FROM Level3
    ORDER BY Level
    

    回报:

    Level   Parent  Person
    ----------------------
    1       NULL    Amy
    2       Amy     Bill
    2       Amy     Chris
    3       Chris   Emma
    3       Chris   Dan
    
    • 3

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve