Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment contrôler l'ordre dynamique par un champ dans une table ?

Si je vous comprends bien, vous avez besoin d'un moyen de gérer correctement la séquence de valeurs en position lorsque vous insérez de nouvelles questions, modifiez la position d'une question existante ou supprimez des questions.

Supposons que vous ayez le DDL suivant de votre tableau de questions :

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

et un ensemble de données initial comme celui-ci

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

Pour obtenir une liste ordonnée de questions vous faites évident

SELECT * 
  FROM questions 
 ORDER BY position;

Pour insérer une nouvelle question à la fin de la liste de questions vous faites

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

Le résultat sera :

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

Pour insérer une nouvelle question à un poste spécifique (disons à la position 3) dans la liste, vous le faites avec deux requêtes :

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

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

Maintenant vous avez

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

Pour échanger les positions de deux questions (par exemple, les questions avec les identifiants 2 et 5) vous faites

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

Voyons ce que nous avons

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

C'est exactement ce que vous faites lorsque l'utilisateur clique sur vos boutons haut et bas, en fournissant des identifiants de question corrects.

Maintenant, si vous souhaitez conserver la séquence de vos positions sans lacunes lorsque vous supprimez une question, vous pouvez le faire.

Pour supprimer de la fin de la liste vous utilisez la suppression simple

DELETE FROM questions WHERE id=4;

Résultats

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

Supprimer une question au milieu (ou au début) de la liste nécessite plus de travail. Disons que nous voulons supprimer la question avec 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;

Et enfin nous avons

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

MISE À JOUR :Pour nous faciliter la vie on peut tout emballer dans des procédures stockées

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 ;

et utilisez-les comme ceci :

-- 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);