2016-03-09 16 views
6

Mam następujący, prosty stółMySQL wynik zestaw uporządkowane według ustalonych pozycjach

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) 

Liczba elementów nie jest ustalony, w rzeczywistości mogą różnić się od ~ 100 do ~ 1000.

Co chcę osiągnąć, to wykonać zapytanie, aby zwrócić zestaw elementów zamówionych przez pole date, które bierze pod uwagę pole "przypięte" do określonych pozycji. Jeśli fixed_position dla danego wpisu nie ma wartości NULL, wynik powinien być przypięty do n-tej pozycji, a jeśli fixed_position ma wartość NULL, to pierwszeństwo ma ORDER BY.

pożądany wynik zapytania do jaśniejszego wyjaśnienia:

(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` 

Próbowałem rozwiązanie pisał w Ordering MySql results when having fixed position for some items ale nawet metodą kopiuj-wklej ten wydaje się nie działać w ogóle.

Co próbowałem tak daleko jest to zapytanie:

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 

Które zwraca:

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 

Czy MySQL może wykonać taką czynność czy mam wziąć podejście backend i wykonać PHP array_merge() na dwóch zestawy wyników?

+0

Co to jest kod SQL, którego używasz? Abyśmy mogli zobaczyć, co próbowaliście. IE: 'zamówienie według daty, ifnull (fixed_position, 0)' –

+0

Dodałem przykładowe zapytanie w moim pytaniu. Spędził ponad 5 godzin na to, szukając odpowiedzi, skończyło się prawie nic. –

+0

Czy 'fixed_position' jest polem w twojej tabeli, czy polem obliczeniowym? –

Odpowiedz

3

brutalny sposób siła rozwiązać to byłoby najpierw utworzyć tabelę sygnalizacyjną mającą ilość rzędów większe niż oryginalnej tabeli:

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 

Następnie można LEFT JOIN tej tabeli do tabeli pochodnej zawierającej wszystko ustalone pozycje oryginalnego stołu:

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 

Powyższe informacje zwracają brakujące pozycje zamówienia.

Demo here

Możesz teraz użyć powyższej kwerendy jako kolejna tabela pochodzi dołączył do oryginalnej tabeli w celu osiągnięcia pożądanego Kolejność:

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

To jest po prostu idealne! Dziękuję, uratowałeś mi dzień i niezliczone godziny pracy. –

0

miałem takie same problem (sortuj według daty + wstawiaj wiersze o stałych wartościach pozycji). Powyższe rozwiązanie wydaje się działać. Ale musisz wiedzieć, ile wartości ma twój stół. Linia:

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

musi się rozszerzyć, jeśli masz więcej wierszy, ponieważ tabela tymczasowa jest krótki. Po niektórych wynikach wyszukiwania Google i testach w DB, znalazłem rozwiązanie, które pasuje do Twoich potrzeb i jest mądrzejsze, aby zrozumieć, myślę.

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

Tak to jest, jak to działa: Istnieją dwa SELECT. Pierwsze SELECT wyszukuje wszystkie kolumny bez ustalonej pozycji i sortuje je według daty. Dodatkowo powoduje JOIN dodanie kolumny licznika wierszy. Drugi szuka wszystkich wierszy o ustalonej pozycji i zwraca sortowanie według "kolpozycji".

Obie instrukcje wyboru zostają połączone przez UNION ALL. Związek jest najpierw sortowany przez kolumnę ASCending, a w drugim kroku przez wartość majonEntry, która wskazuje, że wiersze o stałej pozycji mają być umieszczone przed innymi wierszami, które mają tę samą pozycję.

Powiązane problemy