2013-02-17 51 views
1

我不知道這個問題與我想要的是否正確,但是:我們如何控制表中的字段的動態排序?

我在表格中有一組問題,將以特定順序詢問客戶,有時我們需要插入新的問題以及我們需要向上或向下移動問題。

我做了一個名爲position的字段,還有一些按鈕用於增加和減少它的位置,所以我可以使用SELECT ... ORDER BY,但它不是很好,因爲有時兩個或更多個問題獲得相同的位置編號,MySQL選擇它們的順序。

那麼完成這個工作的正確方法是什麼?

注:我不能使用索引來做到這一點。這對一些人來說是顯而易見的,但對其他人來說卻不是這樣...

+3

'ORDER BY order_field,some_other_field'?您不必僅按一個字段進行排序...... – 2013-02-17 23:34:19

+0

難道您不能在內存中構建問題ID的圖形,然後在需要時從數據庫中檢索它們嗎? 「有時候我們需要插入新的問題,而且我們需要向上或向下移動問題」建議流程邏輯可以適用於圖表結構 – 2013-02-18 03:05:42

回答

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; 

To in塞爾特人的問題列表你做的最後一個新問題

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)在列表中,您有兩個查詢做到這一點:

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

要交換兩個問題的位置(例如,與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 

讓我們看看我們有什麼

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

這就是你做什麼,當用戶點擊您的向上和向下按鈕,提供正確的問題編號。

現在,如果您希望在刪除問題時保持自己的位置順序沒有間隙,那麼可以這樣做。

要從列表的末尾刪除您使用列表的簡單刪除

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

UPDATE:爲了使我們的生活更輕鬆,我們可以把它包裝所有在存儲過程中

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

Tina Turner會說,你簡單最好!謝謝! – PSyLoCKe 2013-02-19 12:50:37

相關問題