2016-03-09 27 views
6

Tôi đã có sau, đơn giản bảngMySQL kết quả thiết lập theo yêu cầu của vị trí cố định

Item (id, name, date, fixed_position) 

(1, 'first entry', '2016-03-09 09:00:00', NULL) 
(2, 'second entry', '2016-03-09 04:00:00', 1) 
(3, 'third entry', '2016-03-09 05:00:00', NULL) 
(4, 'fourth entry', '2016-03-09 19:00:00', NULL) 
(5, 'fifth entry', '2016-03-09 13:00:00', 4) 
(6, 'sixth entry', '2016-03-09 21:00:00', 2) 

Số lượng các mục không cố định, trên thực tế có thể khác nhau từ ~ 100 đến ~ 1000.

Điều tôi muốn đạt được là thực hiện truy vấn để trả lại các mục được sắp xếp theo trường date có trường xem xét fixed_position, viết tắt của trường như kết quả "ghim" vào các vị trí cụ thể. Nếu fixed_position cho mục nhập đã cho không phải là NULL thì kết quả sẽ được ghim vào vị trí thứ n và nếu fixed_position là NULL, thì ORDER BY sẽ được ưu tiên.

đầu ra mong muốn của truy vấn cho lời giải thích sáng: giải pháp

(2, 'second entry', '2016-03-09 04:00:00', 1) // pinned to 1-st position 
(6, 'sixth entry', '2016-03-09 21:00:00', 2)  // pinned to 2-nd position 
(3, 'third entry', '2016-03-09 05:00:00', NULL) // ORDER BY `date` 
(5, 'fifth entry', '2016-03-09 13:00:00', 4)  // pinned to 4-th position 
(1, 'first entry', '2016-03-09 09:00:00', NULL) // ORDER BY `date` 
(4, 'fourth entry', '2016-03-09 19:00:00', NULL) // ORDER BY `date` 

Tôi đã thử posted in Ordering MySql results when having fixed position for some items nhưng ngay cả với phương pháp cắt-dán này dường như không làm việc ở tất cả.

Những gì tôi đã cố gắng này đến nay là truy vấn này:

SELECT 
    @i := @i +1 AS iterator, 
    t.*, 
    COALESCE(t.fixed_position, @i) AS positionCalculated 
FROM 
    Item AS t, 
    (
SELECT 
    @i := 0 
) AS foo 
GROUP BY 
    `id` 
ORDER BY 
    positionCalculated, 
    `date` DESC 

nào trả về:

iterator | id | name  | date    | fixed_position | positionCalculated 
1   1 first entry 2016-03-09 09:00:00 NULL    1 
2   2 second entry 2016-03-09 04:00:00 1    1 
6   6 sixth entry 2016-03-09 21:00:00 2    2 
3   3 third entry 2016-03-09 05:00:00 NULL    3 
4   4 fourth entry 2016-03-09 19:00:00 NULL    4 
5   5 fifth entry 2016-03-09 13:00:00 4    4 

Liệu MySQL có thể thực hiện nhiệm vụ như vậy hay tôi nên áp dụng cách phụ trợ và thực hiện PHP array_merge() trên hai bộ kết quả?

+0

SQL bạn đang sử dụng là gì? Để chúng tôi có thể thấy những gì bạn đã thử. IE: 'sắp xếp theo ngày, ifnull (fixed_position, 0)' –

+0

Tôi đã thêm truy vấn mẫu trong câu hỏi của mình. Đã dành hơn 5 giờ để tìm kiếm câu trả lời, kết thúc với hầu như không có gì. –

+0

Trường 'fixed_position' có nằm trong bảng của bạn hay trường được tính toán không? –

Trả lời

3

Một phương pháp brute force để giải quyết này sẽ được đầu tiên tạo ra một bảng tổng sắp có một số lượng hàng lớn hơn bảng gốc:

SELECT @rn := @rn + 1 AS rn 
FROM (
    SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t1 
CROSS JOIN ( 
    SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t2 
CROSS JOIN (SELECT @rn := 0) AS v 

Sau đó, bạn có thể để lại gia nhập bảng này vào một bảng có nguồn gốc chứa tất cả vị trí cố định của bảng ban đầu của bạn:

SELECT Tally.rn 
FROM (
    ... tally table query here 
) AS Tally 
LEFT JOIN (
    SELECT fixed_position 
    FROM Item 
) AS t ON Tally.rn = t.fixed_position 
WHERE t.t.fixed_position IS NULL 

Ở trên trả về các vị trí đặt hàng bị thiếu.

Demo here

Bây giờ bạn có thể sử dụng các truy vấn trên như được nêu ra một bảng có nguồn gốc gia nhập vào bảng ban đầu để đạt được thứ tự mong muốn:

SELECT id, name, `date`, fixed_position, Gaps.rn, 
     derived.seq, Gaps.seq 
FROM (
    SELECT id, name, `date`, fixed_position, 
     @seq1 := IF(fixed_position IS NULL, @seq1 + 1, @seq1) AS seq 
    FROM Item  
    CROSS JOIN (SELECT @seq1 := 0) AS v 
    ORDER BY `date` 
) AS derived 
LEFT JOIN ( 
    SELECT Tally.rn, 
      @seq2 := @seq2 + 1 AS seq 
    FROM (
     SELECT @rn := @rn + 1 AS rn 
     FROM (
     SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t1 
     CROSS JOIN ( 
     SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t2 
     CROSS JOIN (SELECT @rn := 0) AS v 
    ) AS Tally 
    LEFT JOIN (
     SELECT fixed_position 
     FROM Item 
    ) AS t ON Tally.rn = t.fixed_position 
    CROSS JOIN (SELECT @seq2 := 0) AS v 
    WHERE t.t.fixed_position IS NULL 
    ORDER BY rn 
) AS Gaps ON (derived.seq = Gaps.seq) AND (derived.fixed_position IS NULL) 
ORDER BY COALESCE(derived.fixed_position, Gaps.rn) 

Demo here

+0

Điều này thật hoàn hảo! Cảm ơn bạn, bạn đã lưu lại ngày của tôi và vô số giờ làm việc. –

0

Tôi đã có cùng vấn đề (sắp xếp theo ngày + chèn hàng với giá trị vị trí cố định). Giải pháp trên dường như hoạt động. Nhưng bạn phải biết có bao nhiêu giá trị mà bảng của bạn có. Điểm mấu:

SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1

có để mở rộng nếu bạn có nhiều hàng vì bảng tạm thời là ngắn. Sau một số kết quả tìm kiếm google và kiểm tra trong DB của tôi, tôi đã tìm ra một giải pháp phù hợp với nhu cầu của bạn và thông minh hơn để hiểu tôi nghĩ.

SELECT * FROM (SELECT create_date, fixedposition, @rownum:[email protected] + 1 AS colposition, 1 AS majorEntry FROM myTable JOIN (SELECT @rownum:=0) r WHERE fixedposition IS NULL ORDER BY crdate DESC) AS orderedFixed UNION ALL (SELECT create_date, fixedposition, fixedposition AS colposition, 0 AS majorEntry FROM myTable WHERE fixedposition IS NOT NULL ORDER BY fixedposition ASC) ORDER BY colposition ASC, majorEntry

Vì vậy, đây là cách hoạt động: Có hai câu lệnh SELECT. SELECT đầu tiên tìm kiếm tất cả các cột không có vị trí cố định và sắp xếp chúng theo ngày. Ngoài ra nó làm cho một JOIN để thêm một cột truy cập hàng. Cách thứ hai tìm kiếm tất cả các hàng có vị trí cố định và trả về sắp xếp theo "cột".

Cả hai câu lệnh chọn được kết hợp bởi UNION ALL. Công đoàn được sắp xếp đầu tiên theo cụm từ ASCending và trong bước thứ hai bởi giá trị majonEntry cho biết rằng các hàng có vị trí cố định sẽ được đặt trước các hàng khác có cùng vị trí.

Các vấn đề liên quan