sql >> Database >  >> RDS >> Database

SQL TUSSEN-Slimme tips om te scannen op een reeks waarden

SQL BETWEEN is een operator die wordt gebruikt om een ​​reeks waarden op te geven om te testen. De geretourneerde waarde kan inclusief of binnen het bereik zijn. Of het kan buiten het bereik vallen als u de operator NOT ervoor toevoegt. Het werkt voor datums, datums met tijd, getallen en tekenreeksen.

U kunt het gebruiken in WHERE-clausules voor het volgende:

  • SELECTEER,
  • INSERT (met SELECT)
  • UPDATE,
  • en VERWIJDEREN.

Het werkt ook voor HAVING-clausules samen met GROUP BY.

Maar als je niet oppast, kan SQL BETWEEN je gek maken als je het gebruikt, vooral met datums in de tijd.

Maak je echter geen zorgen. We hebben voorbeelden om met de valkuilen om te gaan bij het gebruik van SQL TUSSEN. Maar daarvoor waren de voorbeeldgegevens die ik gebruikte afkomstig van NOAA . U kunt bij hen gratis weergegevens opvragen. Ik gebruikte de uurlijkse temperatuurrecords voor de Verenigde Staten in het jaar 2010. Daarna importeerde ik de CSV-gegevens naar de SQL Server met behulp van SQL Server Management Studio. Ik heb de kolommen hernoemd en een niet-geclusterde index toegevoegd.

Laten we beginnen.

SQL TUSSEN gebruiken met datums en tijden

Dit moet het meest gezochte item zijn bij het omgaan met SQL TUSSEN. We zullen voorbeelden gebruiken om uit te leggen hoe het werkt.

Tip #1:Specificeer voor DATETIME-kolommen zowel de datum als de tijd

VERKEERD GEBRUIK

Laten we beginnen met het verkeerde gebruik om dit punt te benadrukken. Het volgende gebruik van BETWEEN met DATETIME-kolommen geeft onverwachte resultaten.


SELECT 
 DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour BETWEEN '01/01/2010' AND '01/02/2010'
AND Latitude = 41.995
AND Longitude = -87.9336;


De zoekopdracht retourneert gegevens voor 2 dagen van een weerstation in de buurt van de O'Hare International Airport in Chicago. U kunt het bereik zien tussen een lagere waarde (01/01/2010) en een hogere waarde (01/02/2010). Dit is het resultaat in Afbeelding 1.

Figuur 1 . Resultatenset van een query met SQL TUSSEN 2 datums.

Maar waar is het probleem?

Het zou een uurrecord zijn voor 2 dagen. Daarom moet de resultatenset 48 records bevatten. Maar merk op dat het er maar 24 zijn. Het probleem ligt bij het tijdselement van de DateHour kolom. Als u de tijd niet opgeeft in een DATETIME-kolom, wordt uitgegaan van 00:00 of 12:00 AM. Houd er ook rekening mee dat de gegevens zijn begonnen op 1 januari 2010, om 01:00 uur, niet om 12:00 uur.

Dus intern gebruikte SQL Server DateHour TUSSEN ’01/01/2010 00:00:00.000′ EN ’01/02/2010 00:00:00.000′ . Hoe weten we dat?

DE DATUM IS WERKELIJK EEN STRING

Dat klopt.

De datumwaarden tussen enkele aanhalingstekens zijn niet echt datums, maar tekenreeksen . SQL Server gebruikt impliciete conversie om de tekenreeks naar DATETIME te converteren. Na de conversie wordt het tijdgedeelte toegevoegd aan de datum.

Laten we eens kijken met Include Actual Execution Plan . Druk op Ctrl-M in SQL Server Management Studio en voer vervolgens het vorige voorbeeld opnieuw uit.

Wanneer het uitvoeringsplan verschijnt, klikt u met de rechtermuisknop op de Index Seek operator en selecteer Eigenschappen . Zie afbeelding 2.

