Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

thủ tục mysql để cập nhật tham chiếu số trong các hàng trước đó khi một được cập nhật

Tôi nghĩ có hai trường hợp cần xem xét:

  1. Di chuyển một hàng để nó xuất hiện sớm hơn trong thứ tự.
  2. Di chuyển một hàng để nó xuất hiện sau trong thứ tự.

Nó không phải là tầm thường theo cả hai cách. Không rõ liệu có một ràng buộc duy nhất nào đối với cột 'order' hay không; kết quả cuối cùng chắc chắn phải có một thứ tự duy nhất.

Kí hiệu:

  • 'Bật' đề cập đến hàng có giá trị 'order =n' trong các giá trị cũ
  • 'Nn' đề cập đến hàng có 'order =n' trong các giá trị mới

Trong ví dụ (minh họa cho trường hợp 1):

  • O3 -> N1
  • O1 -> N2
  • O2 -> N3

Thay vào đó, hãy xem xét việc di chuyển id =2 để nó có thứ tự =4:

  • O2 -> N4
  • O3 -> N2
  • O4 -> N3

Về cơ bản, bạn đang thêm hoặc bớt một từ các hàng 'khác', trong đó đó là các hàng theo thứ tự cũ giữa vị trí cũ của hàng đã di chuyển và vị trí mới của hàng đã di chuyển. Trong mã giả, sử dụng $ old và $ new để xác định vị trí trước và sau của hàng đã di chuyển và xử lý trường hợp 1 ($ old> $ new):

UPDATE AnonymousTable
   SET order = CASE
               WHEN order = $old THEN $new
               WHEN order >= $new AND order < $old THEN order + 1
               END CASE
 WHERE order BETWEEN $new AND $old;

Mã tương ứng cho trường hợp 2 ($ old <$ new) là:

UPDATE AnonymousTable
   SET order = CASE
               WHEN order = $old THEN $new
               WHEN order > $new AND order <= $old THEN order - 1
               END CASE
 WHERE order BETWEEN $old AND $new;

Với toàn bộ mệnh đề WHERE trên UPDATE, bạn có thể loại bỏ WHEN thứ hai trong CASE và thay thế nó bằng một ELSE đơn giản.

UPDATE AnonymousTable
   SET order = CASE
               WHEN order = $old THEN $new
               ELSE                   order + 1
               END CASE
 WHERE order BETWEEN $new AND $old;

UPDATE AnonymousTable
   SET order = CASE
               WHEN order = $old THEN $new
               ELSE                   order - 1
               END CASE
 WHERE order BETWEEN $old AND $new;

Tôi nghĩ rằng một thủ tục được lưu trữ là theo thứ tự - lựa chọn giữa hai câu lệnh dựa trên các tham số đầu vào $ old, $ new. Bạn có thể làm điều gì đó với sự kết hợp hợp lý của các biểu thức chẳng hạn như '($old - $new) / ABS($old - $new) 'và' MIN($old, $new) 'và' MAX($old, $new) 'trong đó MIN / MAX không phải là tổng hợp mà là hàm so sánh cho một cặp giá trị (như được tìm thấy trong Fortran, trong số các ngôn ngữ lập trình khác).

Lưu ý rằng tôi đang giả định rằng trong khi một câu lệnh SQL duy nhất đang thực thi, ràng buộc về tính duy nhất (nếu có) không được thực thi khi mỗi hàng được thay đổi - chỉ khi câu lệnh hoàn thành. Điều này là cần thiết vì bạn thực sự không thể kiểm soát thứ tự các hàng được xử lý. Tôi biết về DBMS nơi điều này sẽ gây ra rắc rối; Tôi biết về những người khác ở nơi nó sẽ không.

