Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie steuern wir die dynamische Sortierung durch ein Feld in einer Tabelle?

Wenn ich Sie richtig verstehe, brauchen Sie eine Möglichkeit, die Wertefolge in position richtig zu verwalten Spalte, wenn Sie neue Fragen einfügen, die Position einer bestehenden ändern oder Fragen löschen.

Angenommen, Sie haben die folgende DDL Ihrer Fragentabelle:

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

und anfänglicher Datensatz wie dieser

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

Geordnete Fragenliste erhalten Sie tun es offensichtlich

SELECT * 
  FROM questions 
 ORDER BY position;

Um eine neue Frage am Ende der Fragenliste einzufügen du tust

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

Das Ergebnis wird sein:

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

Um eine neue Frage an einer bestimmten Position einzufügen (sagen wir an Position 3) in der Liste machen Sie es mit zwei Abfragen:

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

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

Jetzt haben Sie

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

Positionen von zwei Fragen vertauschen (z. B. Fragen mit den IDs 2 und 5) Sie tun

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

Mal sehen, was wir haben

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

Genau das tun Sie, wenn der Benutzer auf Ihre Aufwärts- und Abwärtsschaltflächen klickt und die richtigen Fragen-IDs bereitstellt.

Wenn Sie nun Ihre Positionsreihenfolge beim Löschen einer Frage lückenlos beibehalten möchten, können Sie dies tun.

Am Ende der Liste löschen Sie verwenden einfaches Löschen

DELETE FROM questions WHERE id=4;

Ergebnisse

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

Löschen einer Frage in der Mitte (oder am Anfang) der Liste erfordert mehr Arbeit. Nehmen wir an, wir möchten die Frage mit id=5

löschen
-- 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;

Und schließlich haben wir

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

AKTUALISIEREN :Um unser Leben einfacher zu machen, können wir alles in gespeicherte Prozeduren packen

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 ;

und verwenden Sie sie wie folgt:

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