Figuur 2 . Impliciete conversie van een string naar DATETIME. Het is verborgen in het uitvoeringsplan van een query met BETWEEN.

Vouw vervolgens de Predikaten zoeken . uit . De omkaderde delen van figuur 2 tonen de impliciete conversie van de 2 strings naar DATETIME. Aangezien impliciete conversie intern wordt gedaan , raken nieuwelingen in de war waarom hun verwachtingen in de resultatenset niet worden gehaald.

JUIST GEBRUIK

Het onderstaande voorbeeld retourneert de uurrecords tussen 8:00 en 12:00 uur op 2 januari 2010.


SELECT * FROM TemperatureData
WHERE DateHour BETWEEN '01/02/2010 08:00' AND '01/02/2010 12:00'
AND Latitude = 41.995
AND Longitude = -87.9336;


U moet het tijdsgedeelte specificeren, vooral wanneer datums hetzelfde zijn. Of uw verwachte resultaten zullen niet gebeuren.

Om de records voor de hele dag terug te geven, werkt dit niet:


SELECT 
 DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour = '06/01/2010'
AND Latitude = 41.995
AND Longitude = -87.9336;


Er wordt slechts 1 record geretourneerd - die van 1 juni 2010, om 00:00 uur. Maar door TUSSEN met de gespecificeerde tijden te gebruiken, kunt u elk uurrecord voor de hele dag retourneren. Zie het volgende voorbeeld.


SELECT 
 DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour BETWEEN '06/01/2010 00:00' AND '06/01/2010 23:00'
AND Latitude = 41.995
AND Longitude = -87.9336;


Merk op dat ik alleen tot 23.00 uur heb opgegeven. Als uw gegevens op elk moment van de dag worden gebruikt, gebruikt u 23:59 of 23:59 uur in de hogere waarde van het bereik. Geef ook de seconden op als je dat nodig hebt.

Tip #2:Houd rekening met het DATE-gegevenstype

Als u het tijdgedeelte niet nodig hebt, overweeg dan het gegevenstype DATE. En u vermijdt de hierboven genoemde problemen.

SQL TUSSEN met cijfers

Laten we verder gaan met cijfers.

Tip #3:voeg het decimale deel toe voor niet-gehele waarden


SELECT
 DateHour
,[Hourly_Heating_Degree_Hours]
FROM TemperatureData
WHERE DateHour BETWEEN '06/01/2010' AND '06/5/2010 23:00'
AND [Hourly_Heating_Degree_Hours] BETWEEN 5.0 AND 7.0
AND Latitude = 41.995
AND Longitude = -87.9336;


Let op de toevoeging van een andere voorwaarde met betrekking tot getallen. De resultaten worden verder beperkt tot 5 en 7 graden.

Als u DECIMAL-, MONEY- of FLOAT-gegevenstypen gebruikt, geeft u het decimale deel op, zelfs als het nul is, zoals 52,00 of 10.0000. Op deze manier vermijd je impliciete conversie naar de doeldatatypen DECIMAL, MONEY of FLOAT.

SQL TUSSEN met strings

Tip #4:voor strings is het bereik gebaseerd op sortering

Met strings evalueert BETWEEN waarden op alfabetische volgorde. 'A' is de minste en 'Z' is de grootste. Je kunt ook zeggen dat evaluatie in het algemeen gebaseerd is op collatie. Omdat Engels niet de enige taal is die SQL Server ondersteunt. Collatie biedt sorteerregels, hoofdlettergevoeligheid en accentgevoeligheid. Laten we de AdventureWorks . gebruiken database voor dit voorbeeld. Bekijk de onderstaande code en het resultaat in figuur 3.


USE AdventureWorks
GO

SELECT 
 LastName
,FirstName
,MiddleName
FROM Person.Person
WHERE Lastname BETWEEN 'Spanaway' AND 'Splane'
ORDER BY LastName;

Figuur 3 . Resultatenset van een zoekopdracht met BETWEEN met tekenreeksen.