Tất cả có thể được thực hiện trong một câu lệnh SQL duy nhất - nhưng bạn muốn một thủ tục được lưu trữ để sắp xếp các tham số cho câu lệnh. Tôi sử dụng Máy chủ động Informix của IBM (11.50.FC6 trên MacOS X 10.6.2) và đó là một trong những DBMS thực thi ràng buộc duy nhất trên cột 'đơn hàng' ở cuối câu lệnh. Tôi đã phát triển SQL mà không có ràng buộc DUY NHẤT; điều đó cũng hoạt động, tất nhiên. (Và có, IDS cho phép bạn khôi phục các câu lệnh DDL như TẠO BẢNG và TẠO THỦ TỤC. Bạn đã nói gì? DBMS của bạn không? Thật kỳ lạ!)

BEGIN WORK;
CREATE TABLE AnonymousTable
(
    id      INTEGER NOT NULL PRIMARY KEY,
    title   VARCHAR(10) NOT NULL,
    order   INTEGER NOT NULL UNIQUE
);
INSERT INTO AnonymousTable VALUES(1, 'test1', 1);
INSERT INTO AnonymousTable VALUES(2, 'test2', 2);
INSERT INTO AnonymousTable VALUES(3, 'test3', 3);
INSERT INTO AnonymousTable VALUES(4, 'test4', 4);

SELECT * FROM AnonymousTable ORDER BY order;

CREATE PROCEDURE move_old_to_new(old INTEGER, new INTEGER)
    DEFINE v_min, v_max, v_gap, v_inc INTEGER;
    IF old = new OR old IS NULL OR new IS NULL THEN
        RETURN;
    END IF;
    LET v_min = old;
    IF new < old THEN
        LET v_min = new;
    END IF;
    LET v_max = old;
    IF new > old THEN
        LET v_max = new;
    END IF;
    LET v_gap = v_max - v_min + 1;
    LET v_inc = (old - new) / (v_max - v_min);
    UPDATE AnonymousTable
       SET order = v_min + MOD(order - v_min + v_inc + v_gap, v_gap)
     WHERE order BETWEEN v_min AND v_max;
END PROCEDURE;

EXECUTE PROCEDURE move_old_to_new(3,1);
SELECT * FROM AnonymousTable ORDER BY order;
EXECUTE PROCEDURE move_old_to_new(1,3);
SELECT * FROM AnonymousTable ORDER BY order;

INSERT INTO AnonymousTable VALUES(5, 'test5', 5);
INSERT INTO AnonymousTable VALUES(6, 'test6', 6);
INSERT INTO AnonymousTable VALUES(7, 'test7', 7);
INSERT INTO AnonymousTable VALUES(8, 'test8', 8);

EXECUTE PROCEDURE move_old_to_new(3,6);
SELECT * FROM AnonymousTable ORDER BY order;
EXECUTE PROCEDURE move_old_to_new(6,3);
SELECT * FROM AnonymousTable ORDER BY order;
EXECUTE PROCEDURE move_old_to_new(7,2);
SELECT * FROM AnonymousTable ORDER BY order;
EXECUTE PROCEDURE move_old_to_new(2,7);
SELECT * FROM AnonymousTable ORDER BY order;

ROLLBACK WORK;

Các cặp lệnh gọi của thủ tục được lưu trữ với các số được đảo ngược sẽ khôi phục lại thứ tự ban đầu mỗi lần. Rõ ràng, tôi có thể xác định lại v_inc để thay vì chỉ ± 1, nó là 'LET v_inc = v_inc - v_min + v_gap; 'và khi đó biểu thức MOD sẽ chỉ là' MOD(order + v_inc, v_gap) '. Tôi chưa kiểm tra xem điều này có hoạt động với số âm hay không.

Việc thích ứng với MySQL hoặc DBMS khác được coi là một bài tập cho người đọc.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cách thiết lập kết nối PDO đúng cách

  2. Đếm số hàng riêng biệt cho nhiều giá trị

  3. Quyền truy cập PHP MySql (1045) bị từ chối đối với người dùng

  4. tạo bảng mysql nếu nó không tồn tại

  5. Vị trí chính xác của các bảng cơ sở dữ liệu MySQL trong thư mục XAMPP là gì?