1

質問が私が望むもので正しいかどうかはわかりませんが、

特定の順序でクライアントに尋ねられる一連の質問がテーブルにあり、新しい質問を挿入する必要がある場合や、質問を上下に移動する必要がある場合があります。

私は位置と呼ばれるフィールドを作成し、その位置を増減するためのいくつかのボタンを使用できるようにしましたSELECT ... ORDER BYが、2 つ以上の質問が同じ位置番号を取得し、MySQL がそれらの順序を選択することがあるため、あまり良くありません。

では、これを完全に機能させるための適切な方法は何ですか?

注: index を使用してそれを行うことはできません。一部の人にとっては明らかですが、他の人にとってはそうではありません...

4

1 に答える 1

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;

質問リストの最後に新しい質問を挿入するに

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 としましょう) に新しい質問を挿入するには、次の 2 つのクエリを使用します。

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 |
+----+------------------+----------+

2 つの質問(ID が 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 |
+----+------------------+----------+

これは、ユーザーが上下のボタンをクリックして正しい質問 ID を指定したときに行うこととまったく同じです。

質問を削除するときにギャップのない位置の順序を維持したい場合は、それを行うことができます。

リストの最後から削除するには、単純な削除を使用します

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 |
+----+--------------+----------+

更新: 私たちの生活を楽にするために、すべてをストアド プロシージャでラップすることができます

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);
于 2013-02-18T03:14:11.133 に答える