Mysql
 sql >> Database >  >> RDS >> Mysql

Come controlliamo l'ordinamento dinamico in base a un campo in una tabella?

Se ho capito bene, hai bisogno di un modo per gestire correttamente la sequenza di valori in position colonna quando si inseriscono nuove domande, si cambia la posizione di una esistente o si eliminano le domande.

Supponiamo che tu abbia il seguente DDL della tua tabella delle domande:

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

e set di dati iniziali come questo

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

Per ottenere un elenco ordinato di domande sei ovvio

SELECT * 
  FROM questions 
 ORDER BY position;

Per inserire una nuova domanda alla fine dell'elenco delle domande lo fai

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

Il risultato sarà:

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

Per inserire una nuova domanda in una posizione specifica (diciamo alla posizione 3) in lista lo fai con due query:

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

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

Ora hai

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

Per scambiare le posizioni di due domande (es. domande con ID 2 e 5) lo fai

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

Vediamo cosa abbiamo

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

Questo è esattamente ciò che fai quando l'utente fa clic sui pulsanti su e giù, fornendo ID domanda corretti.

Ora, se vuoi mantenere la sequenza delle tue posizioni senza interruzioni quando elimini la domanda, puoi farlo.

Per eliminare dalla fine dell'elenco usi l'eliminazione semplice

DELETE FROM questions WHERE id=4;

Risultati

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

Eliminazione di una domanda al centro (o all'inizio) dell'elenco richiede più lavoro. Supponiamo di voler eliminare la domanda con 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;

E finalmente abbiamo

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

AGGIORNAMENTO :Per semplificarci la vita, possiamo racchiudere tutto in procedure archiviate

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 ;

e usali in questo modo:

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