sql >> Database >  >> RDS >> Sqlserver

Verkrijg de records van de afgelopen maand in SQL-server

Alle bestaande (werkende) antwoorden hebben een van de volgende twee problemen:

  1. Ze negeren indices in de kolom waarin wordt gezocht
  2. Het zal (potentieel) gegevens selecteren die niet bedoeld zijn, waardoor uw resultaten in stilte worden beschadigd.

1. Genegeerde indexen:

Voor het grootste deel, wanneer een kolom die wordt doorzocht een functie heeft die wordt aangeroepen (inclusief impliciet, zoals voor CAST ), moet de optimizer indexen op de kolom negeren en door elk record zoeken. Hier is een snel voorbeeld:

We hebben te maken met tijdstempels en de meeste RDBMS'en hebben de neiging om deze informatie op te slaan als een of andere toenemende waarde, meestal een long of BIGINTEGER telling van milli-/nanoseconden. De huidige tijd ziet/wordt dus als volgt opgeslagen:

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

U ziet de waarde 'Jaar' niet ('2014' ) daarbinnen, jij ook? In feite is er nogal wat ingewikkelde wiskunde om heen en weer te vertalen. Dus als u een van de extractie-/datumgedeeltefuncties in de gezochte kolom aanroept, moet de server al die wiskunde uitvoeren om erachter te komen of u het in de resultaten kunt opnemen. Op kleine tafels is dit geen probleem, maar naarmate het percentage geselecteerde rijen afneemt, wordt dit een steeds grotere afvoer. In dit geval doe je het een tweede keer door te vragen naar MONTH ... nou, je snapt het wel.

2. Onbedoelde gegevens:

Afhankelijk van de specifieke versie van SQL Server en kolomgegevenstypes, met behulp van BETWEEN (of vergelijkbare inclusief bovengrenzen:<= ) kan ertoe leiden dat de verkeerde gegevens worden geselecteerd. In wezen neemt u mogelijk gegevens op van middernacht van de "volgende" dag, of sluit u een deel van de records van de "huidige" dag uit.

Wat u moet doen:

We hebben dus een manier nodig die veilig is voor onze gegevens en die gebruikmaakt van indices (indien haalbaar). De juiste manier is dan van de vorm:

WHERE date_created >= @startOfPreviousMonth AND date_created < @startOfCurrentMonth

Aangezien er maar één maand is, @startOfPreviousMonth kan gemakkelijk worden vervangen door/afgeleid door:

DATEADD(month, -1, @startOCurrentfMonth)

Als u het begin van de huidige maand in de server moet afleiden, kunt u dit als volgt doen:

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

Hier even een korte uitleg. De initiële DATEDIFF(...) krijgt het verschil tussen het begin van het huidige tijdperk (0001-01-01 - AD, CE, wat dan ook), die in wezen een groot geheel getal retourneert. Dit is het aantal maanden tot het begin van de huidige maand. We voegen dit getal vervolgens toe aan het begin van het tijdperk, dat is aan het begin van de opgegeven maand.

Dus je volledige script zou er ongeveer als volgt uit kunnen/moeten zien:

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

Alle datumbewerkingen worden dus maar één keer uitgevoerd, op één waarde; de optimizer is vrij om indexen te gebruiken en er worden geen onjuiste gegevens opgenomen.



  1. Hoe de huidige instelling voor null-uitvoer in PostgreSQL (psql) te tonen

  2. Data-analyse versus datawetenschap:wat is het verschil?

  3. Hoe het totale aantal geretourneerde rijen opnemen in de resultatenset van de opdracht SELECT T-SQL?

  4. Hoe verbinding maken met mssql met behulp van pdo via PHP en Linux?