2009-05-11 15 views
1

Ich habe ein loooooooooooong SELECT Ende mit einer ORDER BY, dass kann die folgenden Werte:ORDER BY mit Bool> Datum> null in SQLite

  • geprüft (1 oder 0)
  • Datum (YYYY-MM -DD)
  • Zeit (HH: MM: SS)

Ich mag würde das Ergebnis der Abfrage die folgende Art und Weise bestellen:

|__checked = 0 
|   |__ date ASC 
|   |__ time ASC 
|   |__ date && time are null 
|__checked = 1 
      |__ date ASC 
      |__ time ASC 
      |__ date && time are null 

Für jetzt habe ich etwas einfaches wie "ORDER BY i1.checked, Datum, Zeit", aber das Problem ist, dass die Elemente mit leeren Datum und Zeiten oben bleiben.

Hier ist die ganze Abfrage, wenn Sie jemals denken, Sie brauchen alle Daten, um eine richtige Lösung zu finden. Schrei nicht.

SELECT i1._id AS _id, i1.title AS title, i1.checked AS checked, 

    // count the children (-1 is because the closure table include a relation between any item and itself) 
    (count(c1.item_id) - 1) AS children_count, 

    // count the unchecked children 
    (SELECT (COUNT(DISTINCT i2._id)) 
    FROM item AS i2 JOIN closure AS c2 ON (i2._id = c2.item_id) 
    WHERE c2.ancestor_id = i1._id 
    AND i2.checked = 0 
    AND c2.item_id NOT IN (0, i1._id)) AS unchecked_children_count, 

    // get the closest deadlines among the children : 
    // if there is a date but no time, time is set to 00:00:00 
    // if there is a time but not date, date is set to today 
    // if there is no date nor time, both are set to an empty string 

    // date 
    ifnull(nullif((SELECT ifnull(nullif(i3.date, ""), date()) AS subdate 
        FROM item AS i3 JOIN closure AS c3 ON (i3._id = c3.item_id) 
        WHERE c3.ancestor_id = i1._id 
        AND (i3.date OR i3.time) 
        ORDER By subdate, ifnull(nullif(i3.time, ""), "00:00:00") 
        LIMIT 1), ""), "") AS date, 

    // time   
    ifnull(nullif((SELECT ifnull(nullif(i4.time, ""), "00:00:00") AS subtime 
        FROM item AS i4 JOIN closure AS c4 ON (i4._id = c4.item_id) 
        WHERE c4.ancestor_id = i1._id 
        AND (i4.date OR i4.time) 
        ORDER By ifnull(nullif(i4.date, ""), date()), subtime 
        LIMIT 1), ""), "") AS time 

FROM item AS i1 JOIN closure AS c1 ON (i1._id = c1.ancestor_id) 
WHERE i1.parent_id = 0 
AND c1.item_id != 0 

GROUP BY c1.ancestor_id 

ORDER BY i1.checked, date, time 

Die Elemente sind in einem Baum mit einer Parent-ID und einer Verschlusstabelle organisiert.

Antwort

5
ORDER BY il.checked, 
     CASE WHEN date IS NULL AND time IS NULL THEN 1 ELSE 0 END, 
     date, time 
+0

dies war meine erste Idee, wird aber, dass die Arbeit auf Anhieb, dass Zeit und Datum angegeben Werte berechnet oder wird er die ganze Menge nach oben in einer inneren Abfrage wickeln müssen? –

+0

Probieren Sie es aus und sehen Sie. Ich vergesse immer, wann ich einen Spaltenalias verwenden kann und wann ich den Ausdruck wiederholen muss. In beiden Fällen benötigen Sie keine innere Abfrage, aber Sie müssen möglicherweise die Ausdrücke für Datum und Uhrzeit wiederholen. Wenn dies der Fall ist, können Sie eine innere Abfrage einfacher finden oder sie als einen Ausdruck kombinieren. –

+0

Danke, ich wusste nicht über den Fall/wann Anweisung. Standard SQL ist voller Überraschungen, ich bin ständig erstaunt, was Sie in einer Abfrage tun können, anstatt massive geschachtelte for-Schleifen und IF/ELSE zu verwenden :-) –

2

Sie könnten eine zusätzliche temp Spalte in einem eingepackten um alle Ihre sql erstellen, damit Sie eine künstliche Reihenfolge hinzufügen können.

SELECT 
    EACH_COLUMN 
    , ... 
    , CASE WHEN DATECol IS NULL AND TimeCol is NULL THEN 0 
     WHEN TimeCol is NULL THEN 1 
     WHEN DATECol IS NULL THEN 2 
     ELSE 3 END As ORDERCOL... 

FROM 
(
    INNER MESS OF ALL THE STUFF IN YOUR QUERY 
) 

ORDER BY 
    ORDERCol DESC --Preserves order of BothCols Populated, Null Dates Next, Null Times Next, Both Nulls Last 
    , Checked 
    , Date 
    , Time