如何获取以多行值连接的 id 记录

Posted

技术标签:

【中文标题】如何获取以多行值连接的 id 记录【英文标题】:How can i get records of id those are connected in multiple row value 【发布时间】:2020-08-09 09:41:54 【问题描述】:

下面是我的桌子

Id      User_id     type               content       item_id    secondary_item_id
   879       1         activity_comment   Amazing       833        833
   907       168       activity_comment   Great         833        879    
   908       1         activity_comment   Welcome       833        907 

我想输出一个评论回复结构,可以用一个例子来描述。在上表中,您可以看到 user_id 1833 ( this is a post id ) 发表评论,然后 user 168 回复他为“很棒”,然后再次 user 1 重播给用户 168。

所以它可能像......

**MY POST** ( This is a post )

---- First comment( Amazing)
------- replay comment  (Great)
------------ sub replay (Welcome )

我已经编写了以下查询,但无法获得预期的输出。

SQL 查询:

<?php 
  $listReplay =$wpdb->get_results("(SELECT * FROM table_one WHERE id = ".$value['secondary_item_id']."  AND type ='activity_comment') UNION DISTINCT 
                            (SELECT * FROM table_one WHERE secondary_item_id = ".$value['secondary_item_id']." AND type ='activity_comment')");
?>

【问题讨论】:

你有item_idsecondary_item_id。我建议将其更新为parent_id 或正在讨论的主线程和replied_to_id,这将是正在回复的评论。最后,添加一个timestamp,它会让排序变得更好。至于获得该结构的 SQL,我会推动它以更轻松地对其进行编码,只需获取数据即可。 对于分层数据最好使用嵌套集模型。见phpro.org/tutorials/… 【参考方案1】:

让我们首先了解如何加载原始数据:

select Id, content, item_id, secondary_item_id
from table_one
where item_id = 833
order by item_id, secondary_item_id;

上面的查询加载了帖子 833 上的 cmets,并按帖子 ID 和父评论 ID 对它们进行排序。到目前为止,一切都很好。现在,假设您将原始数据存储在 $rawResults 中,您可以执行以下操作:

$map = [];
$parsedResults = [];
foreach ($rawResults as $rawResult) 
    if ($rawResult["secondary_item_id"] === $rawResult["item_id"]) 
        $parsedResults[$rawResult["Id"]] = [
            "content" => $rawResult["content"],
            "children" => []
        ];
        $map[$rawResult["Id"]] = $parsedResults[$rawResults["Id"]];
     else 
        $map[$rawResult["secondary_item_id"]]["children"][$rawResult["Id"]]= [
            "content" => $rawResult["content"],
            "children" => []
        ]
    

现在,您有一个元素层次结构,主要级别是主要 cmets,您可以在子项中找到答案。您现在可以像

一样遍历分层数组
function getComments($parsedResults, $prefix = "--- ") 
    $output = "";
    foreach ($parsedResults as $parsedResult) 
        $output .= $prefix.$parsedResult["content"]."\n";
        if (count($parsedResult["children"])) $output .= getComments($parsedResult["children"], "---".$prefix);
    
    return $output;

【讨论】:

【参考方案2】:

如果您运行的是 mysql 8.0,一个典型的方法是使用递归查询来遍历分层数据结构。这会通过单个查询产生所需的结果,因此这比在 php 中迭代更有效。

with recursive cte as (
    select t.*, 1 lvl
    from mytable t
    where 
        type ='activity_comment' 
        and item_id = 833 
        and secondary_item_id = item_id
    union all
    select t.*, c.lvl + 1
    from mytable t
    inner join cte c on c.id = t.secondary_item_id
    where t.type = 'activity_comment'
)
select * from cte order by lvl

递归查询的锚点选择帖子的“第一个”评论,即我们用条件secondary_item_id = item_id 识别。然后,递归部分只是跟随关系直到它们耗尽。

这为您提供了一个列出所有评论帖子的扁平结构,并带有一个名为 lvl 的附加列,指示每个元素的深度。您可以使用该信息来处理应用程序中的显示。

Demo on DB Fiddle

身份证 |用户ID |类型 |内容 | item_id | secondary_item_id |等级 --: | ------: | :--------------- | :-------- | ------: | ----------------: | --: 第879章1 |活动评论 |惊人的 |第833章第833章1 907 | 168 |活动评论 |很棒 |第833章第879章2 908 | 1 |活动评论 |欢迎 |第833章907 | 3

【讨论】:

没有得到结果,它显示了我在问题中提到的item_id 833的所有cmets没有得到结果,结果必须在层次注释结构中。 @SamirSheikh:SQL 查询按设计返回平面结构(行不能“嵌套”)。此查询以正确的顺序(从根到子)为您提供 cmets,并有一列指示每个节点的深度。这与 SQL 查询一样好。从这些结果开始,很容易使用 php 循环并使用 lvl 列将行显示为应用程序中的层次结构。而且,再次记住,使用单个查询比在 php 中迭代和运行多个查询要高效得多。 @PaulSpiegel:我明白你的意思。有解决方案 - 取决于 OP 想要什么。例如,我们可以跟踪每个评论的路径,并使用 if 进行排序。但是 OP 的示例数据没有显示这个用例,所以我没有实现。【参考方案3】:

您可以使用以下代码在 SQL 中获取输出。

WITH comment_activity(Id, User_id, type, content, post_id, secondary_item_id)
AS
(Select   879 ,     1     ,  'activity_comment' ,  'Amazing' ,      833     ,  833 UNION
Select   907 ,     168   ,  'activity_comment' ,  'Great'   ,      833     ,  879  UNION 
Select   908 ,     1     ,  'activity_comment' ,  'Welcome' ,      833     ,  907  
)

Select post_id as post,
ROW_NUMBER() OVER (PARTITION BY post_id ORDER BY ID) as RN, 
content as comment,
User_id,
CASE WHEN ROW_NUMBER() OVER (PARTITION BY post_id ORDER BY ID) = 1
     THEN 'First_Comment (' + content + ')'
     ELSE 'Reply_' + CONVERT(VARCHAR(20),ROW_NUMBER() OVER (PARTITION BY post_id ORDER BY ID) - 1) + '( ' + content + ')'
     END as Thread

from comment_activity
WHERE type = 'activity_comment'
AND post_id = 833

【讨论】:

【参考方案4】:

实际上,Lajos Arpad 的解决方案可以在数据库中进行一些更改。 您添加另一列 parent_item_id。这基本上是该链 cmets 的第一个评论。在您的示例中,所有 3 行都是 879。

现在这可以工作了

select * from <table name> 
where item_id = <item_id> 
group by parent_item_id 
order by secondary_item_id asc

【讨论】:

以上是关于如何获取以多行值连接的 id 记录的主要内容,如果未能解决你的问题,请参考以下文章

当多行满足要求时,如何通过连接在 PostgreSQL 中进行选择?

如果where子句在SQL中有重复的条件值,如何获取多行

MySQL存储过程从列表中插入多行

如何通过动态值数组获取记录顺序?

如何获取隐藏的 ID 以删除 jQuery 数据表中的记录

如何设置子查询以获取具有最新日期和最大 ID 的单个记录?