AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 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

Encontrar ancestralidade de JSON

  • 772

Eu tenho uma hierarquia que se parece com isso:

insira a descrição da imagem aqui

Como JSON no TSQL é isso:

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

Este é apenas um exemplo. Os dados reais podem ser qualquer árvore de profundidade ou amplitude indeterminada.

A documentação e todos os exemplos que encontrei mostram a travessia de cima para baixo . Cada caminho JSON começa no nó raiz e navega, por nomes de nós conhecidos, em direção ao nó desejado. Não encontrei nada sobre começar em uma profundidade indeterminada dentro da hierarquia e trabalhar para cima. Sinto que preciso de algo como fechamento transitivo .

Dado um nome, gostaria de obter a ascendência para esse nome. Por exemplo, dado "Emma" o resultado será "Emma / Chris / Amy". Dado "Bill" a resposta será "Bill/Amy". O formato de saída não é importante; pode ser JSON, uma string ou um conjunto de resultados. Os nomes são únicos.

Este é um exercício de aprendizagem para mim. Não há problema em alterar a representação JSON original para algo equivalente, desde que ainda seja JSONy. Um JSON_QUERY sobre uma representação de lista de adjacências da hierarquia não atingiria meu objetivo.

sql-server t-sql
  • 2 2 respostas
  • 362 Views

2 respostas

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

    Isso me parece ser uma consulta de recursão bastante simples, desde que você desembrulhe o JSON dinamicamente.

    db<>fiddle
    anterior, db mais simples<>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);
    

    Executar em linha ou agrupado em uma função , você pode analisar o caminho JSON para cada nó com um caminho pai correspondente.

    select * 
    from dbo.json_shred(@Employees)
    where [Type] not in (4,5);
    
    Nível Pai Chave Valor Modelo
    1 $. $.pessoa Amy 1
    3 $.staff[1] $.staff[1].person Chris 1
    5 $.staff[1].staff[1] $.staff[1].staff[1].person Emma 1
    5 $.staff[1].staff[0] $.staff[1].staff[0].person Dan 1
    3 $.staff[0] $.staff[0].person Conta 1
    • 7
  2. HandyD
    2019-05-29T00:09:28+08:002019-05-29T00:09:28+08:00

    Você pode usar OPENJSON e um CTE para extrair cada pessoa e sua equipe associada:

    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
    

    Devoluções:

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

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

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

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve