limite condicional em MySQL Query possível?
-
10-07-2019 - |
Pergunta
i sou confrontado com uma decicion sobre manipulação de comentários de rosca em nosso projeto ... Eu tenho uma tabela MySQL simples que detém todos os comentários. Existem dois tipos: os pais e da criança. Childs representam uma resposta a um pai ou outra criança.
Meu problema:
-Comment (profundidade 0)
- Responder Criança (profundidade 1)
--- Responder a criança anterior (profundidade 2)
-Comment (profundidade 0)
Imagine a estrutura acima e uma consulta MySQL com LIMIT 2. Seria cortado da última resposta (profundidade 2). Na verdade eu gostaria de dizer algo como: tentar limitar a 2, se a criança deixou ir até o próximo pai. Tentou várias consultas sem sorte ...
O que eu tenho agora é como se segue:
SELECIONAR
SQL_CALC_FOUND_ROWS
*
DE
comentários
ONDE
comment_post_ID = '{$ _REQUEST [ "ID"]}'
ORDENAR POR
comment_id, COMMENT_DATE
DESC LIMIT 10"
Os campos da tabela importantes são:
comment_id (índice) | comment_parent_id (contém comment_id de pai ou NULL) | COMMENT_DATE
Eu ficaria muito grato por todas as idéias !!!
Saludos, Booosh
Solução
MySQL não tem quaisquer funções para analisar árvore-como estruturas. No cenário mais simples (criança tem um ID do pai), você precisará recurse através de programação para a árvore para localizar todos os sub-nós de um determinado nó. MaxLevel indica a profundidade que você quer ir para. Ele diminui a cada chamada recursiva para que no final você acaba com 0, que pára a recursão.
por exemplo. (Pseudo-código)
findNodes(String parentId, int maxLevel)
{
select * from posts where parent = parentId
foreach (result...)
{
if (maxLevel > 0)
{
findNodes(result.nodeId, maxLevel - 1)
}
doSomethingWIthAResult
}
}
Para fazer isso de uma forma mais concisa, há uma série de técnicas, todas as quais envolvem algum tipo de campo de índice que contém caminho para o posto atual. O caminho pode ser algo como isto: TopNode: Child1: Criança2: Filho3 ... Em que você poderia fazer uma escolha como essa Selecione * de mensagens em que caminho como "TopNode%" e profundidade = 2.
Outras dicas
Sempre penso sobre a pergunta que você realmente quer pedir ao banco de dados e então traduzir isso em SQL - neste caso você quer "uma lista de todos os comentários de alto nível com os seus filhos imediatos, se houver ".
por exemplo. (Simplificado)
SELECT * FROM comments c1
LEFT JOIN comments c2 ON c2.parent_comment_id=c1.comment_id
WHERE c1.parent_comment_id IS NULL
ORDER BY c1.comment_date, c1.comment_id, c2.comment_date, c2.comment_id;
Com esse resultado, você pode escrevê-los na ordem certa - se c2.comment_id é nulo, é um comentário de nível superior sem filhos, e se c1.comment_id é repetido, é uma outra criança do mesmo comentário.
fui confrontado com este mesmo problema, só que eu estava indo apenas uma profundidade de profundidade.
--Comment (depth: 0)
---Reply (depth: 1)
Eu consegui usar uma única consulta para selecionar todos esses registros, enquanto limita os registros Comment
nível superior para apenas 10.
SELECT c.* FROM comments AS c WHERE c.OwnerId = 1 AND c.ParentId = 0 LIMIT 10
UNION
SELECT cc.* FROM comments AS cc
INNER JOIN
(
SELECT CommentId FROM comments WHERE OwnerId = 1 AND ParentId = 0 LIMIT 10
)
AS c2
ON cc.ParentId = c2.CommentId
Esta consulta faz basicamente o seguinte:
- Obtém os 10 primeiros registros que são comentários de alto nível, e têm um específica id proprietário.
- Obtém todos os comentários que têm um ID de pai igual ao comentário id que foi devolvido pela primeira consulta, e os sindicatos los para o conjunto de resultados.
Embora, eu acho que essa consulta seria mais eficiente do que fazer várias chamadas para o banco de dados para cada registro, ele ainda tem a falha que ele executa a primeira consulta duas vezes. Uma vez antes da união, e um na juntar-se à União.
Ele parece ser bastante rápido, mas não tão rápido como eu gostaria. No entanto, se seu banco de dados é remoto, e latência é um problema, esta solução pode servi-lo melhor do que fazer várias consultas remotas ao banco de dados.
Eu finalmente consegui-lo com base em Greg Adamskis dica ... Então não vote a minha resposta, mas verificar a sua única !!!
Para descrever o problema em curto ... Precisamos de uma paginação para uma lista de comentários em nosso site. Usando um limite padrão pode causar que alguns comentários não seria mostrado ... O que precisávamos era um limite que só afetou nossas nós pais não os gânglios cild que são respostas ... É uma longa história ... No entanto talvez uma vez este iis útil para alguém:
function getComments($comment_parent_id, $scope,&$comments, $db)
{
$res = $db->select("SELECT * FROM comments WHERE comment_post_id = '{$_REQUEST["ID"]}' AND comment_parent_id = '{$comment_parent_id}' ORDER BY comment_date DESC LIMIT {$scope}");
while ($row = mysql_fetch_array($res, MYSQL_ASSOC))
{
$i = count($comments)+1;
foreach ($row as $k => $v) {
$comments[$i][$k] = $v;
}
//LOOK FOR REPLIES (childs of parent)
if (mysql_num_rows($db->select("SELECT * FROM comments WHERE comment_parent_id = '{$row['comment_id']}' LIMIT 1")) != 0 ){
getComments($row['comment_id'],100,$comments,$db);
}
}
}
//ARGUMENTS: parent_id (always starting with zero), scope, array holding comments, db class
getComments(0,5,$comments,$db);