Het bereik omvat de achternaam Spanaway . Maar waar is Splane ? Het komt niet voor in de database. Het resultaat bereikte dus slechts tot Spicer .

SQL TUSSEN Tips voor alle ondersteunde gegevenstypen

Of je nu BETWEEN gebruikt voor datums, getallen of tekenreeksen, er zijn algemene dingen waar je op moet letten. Dit kan gezond verstand zijn, maar het gebeurt nog steeds per ongeluk. Lees hoe dit kan gebeuren.

Tip #5:zowel begin- als eindwaarden mogen niet NULL zijn

BETWEEN heeft begin- en eindwaarden nodig voor het bereik. Elk moet een waarde hebben die niet NULL is. Er is een voorbeeld met een NULL-eindwaarde hieronder.


SELECT 
 DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour BETWEEN '01/01/2010' AND NULL;


Dit kan gebeuren als u de SELECT-instructie aanroept vanuit een app of een opgeslagen procedure en u deze niet goed hebt gevalideerd.

Tip #6:de startwaarde kan niet groter zijn dan de eindwaarde

Er wordt ook niets geretourneerd als beide waarden niet NULL zijn, maar het bereik is omgekeerd. Hier is een voorbeeld.

SELECT 
 DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour BETWEEN '01/30/2010' AND '01/01/2010';


Afgezien van datums, zullen de volgende uitdrukkingen ook geen resultaat opleveren:

  • waarde TUSSEN 100 EN -200. Omdat -200 lager is dan 100.
  • werk TUSSEN ‘Zookeeper’ EN ‘Accountant’. Omdat 'Z' groter is dan 'A'.

Tip #7:Bereikwaarden moeten dezelfde gegevenstypen zijn

Soms hebben bedieningselementen van de gebruikersinterface onverwachte uitvoer. Of we hebben gewoon de verkeerde woning opgehaald. En als we het niet controleren voordat we het doorgeven aan SQL Server, kan een situatie als deze gebeuren:


SELECT 
 DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour BETWEEN '06/01/2010' AND 'Saturday, June 5, 2010'
AND Latitude = 41.995
AND Longitude = -87.9336;

Er zal een conversiefout optreden van een tekenreeks naar een datum.

De les van Tip #5 tot #7 is dus om de begin- en eindwaarden van het bereik te valideren .

Tip #8:Gebruik NIET TUSSEN om waarden uit te sluiten

Overweeg een ander voorbeeld.


SELECT
 MONTH(DateHour) AS [Month] 
,round(AVG([Hourly_Heating_Degree_Hours]),2) AS AverageTemperature
FROM TemperatureData
WHERE DateHour BETWEEN '01/01/2010 00:00' AND '06/30/2010 23:00'
AND DateHour NOT BETWEEN '05/01/2010 00:00' AND '05/31/2010 23:00'
AND Latitude = 41.995
AND Longitude = -87.9336
GROUP BY MONTH(DateHour);


Hiermee wordt het maandgemiddelde van januari tot juni geretourneerd, maar is mei exclusief. Het uitsluiten van de records voor mei 2010 wordt mogelijk gemaakt door NOT BETWEEN. Dit is het resultaat in Afbeelding 4.

Figuur 4 . Resultatenset van een zoekopdracht met NOT BETWEEN.

SQL TUSSEN Vergeleken met andere operators

Tip #9:gebruik IN als je een lijst nodig hebt en geen bereik

De IN-operator bepaalt of een waarde overeenkomt met een waarde in een lijst of subquery. Ondertussen controleert het gebruik van NOT IN of een waarde niet overeenkomt.

Zowel de BETWEEN- als de IN-operatoren filteren gegevens op basis van meerdere waarden. Maar het verschil zit hem in de reeks waarden die worden gematcht. BETWEEN maakt gebruik van een bereik. Maar IN gebruikt door komma's gescheiden waarden in een lijst of rijen in een subquery.

