Frage

Ich verwende DATEDIFF in einer SQL-Anweisung.Ich wähle es aus und muss es auch in der WHERE-Klausel verwenden.Diese Aussage funktioniert nicht...

SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
WHERE InitialSave <= 10

Es gibt die Botschaft: Ungültiger Spaltenname „InitialSave“

Aber diese Aussage funktioniert gut ...

SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable
WHERE DATEDIFF(ss, BegTime, EndTime) <= 10

Der Programmierer in mir sagt, dass dies ineffizient ist (es scheint, als würde ich die Funktion zweimal aufrufen).

Also zwei Fragen.Warum funktioniert die erste Aussage nicht?Ist es ineffizient, dies mit der zweiten Anweisung zu tun?

War es hilfreich?

Lösung

Sie können keine Spalten in der SELECT-Anweisung in der where-Anweisung definiert zugreifen, da sie bis nicht erzeugt ist, nachdem die in dem ausgeführt wird.

Sie können dies jedoch tun

select InitialSave from 
(SELECT DATEDIFF(ss, BegTime, EndTime) AS InitialSave
FROM MyTable) aTable
WHERE InitialSave <= 10

Als Nebenbei bemerkt - das bewegt sich im Wesentlichen die DATEDIFF in die where-Anweisung in Bezug auf, wo es zuerst definiert. Mit Funktionen auf Spalten in denen Aussagen verursachen Indizes nicht so effizient genutzt werden und sollen jedoch nach Möglichkeit vermieden werden, wenn Sie verwenden haben datediff dann haben Sie, es zu tun!

Andere Tipps

Hinweis: Wenn ich ursprünglich schrieb diese Antwort, die ich sagte, dass ein Index für eine der Spalten eine Abfrage erstellen können, die als andere Antworten zu besseren Ergebnissen führt (und erwähnte Dan Fuller). Allerdings war ich nicht richtig denken zu 100%. Tatsache ist, dass ohne eine berechnete Spalte oder indiziert (materialisiert) Ansicht, ein Full Table Scan sein wird, erforderlich , weil die beiden Datumsspalten verglichen werden, sind von der gleichen Tabelle!

Ich glaube, es immer noch Wert in den unten angegebenen Informationen, nämlich 1) die Möglichkeit einer verbesserten Leistung in der richtigen Situation, wie wenn der Vergleich zwischen den Säulen aus verschiedenen Tabellen ist, und 2) die Förderung die Gewohnheit in SQL-Entwickler von folgendem Best Praxis und Umformen ihres Denkens in der richtigen Richtung.

Herstellungsbedingungen sargable

Die beste Praxis Ich beziehe mich gehört eine Spalte zu bewegen allein auf einer Seite des Vergleichsoperators zu sein, etwa so:

SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM dbo.MyTable T
WHERE T.EndTime <= T.BegTime + '00:00:10'

Wie gesagt, wird dies nicht einen Scan auf einer einzigen Tabelle vermeiden, aber wie dies in einer Situation, es einen großen Unterschied machen könnte:

SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM
   dbo.BeginTime B
   INNER JOIN dbo.EndTime E
      ON B.BeginTime <= E.EndTime
      AND B.BeginTime + '00:00:10' > E.EndTime

ist EndTime in beiden Bedingungen jetzt allein auf der einen Seite des Vergleichs. Unter der Annahme, dass die BeginTime Tabelle viele weniger Zeilen hat, und die EndTime Tabelle hat einen Index für Spalte EndTime, wird solches DateDiff(second, B.BeginTime, E.EndTime) weit, weit besser als alles, was verwendet wird. Es ist jetzt sargable , was bedeutet, ein gültiges ist "Suchargument" - so wie der Motor Scans der BeginTime Tisch, kann es suchen in die EndTime Tabelle. Eine sorgfältige Auswahl, welche Kolonne allein schon auf der einen Seite des Bedieners erforderlich ist - kann es sich lohnen, das Experimentieren von BeginTime selbst setzen, indem Sie einige Algebra zu tun wechseln AND B.BeginTime > E.EndTime - '00:00:10'

Die Genauigkeit der DateDiff

Ich möchte auch darauf hinweisen, dass DateDiff nicht zurück verstrichene Zeit, sondern zählt die Anzahl der Grenzen gekreuzt. Wenn ein Anruf unter Verwendung von Sekunden DateDiff 1 zurückkehrt, könnte dies 3 ms verstrichene Zeit bedeuten, oder es könnte 1997 ms bedeuten! Dies ist im Wesentlichen eine Genauigkeit von + - 1 Zeiteinheit. Für die bessere Genauigkeit von + - 1/2 Zeiteinheit, würden Sie die folgende Abfrage zu vergleichen 0 wollen EndTime - BegTime:

SELECT DateDiff(second, 0, EndTime - BegTime) AS InitialSave
FROM MyTable
WHERE EndTime <= BegTime + '00:00:10'

Dies hat nun einen maximalen Rundungsfehler von nur einer Sekunde insgesamt, nicht von zwei (in der Tat ein Boden () Betrieb). Beachten Sie, dass Sie nur den datetime Datentyp subtrahieren können - ein date oder einen time Wert subtrahieren Sie die bessere Präzision (eine ganze Menge datetime, DateAdd zu bekommen und möglicherweise auch andere Junk DateDiff oder andere Methoden müßten konvertieren zu verwenden, oder vielleicht eine höhere Präzision Zeiteinheit mit und Dividieren).

Dieses Prinzip ist besonders wichtig, wenn größere Einheiten zu zählen, wie Stunden, Tage oder Monate. Ein DateDiff von 1 month 62 Tage auseinander liegen könnte (man denke 1. Juli 2013 - 31. August 2013)!

über die es "Arbeit", benötigen Sie einen Index verwenden

verwenden, um eine berechnete Spalte mit einem Index oder eine Ansicht mit einem Index, sonst werden Sie Table-Scan. wenn Sie genug Reihen erhalten, fühlen Sie die PAIN der Slow-Scan!

berechnete Spalte & Index:

ALTER TABLE MyTable ADD
    ComputedDate  AS DATEDIFF(ss,BegTime, EndTime)
GO
CREATE NONCLUSTERED INDEX IX_MyTable_ComputedDate  ON MyTable 
    (
    ComputedDate
    ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

Erstellen Sie eine Ansicht & Index:

CREATE VIEW YourNewView
AS
SELECT
    KeyValues
        ,DATEDIFF(ss, BegTime, EndTime) AS InitialSave
    FROM MyTable
GO
CREATE CLUSTERED INDEX IX_YourNewView
    ON YourNewView(InitialSave)
GO

Sie müssen die Funktion anstelle des Spaltenalias verwenden – das Gleiche gilt für count(*) usw.PITA-BROT.

Als Alternative, können Sie berechnete Spalten .

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