我不知道问题是否符合我的要求,但是:
我在表格中有一组问题将按特定顺序询问客户,有时我们需要插入新问题,我们还需要向下或向上移动问题.
我创建了一个名为position的字段,还有一些按钮来增加和减少它的位置所以我可以使用a SELECT ... ORDER BY但它不是很好,因为有时候两个或多个问题得到相同的位置编号而MySQL会选择它们的顺序.
那么让这个完美运作的正确方法是什么?
注意:我不能使用索引来做到这一点.对某些人来说很明显,但对其他人来说,不是......
如果我理解正确,您在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`)
);
Run Code Online (Sandbox Code Playgroud)
和这样的初始数据集
+----+------------+----------+
| id | question | position |
+----+------------+----------+
| 1 | Question 1 | 1 |
| 2 | Question 2 | 2 |
| 3 | Question 3 | 3 |
+----+------------+----------+
Run Code Online (Sandbox Code Playgroud)
要获得明确的有序问题列表
SELECT *
FROM questions
ORDER BY position;
Run Code Online (Sandbox Code Playgroud)
要在问题列表的末尾插入新问题,请执行此操作
INSERT INTO questions (question, position)
SELECT 'New Question', COALESCE(MAX(position), 0) + 1
FROM questions;
Run Code Online (Sandbox Code Playgroud)
结果将是:
+----+--------------+----------+
| id | question | position |
+----+--------------+----------+
| 1 | Question 1 | 1 |
| 2 | Question 2 | 2 |
| 3 | Question 3 | 3 |
| 4 | New Question | 4 |
+----+--------------+----------+
Run Code Online (Sandbox Code Playgroud)
要在列表中向特定位置(例如位置3)插入新问题,您可以使用两个查询执行此操作:
UPDATE questions
SET position = position + 1
WHERE position >= 3;
INSERT INTO questions (question, position)
VALUES ('Another Question', 3);
Run Code Online (Sandbox Code Playgroud)
现在你有了
+----+------------------+----------+
| id | question | position |
+----+------------------+----------+
| 1 | Question 1 | 1 |
| 2 | Question 2 | 2 |
| 5 | Another Question | 3 |
| 3 | Question 3 | 4 |
| 4 | New Question | 5 |
+----+------------------+----------+
Run Code Online (Sandbox Code Playgroud)
要交换两个问题的位置(例如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
Run Code Online (Sandbox Code Playgroud)
让我们看看我们得到了什么
+----+------------------+----------+
| id | question | position |
+----+------------------+----------+
| 1 | Question 1 | 1 |
| 5 | Another Question | 2 |
| 2 | Question 2 | 3 |
| 3 | Question 3 | 4 |
| 4 | New Question | 5 |
+----+------------------+----------+
Run Code Online (Sandbox Code Playgroud)
这正是当用户点击向上和向下按钮,提供正确的问题ID时所做的.
现在,如果你想在删除问题时保持你的位置序列没有间隙,你可以这样做.
要从列表末尾删除,请使用简单删除
DELETE FROM questions WHERE id=4;
Run Code Online (Sandbox Code Playgroud)
结果
+----+------------------+----------+
| id | question | position |
+----+------------------+----------+
| 1 | Question 1 | 1 |
| 5 | Another Question | 2 |
| 2 | Question 2 | 3 |
| 3 | Question 3 | 4 |
+----+------------------+----------+
Run Code Online (Sandbox Code Playgroud)
删除列表中间(或开头)的问题需要更多工作.假设我们要删除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;
Run Code Online (Sandbox Code Playgroud)
最后我们有
+----+--------------+----------+
| id | question | position |
+----+--------------+----------+
| 1 | Question 1 | 1 |
| 2 | Question 2 | 2 |
| 3 | Question 3 | 3 |
+----+--------------+----------+
Run Code Online (Sandbox Code Playgroud)
更新:为了让我们的生活更轻松,我们可以将它全部包装在存储过程中
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 ;
Run Code Online (Sandbox Code Playgroud)
并像这样使用它们:
-- 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);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
192 次 |
| 最近记录: |