none
GETDATE - Vorletzte Woche RRS feed

  • Frage

  • Hallo zusammen,

    Ich möchte in einer Abfrage alle Datensätze der vorletzten Woche ausgeben, bzw. die Datensätze der vorletzten 7 Tage.
    Das würde heissen:

    ("Heute" - 7 Tage ) ("ab hier" - die folgenden 7 Tage)

    Momentan geschieht dier per OFFSET 'Anzahl der Datensätze' FETCH NEXT 'Anzahl der Datensätze der letzten 7 Tage'

    Danke für eure Hilfe.

    Gruss,

    Enrique

    Montag, 25. Februar 2013 12:25

Antworten

Alle Antworten

  • Am 25.02.2013 13:25, schrieb Enrique Martin:
    > Hallo zusammen,
    >
    > Ich möchte in einer Abfrage alle Datensätze der vorletzten Woche
    > ausgeben, bzw. die Datensätze der vorletzten 7 Tage.
    > Das würde heissen:
    >
    > ("Heute" - 7 Tage ) ("ab hier" - die folgenden 7 Tage)
    >
    > Momentan geschieht dier per OFFSET 'Anzahl der Datensätze' FETCH NEXT
    > 'Anzahl der Datensätze der letzten 7 Tage'
     
    Nun die aktuelle Woche bekommst du mit
    DATEPART(week, GETDATE())
     
    Auf die Vorletzte müsstest du mit
    DATEPART(week, [DatumsSpalte]) = DATEPART(week, GETDATE())-2
    prüfen können.
     
    Du musst allerdings noch auf den Jahreswechsel achten, da dort die
    vorletzte Woche auch in den 50er sein kann und der Vergleich keine
    Treffer bringt.
    Eventuell klappt dann die Prüfung
    DATEPART(week, [DatumsSpalte]) = DATEPART(week, GETDATE()-14)
     
    Hab ich jetzt nicht getestet ... schau mal ob das dir hilft.
     
    Montag, 25. Februar 2013 12:33
  • Hat mir leider noch nicht weitergeholfen, aber ich danke für deine Antwort.

    Kann ich dies nicht irgendwie in die WHERE-Clausel einbauen.

    WHERE DATE <= ......
    AND DATE >= .....

    Danke!

    Montag, 25. Februar 2013 14:56
  • Ja, du kannst das in der WHERE Klausel einbauen: WHERE DateColumn >= DATEADD(DAY, -7, GETDATE()) AND DateColumn <= GETDATE().

    Abhängig von der genauen Anforderung solltest du evtl. den Zeitanteil aus GETDATE() und der DateColumn herausfiltern.


    -- Frank Kalis Microsoft SQL Server MVP Webmaster: http://www.insidesql.org

    Montag, 25. Februar 2013 15:09
  • Am 25.02.2013 15:56, schrieb Enrique Martin:
    > Hat mir leider noch nicht weitergeholfen, aber ich danke für deine Antwort.
    >
    > Kann ich dies nicht irgendwie in die WHERE-Clausel einbauen.
    >
    > WHERE DATE <= ......
    > AND DATE >= .....
     
    ... WHERE DATEPART(week, [DATE]) = DATEPART(week, GETDATE()-14)
     
    Am Besten vielleicht den Teil DATEPART(week, GETDATE()-14) auswerten und
    direkt darauf vergleichen
    ... WHERE DATEPART(week, [DATE]) = 7
     
    Aber irgendwie bin ich noch nicht sicher welchen Datumsbereich du nun
    konkret suchst.
     
    Montag, 25. Februar 2013 15:52
  • Hallo Enrique,

    ja, das geht relativ einfach

    SELECT * FROM dbo.DeineTable
    WHERE Datumsfeld >= DATEADD(day, -14, getdate() AND Datumsfeld <= DATEADD(day, -7, getdate()).

    Der Vorschlag von Lutz ist nicht schlecht aber leider für Abfragen ein absoluter Killer, da durch diese Verwendung sogenannte non SARGable Abfragen generiert werden.

    Erklärung und Beispiele findest Du hier:

    http://db-berater.blogspot.de/2012/11/optimierung-von-datenbankmodellensargab.html


    Uwe Ricken

    MCSE - SQL Server 2012
    MCSA - SQL Server 2012
    MCITP Database Administrator 2005
    MCITP Database Administrator 2008
    MCITP Microsoft SQL Server 2008, Database Development

    db Berater GmbH
    http://www-db-berater.de
    SQL Server Blog (german only)


    Dienstag, 26. Februar 2013 09:28
  • Am 26.02.2013 10:28, schrieb Uwe Ricken:
    > Hallo Enrique,
    >
    > ja, das geht relativ einfach
    >
    > SELECT * FROM dbo.DeineTable
    > WHERE Datumsfeld >= DATEADD(day, -14, getdate() AND Datumsfeld <= DATEADD(day, -7, getdate()).
    >
    > Der Vorschlag von Lutz ist nicht schlecht aber leider für Abfragen ein
    > absoluter Killer, da durch diese Verwendung sogenannte non SARGable
    > Abfragen generiert werden.
    >
    > Erklärung und Beispiele findest Du hier:
    >
     
    Danke für die Info Uwe.
    Dann doch lieber deine Variante, wo man auch noch etwas flexibler mit
    dem Zeitraum sein kann.
     
    Bei meinem Vorschlag könnte man das vielleicht umgehen, wenn man eine
    berechnete Spalte PERSISTED anlegt - dann sollte die Abfrage auf das
    Feld SARGable sein.
    Allerdings funktionieren nur echte Wochen, nicht 7 Tage von Mittwoch zu
    Mittwoch.
     
     
    Dienstag, 26. Februar 2013 10:01
  • Bei meinem Vorschlag könnte man das vielleicht umgehen, wenn man eine
    berechnete Spalte PERSISTED anlegt - dann sollte die Abfrage auf das
    Feld SARGable sein.
    Allerdings funktionieren nur echte Wochen, nicht 7 Tage von Mittwoch zu
    Mittwoch.

    Nein, wahrscheinlich nicht. Dein Vorschlag mit der DATEPART Funktion wird (wahrscheinlich) ein Killer, weil der Optimierer einen evtl. vorhandenen Index nicht optimal nutzen kann.

    Als Erklärung und in Ergänzung zu Uwe's Link, lies dir das mal in Ruhe durch: http://sqlblog.com/blogs/rob_farley/archive/2010/01/21/sargable-functions-in-sql-server.aspx


    -- Frank Kalis Microsoft SQL Server MVP Webmaster: http://www.insidesql.org

    Dienstag, 26. Februar 2013 10:36
  • Am 26.02.2013 11:36, schrieb Frank Kalis [MVP]:
    >     Bei meinem Vorschlag könnte man das vielleicht umgehen, wenn man eine
    >     berechnete Spalte PERSISTED anlegt - dann sollte die Abfrage auf das
    >     Feld SARGable sein.
    >     Allerdings funktionieren nur echte Wochen, nicht 7 Tage von Mittwoch zu
    >     Mittwoch.
    >
    > Nein, wahrscheinlich nicht. Dein Vorschlag mit der DATEPART Funktion
    > wird (wahrscheinlich) ein Killer, weil der Optimierer einen evtl.
    > vorhandenen Index nicht optimal nutzen kann.
     
    Auch wenn wir jetzt etwas vom Thema abschweifen ...
     
    Ja aber das umgehe ich ja indem ich die Woche als INT abspeichere und
    dann einen Integer-Wert vergleiche. Die Berechnung selber erfolgt nur
    bei Änderung des Datensatzes.
     
    ALTER TABLE TABELLE
     ADD COLUMN [DATE_WEEK] AS DATEPART(week, [DATE]) PERSISTED
     
    ... WHERE [DATE_WEEK] = DATEPART(week, GETDATE()-14)
     
    Oder bin ich da auf dem Holzweg?
     
     
    Dienstag, 26. Februar 2013 12:25
  • Hallo Lutz,

    damit bist Du leider auf dem Holzweg, da datepart in Verbindung mit week einen Fehler liefert.

    ALTER TABLE dbo.index_table
    ADD col_datecw AS DATEPART(week, coldate) PERSISTED;
    Msg 4936, Level 16, State 1, Line 1
    Computed column 'col_datecw' in table 'index_table' cannot be persisted because the column is non-deterministic.

    Dennoch ist die Idee nicht schlecht. Man kann tatsächlich mit einem Index auf einem kalkulierten Attribut arbeiten. I. d. R. wird er auch verwendet!

    USE tempdb
    GO
    DROP TABLE dbo.index_table;
    GO
    CREATE TABLE dbo.index_table
    (
    	id int	not null identity (1, 1),
    	colDate datetime not null DEFAULT (DATEDIFF(dd, RAND() * 1000, getdate()))
    	
    	CONSTRAINT pk_index_table PRIMARY KEY CLUSTERED (id)
    );
    SET NOCOUNT ON
    GO
    INSERT INTO dbo.index_table DEFAULT VALUES
    GO 10000
    SELECT * FROM dbo.index_table
    WHERE	colDate >= DATEADD(dd, -14, getdate()) AND
    	colDate <= DATEADD(dd, -7, getdate())
    		
    CREATE INDEX ix_index_table_coldate ON dbo.index_table (coldate);
    SELECT * FROM dbo.index_table
    WHERE	colDate >= DATEADD(dd, -14, getdate()) AND
    	colDate <= DATEADD(dd, -7, getdate())


    Das obige Beispiel erstellt eine einfache Tabelle führt die von mir gemachte Abfrage einmal aus. Anschließend wird ein Index auf das Attribute coldate platziert um zu zeigen, dass eine Optimierung auf diesem Attribut stattfinde. Das Ergebnis des Ausführungsplans sieht dann wie folgt aus: 

    Man kann sehr gut erkennen, dass bei Abfrage 1 ein Table Scan ausgeführt wird, während bei der zweiten Abfrage der zuvor gesetzte Index verwendet wird. Somit wäre das - zunächst - eine sehr gute Lösung.

    Nun füge ich ein berechnetes Attribut ein (als Beispiel Jahr des Datums) und setze auf dieses Attribut eine Index. Wichtig ist dabei, dass das Attribut PERSISTED angelegt wird:

    -- Now we create a persistent column which stores the datediff
    ALTER TABLE dbo.index_table
    ADD col_dateyear AS CAST(DATEPART(year, coldate) AS int) PERSISTED;
    CREATE INDEX ix_index_table_year ON dbo.index_table (col_dateyear);

    Die Ausführung auf das Jahr 2013 sieht dann wie folgt aus:

    Es wird ein INDEX-SEEK unter Verwendung des zuvor angelegten Indexes durchgeführt. Wichtig für die Ausführungstrategie ist nicht der Index allein sondern auch die Histogrammdaten aus DBCC SHOW_STATISTICS () WITH HISTOGRAM. Ist der abzufragende Bereich >= 30% der Gesamtdatenmenge, wird wieder ein Index-Scan ausgeführt!

    Ob und welcher Index verwendet wird, hängt immer davon ab, wie der Index selbst definiert ist. Würde ich z. B. auch noch das Attribut coldate in die Abfrage einbeziehen, kann es sein, dass SQL Server trotz des performanten Index auf col_dateyear einen Clustered Index Scan durchführt, um so die teureren Bookmark-Lookups zu vermeiden. Das ist ein sehr komplexes Thema und ich glaube, ich sollte dazu mal was in meinem Blog schreiben :D


    Uwe Ricken

    MCSE - SQL Server 2012
    MCSA - SQL Server 2012
    MCITP Database Administrator 2005
    MCITP Database Administrator 2008
    MCITP Microsoft SQL Server 2008, Database Development

    db Berater GmbH
    http://www-db-berater.de
    SQL Server Blog (german only)


    Dienstag, 26. Februar 2013 12:59
  • Am 26.02.2013 13:59, schrieb Uwe Ricken:
    > Hallo Lutz,
    >
    > damit bist Du leider auf dem Holzweg, da datepart in Verbindung mit week
    > einen Fehler liefert.
    >
    > ALTER TABLE dbo.index_table
    > ADD col_datecw AS DATEPART(week, coldate) PERSISTED;
    > Msg 4936, Level 16, State 1, Line 1
    > Computed column 'col_datecw' in table 'index_table' cannot be persisted because the column is non-deterministic.
     
    Daran habe ich gar nicht gedacht, habe es aber ehrlich gesagt auch nicht
    ausprobiert. Ursache wird die Abhängigkeit von SET DATEFIRST sein.
    Aber selbst da gibt es Abhilfe:
    DATEPART(iso_week, coldate) funktioniert als permanente berechnete Spalte.
     
    > Dennoch ist die Idee nicht schlecht. Man kann tatsächlich mit einem
    > Index auf einem kalkulierten Attribut arbeiten. I. d. R. wird er auch
    > verwendet!
    >
    > ... ausführliche Abhandlung zum Thema ;)
    >
    > Das ist
    > ein sehr komplexes Thema und ich glaube, ich sollte dazu mal was in
    > meinem Blog schreiben :D
     
    Danke für die Ausführungen und einen Blog-Eintrag dazu kann ich nur
    begrüßen ;)
     
     
    Dienstag, 26. Februar 2013 13:35
  • Am 26.02.2013 11:36, schrieb Frank Kalis [MVP]:
    >     Bei meinem Vorschlag könnte man das vielleicht umgehen, wenn man eine
    >     berechnete Spalte PERSISTED anlegt - dann sollte die Abfrage auf das
    >     Feld SARGable sein.
    >     Allerdings funktionieren nur echte Wochen, nicht 7 Tage von Mittwoch zu
    >     Mittwoch.
    >
    > Nein, wahrscheinlich nicht. Dein Vorschlag mit der DATEPART Funktion
    > wird (wahrscheinlich) ein Killer, weil der Optimierer einen evtl.
    > vorhandenen Index nicht optimal nutzen kann.
    Auch wenn wir jetzt etwas vom Thema abschweifen ...
    Ja aber das umgehe ich ja indem ich die Woche als INT abspeichere und
    dann einen Integer-Wert vergleiche. Die Berechnung selber erfolgt nur
    bei Änderung des Datensatzes.
    ALTER TABLE TABELLE
     ADD COLUMN [DATE_WEEK] AS DATEPART(week, [DATE]) PERSISTED
    ... WHERE [DATE_WEEK] = DATEPART(week, GETDATE()-14)
    Oder bin ich da auf dem Holzweg?
    Mal ganz abgesehen davon, wie jetzt die Ermittlung der Woche in der berechneten Spalte selber erfolgt, erscheint es mir fragwürdig, diese weitere Spalte zu verwenden und damit die Tabellenstruktur aufzublasen nur um damit mehr oder weniger redundant die Daten zu halten, die du bereits in der Date(Time) Spalte hast. Die eine Information kann man ohne grosse Probleme aus der anderen ableiten und von daher würde ich nicht mit so einem Design starten. Evtl. ergeben sich später gewisse Notwendigkeiten, weshalb man so eine "Denormalisierung" in Betracht ziehen könnte, aber das ist dann wieder eine andere Geschichte. :-)

    -- Frank Kalis Microsoft SQL Server MVP Webmaster: http://www.insidesql.org

    Dienstag, 26. Februar 2013 15:54