Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Pobierz rekordy z ostatniego miesiąca na serwerze SQL

Wszystkie istniejące (działające) odpowiedzi mają jeden z dwóch problemów:

  1. Zignorują indeksy w przeszukiwanej kolumnie
  2. Będzie (potencjalnie) wybiera dane, które nie są zamierzone, po cichu psując wyniki.

1. Ignorowane indeksy:

W większości przypadków, gdy przeszukiwana kolumna ma wywołaną funkcję (w tym niejawnie, jak dla CAST ), optymalizator musi zignorować indeksy w kolumnie i przeszukać każdy rekord. Oto krótki przykład:

Mamy do czynienia ze znacznikami czasu, a większość RDBMS przechowuje te informacje jako pewnego rodzaju rosnącą wartość, zwykle long lub BIGINTEGER liczba mili-/nanosekund. Aktualny czas wygląda więc/jest przechowywany w następujący sposób:

1402401635000000  -- 2014-06-10 12:00:35.000000 GMT

Nie widzisz wartości „Rok” ('2014' ) tam, prawda? W rzeczywistości jest sporo skomplikowanej matematyki do przetłumaczenia tam iz powrotem. Więc jeśli wywołasz jakąkolwiek funkcję wyodrębniania/części daty w przeszukiwanej kolumnie, serwer musi wykonać całą tę matematykę tylko po to, aby dowiedzieć się, czy możesz uwzględnić ją w wynikach. Na małych stołach nie stanowi to problemu, ale wraz ze spadkiem odsetka wybranych rzędów staje się to coraz większym drenażem. W tym przypadku robisz to po raz drugi, pytając o MONTH ... cóż, masz obraz.

2. Niezamierzone dane:

W zależności od konkretnej wersji SQL Server i typów danych kolumn, używając BETWEEN (lub podobne włącznie górne zakresy:<= ) może spowodować wybranie niewłaściwych danych. Zasadniczo potencjalnie możesz włączyć dane z północy „następnego” dnia lub wykluczyć część rekordów „bieżącego” dnia.

Co powinnaś robić:

Potrzebujemy więc sposobu, który będzie bezpieczny dla naszych danych i będzie korzystał z indeksów (jeśli jest to wykonalne). Prawidłowy sposób ma więc postać:

WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth

Biorąc pod uwagę, że jest tylko jeden miesiąc, @startOfPreviousMonth można łatwo zastąpić/wyprowadzić przez:

DATEADD(month, -1, @startOCurrentfMonth)

Jeśli chcesz uzyskać na serwerze początek bieżącego miesiąca, możesz to zrobić w następujący sposób:

DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)

Tutaj krótkie wyjaśnienie. Początkowy DATEDIFF(...) otrzyma różnicę między początkiem bieżącej ery (0001-01-01 - AD, CE, cokolwiek), zasadniczo zwraca dużą liczbę całkowitą. Jest to liczba miesięcy do rozpoczęcia bieżącego miesiąc. Następnie dodajemy tę liczbę do początku ery, czyli na początku danego miesiąca.

Twój pełny skrypt mógłby/powinien wyglądać podobnie do następującego:

DECLARE @startOfCurrentMonth DATETIME
SET @startOfCurrentMonth = DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)

SELECT *
FROM Member
WHERE date_created >= DATEADD(month, -1, @startOfCurrentMonth) -- this was originally    misspelled
      AND date_created < @startOfCurrentMonth

Wszystkie operacje na datach są zatem wykonywane tylko raz, na jednej wartości; optymalizator może swobodnie używać indeksów i żadne nieprawidłowe dane nie zostaną uwzględnione.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Interfejsy sieciowe programu SQL Server:ciąg połączenia jest nieprawidłowy [87]

  2. Potrzebujesz pomocy w obliczeniach przy użyciu dwóch zestawów danych przy użyciu Expression SSRS

  3. Instrukcja ALTER TABLE kolidowała z ograniczeniem FOREIGN KEY w SQL Server — SQL Sever / TSQL Tutorial, część 69

  4. Jak podzielić okno zapytania w SQL Server Management Studio (SSMS) — samouczek SQL Server / TSQL część 13

  5. Unikanie zakleszczeń SQL dzięki dostrajaniu zapytań:porady Brenta Ozara