Auto-junções recursivas


15

Eu tenho uma commentstabela, que pode ser simplificada para isso:

comments
=======
id
user_id
text
parent_id

onde parent_idé anulável, mas pode ser uma chave para seu comentário pai.


Agora, como posso selecttodos os descendentes de um comentário específico?
Os comentários podem estar vários níveis abaixo ...

Respostas:


16

Consultas hierárquicas , como essas consultas recursivas são conhecidas, não são suportadas pelo MySQL.

No entanto, eles são suportados no Oracle, Microsoft SQL Server, DB2 e PostgreSQL, entre outros.

Se você precisar de uma solução alternativa, poderá encontrar um truque dinâmico (e, portanto, potencialmente perigoso) aqui: /programming/8104187/mysql-hierarchical-queries

Você também pode encontrar uma discussão sobre como armazenar dados hierárquicos com outros modelos que não uma Lista de Adjacências (por exemplo, a coluna Pai ) aqui: /programming/192220/what-is-the-most-efficient- maneira elegante de analisar uma mesa plana em uma árvore /

Boa sorte!


Gostaria de saber como essa solução no seu segundo link pode ser perigosa. Você poderia explicar isso? Caso contrário, seja bem-vindo ao site!
Dezso

3
@dezso: O próprio criador da consulta, Quassnoi " * Não é seguro para atualização *, porque o MySQL não define claramente o comportamento da variável da sessão. No entanto, é a única maneira de lidar com listas de adjacências em tempo hábil na consulta ." Perigoso pode ter sido uma palavra muito forte ( potencialmente instável ?), Mas prefiro errar por precaução (além disso, tenho mais conhecimento em Oracle do que MySQL, por isso queria ser mais cauteloso). Obrigado pelo bem-vindo, a propósito! Há muito tempo que sou espreitador da rede SE e decidi que era hora de pagar um pouco.
Valmoer

2
A sintaxe WITH [RECURSIVE] agora é suportada no mysql 8.0. dev.mysql.com/doc/refman/8.0/en/with.html
ClearCrescendo

6

O design desta tabela é um "antipadrão" SQL antipadrão, conforme descrito por Bill Karwin (a partir do slide 48 em sua apresentação Strike Back do Antipatterns SQL ). O problema desse design especificamente é a dificuldade de obter todos os descendentes (ou pais) de um nó. Como você está usando o MySQL, não é possível usar expressões de tabela comuns (a instrução WITH e seu modificador RECURSIVE) presentes em outros RDBMSes.

O que resta é:

  • use uma implementação alternativa da estrutura hierárquica de dados (as respostas a esta pergunta podem ser uma boa referência)
  • crie consultas de associação automática com um limite de profundidade. Para profundidade = 5, você pode usar algo nas linhas de:

    SELECT *
    FROM comments AS c1
      JOIN comments AS c2 ON (c2.parent_id = c1.id)
      JOIN comments AS c3 ON (c3.parent_id = c2.id)
      JOIN comments AS c4 ON (c4.parent_id = c3.id)
      JOIN comments AS c5 ON (c5.parent_id = c4.id)
  • use um RDBMS que suporte WITH RECURSIVE (embora isso provavelmente não seja uma opção para a maioria das pessoas)


2
Eu discordo de Bill Karwin aqui. O modelo de adjacência não é um antipadrão. Com um DBMS moderno que suporta consultas recursivas (a Oracle suporta isso há mais de 20 anos), esse modelo é muito eficiente para recuperar e atualizar.
A_horse_with_no_name

5

O MySQL não suporta consultas recursivas como a que você precisa.

O que fiz um tempo atrás foi escrever Procedimentos armazenados que fornecem o modelo para isso.

Em vez de reinventar a roda, darei a você os links para meus posts anteriores sobre isso:

Resumindo, os Procedimentos armazenados que fiz para fazer o percurso da árvore de pré-encomenda usando o processamento da fila

  • GetParentIDByID
  • GetAncestry
  • GetFamilyTree

Pai de todos os filhos (como o procedimento armazenado GetFamilyTree)

  • PASSO01) Comece com a parent_idem uma fila
  • PASSO 02) Desfileirar o próximo parent_idcomo o atual
  • PASSO03) Coloque em fila todos os idvalores que possuem a correnteparent_id
  • PASSO04) Imprimir ou coletar o comentário
  • PASSO05) Se a fila não estiver vazia, vá para STEP02
  • PASSO 06) Você terminou !!!

Filho de todos os pais (como o GetAncestry Stored Procedure)

  • STEP01) Comece com um idem uma fila
  • PASSO 02) Desfileirar o próximo idcomo o atual
  • PASSO03) Coloque o parent_idvalor da corrente na filaid
  • PASSO04) Imprimir ou coletar o comentário
  • PASSO05) Se a fila não estiver vazia, vá para STEP02
  • PASSO 06) Você terminou !!!

Consulte os procedimentos armazenados em meus outros posts para ver a implementação.

De uma chance !!!


2
SELECT  group_concat(@id :=
        (
        SELECT  id
        FROM    comments
        WHERE   parent_id = @id
        )) AS comment
FROM    (
        SELECT  @id := 1
        ) vars
STRAIGHT_JOIN
        comments
WHERE   @id IS NOT NULL

violino

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.