2013-02-17 23 views
1

我不知道这个问题与我想要的是否正确,但是:我们如何控制表中的字段的动态排序?

我在表格中有一组问题,将以特定顺序询问客户,有时我们需要插入新的问题以及我们需要向上或向下移动问题。

我做了一个名为position的字段,还有一些按钮用于增加和减少它的位置,所以我可以使用SELECT ... ORDER BY,但它不是很好,因为有时两个或更多个问题获得相同的位置编号,MySQL选择它们的顺序。

那么完成这个工作的正确方法是什么?

注:我不能使用索引来做到这一点。这对一些人来说是显而易见的,但对其他人来说却不是这样...

+3

'ORDER BY order_field,some_other_field'?您不必仅按一个字段进行排序...... – 2013-02-17 23:34:19

+0

难道您不能在内存中构建问题ID的图形,然后在需要时从数据库中检索它们吗? “有时候我们需要插入新的问题,而且我们需要向上或向下移动问题”建议流程逻辑可以适用于图表结构 – 2013-02-18 03:05:42

回答

6

如果我理解你的话,你需要一种方法来正确管理position列中的值序列,当你插入新的问题时,改变现有的位置一个或删除问题。

比方说,你有以下的问题表的DDL:

CREATE TABLE `questions` (
    `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, 
    `question` VARCHAR(256) DEFAULT NULL, 
    `position` INT(11) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
); 

和初使数据集这样

+----+------------+----------+ 
| id | question | position | 
+----+------------+----------+ 
| 1 | Question 1 |  1 | 
| 2 | Question 2 |  2 | 
| 3 | Question 3 |  3 | 
+----+------------+----------+ 

若要下令你做明显的问题清单

SELECT * 
    FROM questions 
ORDER BY position; 

To in塞尔特人的问题列表你做的最后一个新问题

INSERT INTO questions (question, position) 
SELECT 'New Question', COALESCE(MAX(position), 0) + 1 
    FROM questions; 

结果将是:

+----+--------------+----------+ 
| id | question  | position | 
+----+--------------+----------+ 
| 1 | Question 1 |  1 | 
| 2 | Question 2 |  2 | 
| 3 | Question 3 |  3 | 
| 4 | New Question |  4 | 
+----+--------------+----------+ 

要插入一个新的问题到特定位置(假设到位置3)在列表中,您有两个查询做到这一点:

UPDATE questions 
    SET position = position + 1 
WHERE position >= 3; 

INSERT INTO questions (question, position) 
VALUES ('Another Question', 3); 

现在你有

+----+------------------+----------+ 
| id | question   | position | 
+----+------------------+----------+ 
| 1 | Question 1  |  1 | 
| 2 | Question 2  |  2 | 
| 5 | Another Question |  3 | 
| 3 | Question 3  |  4 | 
| 4 | New Question  |  5 | 
+----+------------------+----------+ 

要交换两个问题的位置(例如,与IDS 2个问题和5)你做

UPDATE questions AS q1 INNER JOIN 
     questions AS q2 ON q1.id = 2 AND q2.id = 5 
    SET q1.position = q2.position, 
     q2.position = q1.position 

让我们看看我们有什么

+----+------------------+----------+ 
| id | question   | position | 
+----+------------------+----------+ 
| 1 | Question 1  |  1 | 
| 5 | Another Question |  2 | 
| 2 | Question 2  |  3 | 
| 3 | Question 3  |  4 | 
| 4 | New Question  |  5 | 
+----+------------------+----------+ 

这就是你做什么,当用户点击您的向上和向下按钮,提供正确的问题编号。

现在,如果您希望在删除问题时保持自己的位置顺序没有间隙,那么可以这样做。

要从列表的末尾删除您使用列表的简单删除

DELETE FROM questions WHERE id=4; 

结果

+----+------------------+----------+ 
| id | question   | position | 
+----+------------------+----------+ 
| 1 | Question 1  |  1 | 
| 5 | Another Question |  2 | 
| 2 | Question 2  |  3 | 
| 3 | Question 3  |  4 | 
+----+------------------+----------+ 

删除问题在中间(或开始)需要更多的工作。比方说,我们要删除ID为这个问题= 5

-- Get the current position of question with id=5 
SELECT position FROM questions WHERE id=5; 
-- Position is 2 
-- Now delete the question 
DELETE FROM questions WHERE id=5; 
-- And update position values 
UPDATE questions 
    SET position = position - 1 
WHERE position > 2; 

最后我们

+----+--------------+----------+ 
| id | question  | position | 
+----+--------------+----------+ 
| 1 | Question 1 |  1 | 
| 2 | Question 2 |  2 | 
| 3 | Question 3 |  3 | 
+----+--------------+----------+ 

UPDATE:为了使我们的生活更轻松,我们可以把它包装所有在存储过程中

DELIMITER $$ 
CREATE PROCEDURE add_question (q VARCHAR(256), p INT) 
BEGIN 

IF p IS NULL OR p = 0 THEN 
    INSERT INTO questions (question, position) 
    SELECT q, COALESCE(MAX(position), 0) + 1 
     FROM questions; 
ELSE 
    UPDATE questions 
     SET position = position + 1 
    WHERE position >= p; 

    INSERT INTO questions (question, position) 
    VALUES (q, p); 
END IF; 
END$$ 
DELIMITER ; 

DELIMITER $$ 
CREATE PROCEDURE swap_questions (q1 INT, q2 INT) 
BEGIN 
    UPDATE questions AS qs1 INNER JOIN 
      questions AS qs2 ON qs1.id = q1 AND qs2.id = q2 
     SET qs1.position = qs2.position, 
      qs2.position = qs1.position; 
END$$ 
DELIMITER ; 

DELIMITER $$ 
CREATE PROCEDURE delete_question (q INT) 
BEGIN 
    SELECT position INTO @cur_pos FROM questions WHERE id=q; 
    SELECT MAX(position) INTO @max FROM questions; 

    DELETE FROM questions WHERE id=q; 

IF @cur_pos <> @max THEN 
    UPDATE questions 
     SET position = position - 1 
    WHERE position > @cur_pos; 
END IF; 
END$$ 
DELIMITER ; 

并且像这样使用它们:

-- Add a question to the end of the list 
CALL add_question('How are you today?', 0); 
CALL add_question('How are you today?', NULL); 

-- Add a question at a specific position 
CALL add_question('How do you do today?', 3); 

-- Swap questions' positions 
CALL swap_questions(1, 7); 

-- Delete a question 
CALL delete_question(2); 
+0

Tina Turner会说,你简单最好!谢谢! – PSyLoCKe 2013-02-19 12:50:37

相关问题