2016-12-02 3 views
0

Ich habe eine Abfrage, die sich selbst verbindet, um entweder den Datensatz der letzten oder ältesten Bestellung für jede eindeutige Liste abzurufen.Gibt es eine Möglichkeit, einen Operator basierend auf einem CASE in MySQL dynamisch zu definieren?

SELECT 
    lists.ordered, 
    cnt1.* 
FROM 
    cnt_lists as cnt1 
    LEFT JOIN 
     lists 
     on 
      cnt1.list_id = lists.id 
    LEFT JOIN 
     cnt_lists as cnt2 
     on 
      (cnt1.list_id = cnt2.list_id AND cnt1.id < cnt2.id) 

WHERE 
    cnt2.id is null and cnt1.list_id in ('3176', '3295', '3296') and cnt1.listable_type = 'Movie'; 

Diese Abfrage funktioniert gut, aber lists.ordered kann entweder eine 0 oder eine 1 sein, wenn lists.ordered = 0 ich den Bediener bei der on Anweisung sein möchte cnt1.id < cnt2.id aber wenn lists.ordered = 1 Ich möchte es cnt1.id > cnt2.id rückgängig gemacht werden.

Gibt es eine Möglichkeit, den Operator basierend auf einer CASE-Anweisung dynamisch zu definieren? Das Folgende funktioniert nicht, aber ich spielte mit Ideen.

SELECT 
    lists.ordered, 
    CASE 
     WHEN lists.ordered = 1 THEN '>' 
     ELSE '<' 
    END AS operator, 
    cnt1.* 
FROM 
    cnt_lists as cnt1 
    LEFT JOIN 
     lists 
     on 
      cnt1.list_id = lists.id 
    LEFT JOIN 
     cnt_lists as cnt2 
     on 
      (cnt1.list_id = cnt2.list_id AND cnt1.id operator cnt2.id) 

WHERE 
    cnt2.id is null and cnt1.list_id in ('3176', '3295', '3296') and cnt1.listable_type = 'App\\Models\\Movie'; 

Was ist, um sowohl die höchste Ordnung zu ziehen und die niedrigste Ordnung für jede Liste, und ich kann, welche der beiden Datensätze bestimmen, auf der PHP-Seite zu benutzen?

Ich bin nur auf der Suche nach Ideen, wie ich versuche, eine N + 1 Abfrage Problem zu vermeiden, für jede Liste einzeln abfragen zu müssen.

Antwort

2

Sich auf eine dynamische Abfrage zu verlassen, ist unordentlich. Du bist besser dran, dass die Betreiber in den WHERE Teil der Abfrage ziehen und koppeln sie mit einem OR:

SELECT 
    lists.ordered, 
    cnt1.* 
FROM 
    cnt_lists as cnt1 
    LEFT JOIN 
     lists 
     on 
      cnt1.list_id = lists.id 
    LEFT JOIN 
     cnt_lists as cnt2 
     on 
      (cnt1.list_id = cnt2.list_id) 

WHERE 
    cnt2.id is null and cnt1.list_id in ('3176', '3295', '3296') 
    and cnt1.listable_type = 'Movie' 
    AND (
     cnt2.id IS NULL /* Including this here because you have a LEFT JOIN */ 
     (lists.ordered = 1 AND cnt1.id < cnt2.id) OR 
     (lists.ordered = 0 AND cnt1.id > cnt2.id) 
    ); 

Die andere Option ist direkt diese Logik in der Join-Logik zu setzen. Dies kann einfacher zu lesen sein.

SELECT 
    lists.ordered, 
    cnt1.* 
FROM 
    cnt_lists as cnt1 
    LEFT JOIN 
     lists 
     on 
      cnt1.list_id = lists.id 
    LEFT JOIN 
     cnt_lists as cnt2 
     on 
      (cnt1.list_id = cnt2.list_id AND (
     (lists.ordered = 1 AND cnt1.id < cnt2.id) OR 
     (lists.ordered = 0 AND cnt1.id > cnt2.id) 
    )) 

WHERE 
    cnt2.id is null and cnt1.list_id in ('3176', '3295', '3296') 
    and cnt1.listable_type = 'Movie' 
    ; 

Sie haben die Möglichkeit, von < in der endgültigen Ausgabe einschließlich, aber das wird nicht besonders nützlich sein.

Wenn Sie * WIRKLICH * möchten eine dynamische Abfrage erstellen, ist es schwierig, in einem Schritt zu tun, but it is definitely doable.

+0

Ich erkunde Ihre zweite Option mit der Logik in der Join-Anweisung, aber ich sehe eine seltsame Sache. In diesem Fall '(lists.ordered = 1 AND cnt1.id ATLChris

Verwandte Themen