Frage

Es muss einen besseren Weg Abfrage geschrieben wird.

Ich möchte Sie alle Daten zwischen zwei Datumsangaben.Im Idealfall werden die ersten und letzten Zeilen der Ergebnismenge möchten, werden diese angegeben, die in der WHERE-Klausel.Wenn diese Zeilen nicht vorhanden sind, möchte ich die Zeilen vorausgehenden und folgenden der angeforderte Bereich.

Ein Beispiel:

Wenn meine Daten:

...
135321, 20090311 10:15:00
135321, 20090311 10:45:00
135321, 20090311 11:00:00
135321, 20090311 11:15:00
135321, 20090311 11:30:00
135321, 20090311 12:30:00
...

Und die Abfrage ist:

    SELECT * 
    FROM data_bahf 
    WHERE param_id = 135321 
    AND datetime >= '20090311 10:30:00' 
    AND datetime <= '20090311 12:00:00'

Ich möchte die zurückgegebenen Daten umfassen die Zeile bei 10:15 und von 12:30 Uhr.Nicht nur diejenigen, streng erfüllen die WHERE-Klausel.

Dies ist die beste, die ich mir ausgedacht habe.

SELECT * FROM (
    SELECT * 
    FROM data_bahf 
    WHERE param_id = 135321 
    AND datetime > '20090311 10:30:00' 
    AND datetime < '20090311 12:00:00'

    UNION

    (
        SELECT * FROM data_bahf 
        WHERE param_id = 135321 
        AND datetime <= '20090311 10:30:00' 
        ORDER BY datetime desc
        LIMIT 1
    )

    UNION

    (
        SELECT * FROM data_bahf 
        WHERE param_id = 135321 
        AND datetime >= '20090311 12:00:00'
        ORDER BY datetime asc
        LIMIT 1
    )
) 
AS A
ORDER BY datetime

(Ignorieren Sie die Verwendung von SELECT * für jetzt)

EDIT:Ich habe Indizes für param_id, datetime, und (param_id, datetime)

War es hilfreich?

Lösung

Erstens, stellen Sie sicher, dass Sie ein composite index (param_id, datetime)

Zweite, eine Abfrage wie diese:

SELECT  *
FROM    data_bahf
WHERE   param_id = 135321
        AND datetime BETWEEN
        COALESCE(
        (
        SELECT  MAX(datetime)
        FROM    data_bahf
        WHERE   param_id = 135321
              AND datetime <= '2009-01-01 00:00:00'
        ), '0001-01-01')
        AND 
        COALESCE(
        (
        SELECT  MIN(datetime)
        FROM    data_bahf
        WHERE   param_id = 135321
              AND datetime >= '2009-01-02 00:00:00'
        ), '9999-01-01')

Gerade nachgeschaut, es läuft in 1.215 ms für eine Beispieltabelle 200,000 Zeilen

Andere Tipps

Ich würde sagen:

SELECT 
  o.* 
FROM 
  data_bahf o
WHERE 
  o.param_id = 135321 
  AND o.datetime BETWEEN
  ISNULL(
    (
      SELECT   MAX(datetime) 
      FROM     data_bahf i
      WHERE    i.param_id = 135321 AND i.datetime <= '20090311 10:30:00'
    ),
    '0001-01-01 00:00:00'
  )
  AND
  ISNULL(
    (
      SELECT   MIN(datetime) 
      FROM     data_bahf i
      WHERE    i.param_id = 135321 AND i.datetime >= '20090311 12:00:00'
    ),
    '9999-12-31 23:59:59'
  )

EDIT:Fallback Hinzugefügt.
Wenn es keine Zeile passend zu den sub-Abfrage, es wird Ergebnis in eine NULL Wert, die gefangen werden müssen, indem ISNULL() oder BETWEEN Betreiber fehl, und der Haupt Abfrage keine Zeilen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top