Bekijk het onderstaande voorbeeld.

SELECT
 DateHour
,[Hourly_Heating_Degree_Hours]
FROM TemperatureData
WHERE DateHour BETWEEN '06/01/2010' AND '06/5/2010 23:00'
AND [Hourly_Heating_Degree_Hours] IN (5.2, 6, 7, 3.7)
AND Latitude = 41.995
AND Longitude = -87.9336;


Kijk naar de lijst met waarden die door IN worden gebruikt. Het hoeft geen lijst met oplopende waarden te zijn. De laatste waarde in de lijst (3.7) is ook de minste van de getallen.

Tip #10:Kies uit TUSSEN of>=met <=

Tijdens runtime converteert SQL Server BETWEEN naar>=met <=operators. Hoe weten we dat?

Bekijk de onderstaande code.


SELECT
 DateHour
,AVG(Hourly_Heating_Degree_Hours) AS AverageTemp
FROM TemperatureData
WHERE DateHour BETWEEN '01/01/2010 08:00' AND '01/01/2010 12:00'
GROUP BY DateHour;

SELECT
 DateHour
,AVG(Hourly_Heating_Degree_Hours) AS AverageTemp
FROM TemperatureData
WHERE DateHour >= '01/01/2010 08:00' 
AND DateHour <= '01/01/2010 12:00'
GROUP BY DateHour;


Beide zoekopdrachten hebben hetzelfde resultaat als in Afbeelding 5.

Figuur 5 . Resultaat ingesteld met BETWEEN of>=met <=.

Ze hebben ook hetzelfde uitvoeringsplan, zoals te zien is in figuur 6.

Figuur 6 . Uitvoeringsplan van 2 zoekopdrachten waarin het gebruik van BETWEEN, en>=en <=operators wordt vergeleken.

Maar hier is het ding.

Let op de eerste Index Zoek operator in Afbeelding 6. Zie vervolgens de Zoekpredikaten . Zie je het trefwoord BETWEEN? Er is er geen, toch? Omdat het wordt geconverteerd naar>=met <=operators. Dat zijn de operators die aanwezig zijn in de Seek Predicates .

Maar er is meer.

Als u met uw muis naar de tweede Index Seek . gaat operator, ziet u dezelfde eigenschappen als de eerste Index Seek .

Het lijkt er dus op dat de operator BETWEEN een snelkoppeling is naar>=met <=operators . Je typt meer als je de laatste gebruikt. U zult dezelfde conversie zien gebeuren wanneer BETWEEN wordt gebruikt in cijfers en tekenreeksen.

Uiteindelijk is het aan jou of je BETWEEN of de operatoren>=en <=gebruikt. De conversietijd die nodig is om TUSSEN te converteren is te verwaarlozen. Maar als je die extra, verwaarloosbare tijd nog steeds niet wilt, gebruik dan>=en <=operators.

Kortom

SQL BETWEEN is goed voor het ophalen van gegevens inclusief het bereik. En het is niet zo moeilijk om te gebruiken. Zelfs de DATETIME-waarden zijn beheersbaar met BETWEEN. Zorg ervoor dat u het tijdsgedeelte goed afdekt. Het is ook gelijk aan het gebruik van>=met <=. Het is aan jou welke je het liefst gebruikt.

Je kunt een bladwijzer maken voor deze pagina om SQL TUSSEN-tips te krijgen voor datums, getallen en tekenreeksen wanneer je ze nodig hebt.

Als je TUSSEN trucs hebt die we niet hebben behandeld, kun je ze met ons delen in het gedeelte Opmerkingen. En als je dit artikel leuk vindt, deel het dan door op sociale media-knoppen te drukken.

Veel plezier met coderen, iedereen!


  1. Hoe kan ik de querycache van SQL Server wissen?

  2. Tel het aantal voorkomens van een string in een VARCHAR-veld?

  3. PostgreSQL-beheer en -automatisering met ClusterControl

  4. SQLT en partitionering