动态SQL排序帮助

时间:2011-06-22 04:58:09

标签: mysql dynamic sql-order-by

嘿伙计们,我环顾四周,但没有解决这个问题。

我有一个帖子/评论数据库,我无法正确订购。

我需要它主要通过它的id来排序,但如果它的parent_id不等于它的id,它将被放置在它的父节点之后,这些子节点也会按id排序。

这是我目前的数据库。

CREATE TABLE `questions` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `parent_id` int(10) NOT NULL,
  `entry_type` varchar(8) NOT NULL,
  `entry_content` varchar(1024) NOT NULL,
  `entry_poster_id` varchar(10) NOT NULL,
  `entry_status` varchar(1) NOT NULL,
  `entry_score` varchar(10) NOT NULL,
  `time_posted` varchar(10) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `id` (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;

--
-- Dumping data for table `questions`
--

INSERT INTO `questions` VALUES(1, 1, 'question', 'How do I does SQL?', 'CodyC', '0', '2', '1308641965');
INSERT INTO `questions` VALUES(2, 1, 'answer', 'Easy, you eat cheese!', 'PatrickS', '0', '-4', '1308641965');
INSERT INTO `questions` VALUES(3, 2, 'comment', 'WTF are you on noobass?!', 'FraserK', '0', '100', '1308641965');
INSERT INTO `questions` VALUES(4, 1, 'answer', 'blah', '5', '0', '0', '1308642204');
INSERT INTO `questions` VALUES(5, 4, 'comment', 'blah2', '4', '0', '0', '1308642247');
INSERT INTO `questions` VALUES(6, 2, '2', '3', '3', '3', '3', '3');

和我当前的查询

SELECT *
FROM questions
WHERE parent_id =1
OR parent_id
IN (
    SELECT id
    FROM questions
    WHERE parent_id =1
    AND parent_id != id
)

我如何订购,以便每个对象在其父级之后的订单ID,其中id = parent_id表示基础级别且没有父级!

提前致谢。

弗雷泽

7 个答案:

答案 0 :(得分:1)

这似乎有效:

SELECT *
FROM questions
order by case when parent_id != id then parent_id else id end, id;

但这取决于你是否想要孩子之前的孙子等。你的问题没有说明。

但是,如果您使用这种技术,您可以根据需要使订购条款变得复杂 - 它不需要是选定的列 - 只需补充您需要的内容即可。

答案 1 :(得分:0)

使用mysql看起来有点复杂,但你可以使用PHP。使用递归函数。这很容易处理。

这是代码库中的一个函数。它只是创建一个无序列表树。您可以根据自己的要求对其进行修改

function output_lis_pages($parentID = 0)
{
    $stack = array(); //create a stack for our <li>'s 

    $arr = array();
    $sql = "select pageid, pagetitle, pagelink, parentid
        from pages
        where parentid =  $parentID
        order by orderid";

    $crs = mysql_query($sql);

    if(mysql_num_rows($crs)==0)
    {
            // no child menu exists for this page
            return false;
    }   
    else
    {
            while($crow = mysql_fetch_array($crs))
            {
                $arr [] =  array(
                    'pagetitle'=> stripslashes($crow["pagetitle"]),
                    'pagelink'=> $crow["pagelink"],
                    'parentid'=>$crow["parentid"],
                    'pageid'=>$crow["pageid"]
                    );
            }
    }

    foreach($arr as $a)
    { 
            $str = '';
                    //if the item's parent matches the parentID we're outputting...
            if($a['parentid']==$parentID)
            { 
                if($a['pagelink']=="")
                        $tmplink = "page.php?pageid=".$a['pageid'];
                else
                        $tmplink = $a['pagelink'];


                $str.='<li><a href="'.$tmplink.'">'.$a['pagetitle']."</a>";

                $subStr = output_lis_pages($a['pageid']);

                if($subStr){
                        $str.="\n".'<ul>'.$subStr.'</ul>'."\n";
                }

                $str.='</li>'."\n";
                $stack[] = $str;
            }
    }
    //If we have <li>'s return a string 
    if(count($stack)>0)
    {
            return  join("\n",$stack);
    }

    //If no <li>'s in the stack, return false 
    return false;
}

答案 2 :(得分:0)

    SELECT *
         , CASE WHEN parent_id = 1 THEN id ELSE parent_id END AS sort_level
    FROM questions
    WHERE parent_id = 1
       OR parent_id
          IN (
              SELECT id
              FROM questions
              WHERE parent_id = 1
                AND parent_id != id
             )
    ORDER BY sort_level 
           , id

答案 3 :(得分:0)

你遇到了关系数据库系统的旧bugbear。当您的数据具有层次结构时,使用它们并不好玩。您有尝试从数据库记录中生成图表的特定步骤的问题。没有SQL方言中的递归功能,这很难实现。这是一个可能有用的链接: http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/

另请参阅StackOverflow:What are the options for storing hierarchical data in a relational database?

答案 4 :(得分:0)

调查你的问题并阅读你的评论 - “我需要得到一个具体问题,包括所有答案和评论”,我认为你希望展示每个问题,然后是答案,然后是评论。正确?

如果是这样,这是您的查询:

SELECT `id`,
(CASE 
    WHEN `entry_type` = 'question' THEN CONCAT(`id`, '-', `parent_id`)
    WHEN `entry_type` = 'answer' THEN CONCAT(`id`, '-', `parent_id`)
    WHEN `entry_type` = 'comment' THEN CONCAT(`parent_id`, '-', `id`)
END) `sort_order`,
`entry_type`, `entry_content`
FROM `questions`
ORDER BY `sort_order`;

以上查询将为您提供每个问题,然后是第一个答案,然后是对第一个答案的评论;然后是第二个答案,然后是对第二个答案的评论,依此类推。

因此,对于您给出的INSERT,这将是输出:

+----+------------+------------+--------------------------+
| id | sort_order | entry_type | entry_content            |
+----+------------+------------+--------------------------+
|  1 | 1-1        | question   | How do I does SQL?       |
|  2 | 2-1        | answer     | Easy, you eat cheese!    |
|  3 | 2-3        | comment    | WTF are you on noobass?! |
|  6 | 2-6        | comment    | 3                        |
|  4 | 4-1        | answer     | blah                     |
|  5 | 4-5        | comment    | blah2                    |
+----+------------+------------+--------------------------+

希望它有所帮助。

编辑:更新了查询,仅针对一个问题获取答案和评论

SELECT `id`, 
(CASE
    WHEN (`entry_type` IN ('question', 'answer')) THEN `id`
    WHEN `entry_type` = 'comment' THEN `parent_id`
END) `sort_order_1`, 
(CASE
    WHEN (`entry_type` IN ('question', 'answer')) THEN `parent_id`
    WHEN `entry_type` = 'comment' THEN `id`
END) `sort_order_2`, 
(CASE
    WHEN (`entry_type` IN ('question', 'answer')) THEN `parent_id`
    WHEN `entry_type` = 'comment' THEN (SELECT `Q1`.`parent_id` FROM `questions` `Q1` WHERE `Q1`.`id` = `Q`.`parent_id`)
END) `question_id`,
`entry_type`, `entry_content` 
FROM `questions` `Q` 
HAVING `question_id` = 1 
ORDER BY `sort_order_1`, `sort_order_2`;

输出:

+----+--------------+--------------+-------------+------------+--------------------------+
| id | sort_order_1 | sort_order_2 | question_id | entry_type | entry_content            |
+----+--------------+--------------+-------------+------------+--------------------------+
|  1 | 1            | 1            |           1 | question   | How do I does SQL?       |
|  2 | 2            | 1            |           1 | answer     | Easy, you eat cheese!    |
|  3 | 2            | 3            |           1 | comment    | WTF are you on noobass?! |
|  6 | 2            | 6            |           1 | comment    | 3                        |
|  4 | 4            | 1            |           1 | answer     | blah                     |
|  5 | 4            | 5            |           1 | comment    | blah2                    |
+----+--------------+--------------+-------------+------------+--------------------------+

您可以更改HAVING部分以获取特定问题的答案和评论。希望这有帮助!

编辑2 :可能是另一种可能的实现(但我认为它可能对大型表有一些性能影响):

SELECT `a`.`id` AS `question_id`, `a`.`entry_content` AS `question`,
    `b`.`id` AS `answer_id`, `b`.`entry_content` AS `answer`,
    `c`.`id` AS `comment_id`, `c`.`entry_content` AS `comment`
FROM `questions` `a`
LEFT JOIN `questions` `b` ON (`a`.`id` = `b`.`parent_id` AND `b`.`entry_type` = 'answer')
LEFT JOIN `questions` `c` ON (`b`.`id` = `c`.`parent_id` AND `c`.`entry_type` = 'comment')
WHERE `a`.`entry_type` = 'question'
AND `a`.`id` = 1
ORDER BY `a`.`id`, `b`.`id`, `c`.`id`;

输出:

+----+--------------------+------+-----------------------+------+--------------------------+
| id | question           | id   | answer                | id   | comment                  |
+----+--------------------+------+-----------------------+------+--------------------------+
|  1 | How do I does SQL? |    2 | Easy, you eat cheese! |    3 | WTF are you on noobass?! |
|  1 | How do I does SQL? |    2 | Easy, you eat cheese! |    6 | 3                        |
|  1 | How do I does SQL? |    4 | blah                  |    5 | blah2                    |
+----+--------------------+------+-----------------------+------+--------------------------+

答案 5 :(得分:0)

经过一周的尝试后,我无法让它与查询一起工作,所以我决定只在PHP中执行它,这也将减少MySQL引擎的负载。这是我希望引用它的任何人的PHP。

$question_id = $database->escape_string($question_id); //escape input
$q = "SELECT * FROM questions WHERE parent_id = $question_id OR parent_id IN (SELECT id FROM questions  WHERE parent_id = $question_id AND parent_id != id) ORDER BY parent_id , id";
$database->dbquery($q);//query the DB
while($row = $database->result->fetch_assoc()){//Process results to standard array.
    //other irrelevant stuff happens here
    $unsorted[] = $row;
}
$question = array_shift($unsorted);//take the question off the array
$sorted[] = $question;//add it to the start of the sorted array
$qusetion_id = $question['id'];
foreach($unsorted as $row){//this creates a multidimensional hierarchy of the answers->comments
    if($row['parent_id'] == $question_id){//if its an answer
        $sorted_multi[$row['id']] = array();//create a new answer sub-array
        $sorted_multi[$row['id']][] = $row;//append it
    }else{
        $sorted_multi[$row['parent_id']][] = $row;//append the answer to the correct sub-array
    }
}
foreach($sorted_multi as $temp){//converts the multidimensional into a single dimension appending it to the sorted array.
    foreach($temp as $row){
        $sorted[] = $row;
    }
}

单调乏味,但最终因为其他无法预料的处理需要在mysql之后完成而更好。

感谢所有回复:):)):)

答案 6 :(得分:-1)

Simply use the "ORDER BY" clause to select the ordering you want!

SELECT *
    FROM questions
    WHERE parent_id =1
    OR parent_id
    IN (
        SELECT id
        FROM questions
        WHERE parent_id =1
        AND parent_id != id
    )
    ORDER BY Parent_id , id