【问题标题】:SELECT and list children and parent选择并列出孩子和父母
【发布时间】:2012-09-28 00:53:51
【问题描述】:

我需要一个用于以下复杂任务的 SQL 查询...

我需要从名为parent_id 的列中进行选择。如果一行的 parent_id 为 0,则表示它是一个类别(它还有 type 列,表示类别为 cat),如果一行的 parent_id 为 1 或更多,则表示它是一个类别规则。规则的parent_id 是类别的rule_id

包含一些数据的表结构:

我需要选择一种方式,即每个类别都有其子项。从图片中我们可以得到:

Sample Category 1
   Sample rule 1
Sample Category 2

我尝试了一些从这里找到的查询,但没有一个有效。

这是我上次尝试的:

'SELECT *
FROM ' . RULES_TABLE . ' AS parent
    LEFT JOIN ' . RULES_TABLE . ' AS child 
    ON child.parent_id = parent.rule_id 
WHERE parent.parent_id = 0
     AND parent.public = 1
ORDER BY parent.cat_position, child.rule_position';

它仅返回示例规则 1

想法?

【问题讨论】:

  • 如果您要问的是,您不能在 sql 中使用单个查询来执行此操作...请更具体一点,您可以通过查询类别和子查询来查询规则甚至在单个查询中,如果您可以在结果中没有规则的情况下牺牲类别并接收每个规则的类别名称,或者不牺牲带有连接(带有逗号或您选择的某些字符)规则名称的空类别
  • 我可以通过将查询放入由另一个查询创建的循环中来解决此问题,但不建议这样做,我不应该这样做。这就是为什么我在这里询问一个不包括循环查询的可接受的解决方案。
  • 如果您有不包含循环查询的解决方案,请发布。
  • @xception 你能告诉我一个例子,它与下面的内容相同,但带有子查询吗?
  • group_concat_max_size 不够?单个查询还有另一种方法,但需要在编程方面进行更多处理,或者我也可以使用子查询!

标签: php mysql sql select


【解决方案1】:

试试这个小提琴http://sqlfiddle.com/#!2/0a9c5/16,下面的sql代码

SELECT c.rule_id, c.rule_title, GROUP_CONCAT(r.rule_title)
FROM RULES_TABLE AS c
LEFT JOIN RULES_TABLE AS r
    ON r.parent_id = c.rule_id
WHERE c.parent_id IS NULL AND c.public = 1
GROUP BY c.rule_id
ORDER BY c.cat_position, c.rule_position;

故意省略代码的 php 化以保持语法突出显示,这似乎无论如何都不起作用

如果超过允许的最大 group_concat 大小,您可以增加它或使用以下版本,并在 php 中进行更多处理:

SELECT c.rule_id, c.rule_title, r.rule_title as r_rule_title
FROM RULES_TABLE AS c
LEFT JOIN RULES_TABLE AS r
    ON r.parent_id = c.rule_id
WHERE c.parent_id IS NULL AND c.public = 1
ORDER BY c.cat_position, c.rule_position;

在 php 中,只提供骨架代码,填写实际值,假设您使用 pdo 并且您的 pdostatement var 命名为$query

$old_rule_id = null;
$rrt = array(); // will contain all r.rule_titles for a give c.rule_id
while( ($i = $query->fetch(PDO::FETCH_OBJ)) !== false ) {
    if( $old_rule_id != $i->rule_id ) {
        if( count($rrt) ) {
            echo ... all the data for previous rule from $rrt ...
            echo ... end of previous element ...
            $rrt = array(); // empty it to collect new data
        }
        echo ... start of current element use data from $i->rule_id and $i->rule_title ...
        $old_rule_id = $rule_id;
    }
    $rrt[] = $i->r_rule_title;
}
// the following is the same if from inside the while, minus reinitialization of $rrt;
if( count($rrt) ) {
    echo ... all the data for previous rule from $rrt ...
    echo ... end of previous element ...
}

用有效代码替换...之间的内容

【讨论】:

  • You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'GROUP BY c.rule_id' at line 7 [1064]
  • @Dugi 用小提琴更新,group by 必须在 order by 之前,无论如何它现在可以工作了,唯一的事情是你在一个用逗号分隔的字符串中获取规则名称
  • 嗯,它确实工作得很好。很快就会接受你的回答。非常感谢:)
  • 发生了一件坏事。该查询将一个完整的字符串拆分为逗号分隔的字符串。 EG:来自 rule_description 的示例行显示 I will be going there,查询使其成为 I, will, be, going, there
  • 你给我一些实际数据怎么样,这样我就可以弄清楚你想要做什么,或者使用GROUP_CONCAT(r.rule_title SEPARATOR ' ')而不是使用空格而不是逗号,或者如果你已经有空格使用GROUP_CONCAT(r.rule_title SEPARATOR '')
【解决方案2】:

使用 FOR XML EXPLICIT 可以获得层次结构列表。

试试这个:

SELECT 
 1 Tag,
 null Parent,
 '' [root!1!name],
 null [category!2!id],
 null [category!2!name],
 null [rule!3!id],
 null [rule!3!name]

UNION ALL 

SELECT DISTINCT 
 2 Tag,
 1 Parent,
 null,
 rule_id [category!2!id],
 rule_title [category!2!name],
 null [rule!3!id],
 null [rule!3!name]
FROM rules
WHERE parent_id = 0 and rule_type = 'cat'

UNION ALL 

SELECT  
 3 Tag,
 2 Parent,
 null,
 parent_id [category!2!id],
 null [category!2!name],
 rule_id [rule!3!id],
 rule_title [rule!3!name]
FROM rules
WHERE parent_id > 0 and rule_type = 'rule'

FOR XML EXPLICIT

欲了解更多信息,请访问http://msdn.microsoft.com/en-us/library/ms189068.aspx

【讨论】:

  • 嗯,问题是mysql而不是mssql
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-13
  • 1970-01-01
相关资源
最近更新 更多