SQL BETWEEN är en operator som används för att ange ett värdeintervall som ska testas. Det returnerade värdet kan vara inklusive eller inom intervallet. Eller det kan vara utanför intervallet om du lägger till NOT-operatorn före den. Det fungerar för datum, datum med tid, siffror och strängar.
Du kan använda den på WHERE-satser för följande:
- VÄLJ,
- INSERT (med SELECT)
- UPPDATERA,
- och DELETE.
Det fungerar även för HAVING-satser tillsammans med GROUP BY.
Men om du inte är försiktig kan SQL BETWEEN göra dig galen när du använder den, särskilt med datum med tid.
Oroa dig inte. Vi har exempel för att hantera gotchas i att använda SQL BETWEEN. Men innan dess kom provdatan jag använde från NOAA . Du kan begära väderdata gratis från dem. Jag använde timtemperaturposterna för USA år 2010. Sedan importerade jag CSV-data till SQL Server med SQL Server Management Studio. Jag döpte om kolumnerna och lade till ett icke-klustrat index.
Låt oss börja.
Använda SQL BETWEEN med datum och tider
Detta måste vara det mest sökta objektet när man hanterar SQL BETWEEN. Vi kommer att använda exempel för att förklara hur det fungerar.
Tips #1:För DATETIME-kolumner, ange både datum och tid
FEL ANVÄNDNING
Låt oss börja med fel användning för att betona denna punkt. Följande användning av BETWEEN med DATETIME-kolumner kommer att ge oväntade resultat.
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;
Frågan returnerar data för 2 dagar från en väderstation nära O’Hare International Airport i Chicago. Du kan se intervallet mellan ett lägre värde (01/01/2010) och ett högre värde (01/02/2010). Här är resultatet i figur 1.
Figur 1 . Resultatuppsättning av en fråga som använder SQL MELLAN 2 datum.
Men var är problemet?
Det är tänkt att vara ett timrekord i 2 dagar. På grund av det borde resultatuppsättningen ha 48 rekord. Men observera att det bara är 24. Problemet ligger i tidselementet i DateHour kolumn. När du inte anger tiden i en DATETIME-kolumn antar den 00:00 eller 12:00 AM. Observera också att uppgifterna startade den 1 januari 2010, klockan 01:00, inte 12:00.
Så internt använde SQL Server DateHour MELLAN ’01/01/2010 00:00:00.000′ OCH ’01/02/2010 00:00:00.000′ . Hur vet vi det?
DATUMET ÄR FAKTISKT EN STRÄNG
Det stämmer.
Datumvärdena inom enstaka citattecken är egentligen inte datum utan strängar . SQL Server använder implicit konvertering för att konvertera strängen till DATETIME. Efter konverteringen kommer tidsdelen att läggas till datumet.
Låt oss inspektera med Inkludera faktisk utförandeplan . Tryck på Ctrl-M i SQL Server Management Studio, kör sedan om föregående exempel.
När exekveringsplanen visas högerklickar du på Indexsökning operatorn och välj Egenskaper . Se figur 2.
Figur 2 . Implicit konvertering av en sträng till DATETIME. Den är gömd i exekveringsplanen för en fråga som använder BETWEEN.
Expandera sedan Seek Predicates . De inrutade delarna av figur 2 visar den implicita omvandlingen av de två strängarna till DATETIME. Eftersom implicit konvertering görs internt , nybörjare blir förvirrade varför deras förväntningar i resultatuppsättningen inte uppfylls.
KORREKT ANVÄNDNING
Exemplet nedan kommer att returnera timposterna mellan 08:00 och 12:00 den 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;
Du måste ange tidsdelen, särskilt när datumen är desamma. Eller så kommer dina förväntade resultat inte att hända.
Om du vill returnera posterna för hela dagen fungerar det inte:
SELECT
DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour = '06/01/2010'
AND Latitude = 41.995
AND Longitude = -87.9336;
Det kommer bara att returnera 1 post – den för 1 juni 2010, kl. 12:00. Men genom att använda BETWEEN med de angivna tiderna kan du returnera varje timmes rekord för hela dagen. Se nästa exempel.
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;
Observera att jag endast angav fram till 23:00. Om din data används någon tid på dygnet, använd 23:59 eller 23:59 i det högre värdet i intervallet. Ange även sekunderna om du behöver det.
Tips #2:Tänk på datatypen DATUM
Om du inte behöver tidsdelen, överväg datatypen DATE istället. Och du kommer att undvika problemen som nämns ovan.
SQL MELLAN med siffror
Låt oss gå vidare till siffror.
Tips #3:Inkludera decimaldelen för icke-heltalsvärden
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;
Notera tillägget av ett annat villkor som involverar siffror. Resultaten kommer vidare att begränsas till 5 och 7 grader.
När du använder datatyperna DECIMAL, MONEY eller FLOAT, ange decimaldelen även om den är noll, som 52,00 eller 10,0000. På detta sätt undviker du implicit konvertering till måldatatyperna DECIMAL, MONEY eller FLOAT.
SQL MELLAN med strängar
Tips #4:För strängar är intervallet baserat på sortering
Med strängar utvärderar BETWEEN värden baserat på alfabetisk ordning. 'A' är minst och 'Z' är störst. Man kan också säga att i allmänhet är utvärdering baserad på sammanställning. Eftersom engelska inte är det enda språket som SQL Server stöder. Sortering ger sorteringsregler, skiftläge och accentkänslighet. Låt oss använda AdventureWorks databas för detta exempel. Kolla in koden nedan och resultatet i figur 3.
USE AdventureWorks
GO
SELECT
LastName
,FirstName
,MiddleName
FROM Person.Person
WHERE Lastname BETWEEN 'Spanaway' AND 'Splane'
ORDER BY LastName;
Figur 3 . Resultatuppsättning av en fråga som använder BETWEEN med strängar.
Området täcker efternamnet Spanaway . Men var är Splane ? Det finns inte i databasen. Så resultatet nådde bara upp till Spicer .
SQL MELLAN Tips för alla datatyper som stöds
Oavsett om du använder BETWEEN för datum, siffror eller strängar, finns det vanliga saker du bör vara medveten om. Detta kan vara sunt förnuft, men det händer ändå av misstag. Läs om hur detta kan hända.
Tips #5:Både start- och slutvärden kan inte vara NULL
BETWEEN behöver start- och slutvärden för intervallet. Var och en ska ha ett värde som inte är NULL. Det finns ett exempel med ett NULL-slutvärde nedan.
SELECT
DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour BETWEEN '01/01/2010' AND NULL;
Detta kan hända om du anropar SELECT-satsen från en app eller en lagrad procedur och du inte validerade den ordentligt.
Tips #6:Startvärdet kan inte vara högre än slutvärdet
Ingenting kommer också att returneras om båda värdena inte är NULL, men intervallet är omvänt. Här är ett exempel.
SELECT
DateHour
,Hourly_Heating_Degree_Hours
FROM TemperatureData
WHERE DateHour BETWEEN '01/30/2010' AND '01/01/2010';
Bortsett från datum kommer följande uttryck inte heller att returnera ett resultat:
- värde MELLAN 100 OCH -200. Eftersom -200 är lägre än 100.
- arbeta MELLAN 'Zookeeper' OCH 'Revisor'. Eftersom 'Z' är större än 'A'.
Tips #7:Områdesvärden bör vara samma datatyper
Ibland har användargränssnittskontroller oväntade resultat. Eller så har vi bara hämtat fel egendom. Och om vi inte kontrollerar det innan vi skickar det till SQL Server, kan en situation som denna inträffa:
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;
Ett konverteringsfel från en teckensträng till ett datum kommer att inträffa.
Så, lärdomen från tips #5 till #7 är att validera start- och slutvärdena för intervallet .
Tips #8:Använd INTE MELLAN för att utesluta värden
Tänk på ett annat exempel.
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);
Detta kommer att returnera månadsgenomsnittet från januari till juni men exkluderar maj. Att exkludera posterna för maj 2010 är möjliggjort av NOT BETWEEN. Här är resultatet i figur 4.
Figur 4 . Resultatuppsättning av en fråga som använder NOT BETWEEN.
SQL MELLAN Jämfört med andra operatörer
Tips #9:Använd IN om du behöver en lista och inte ett intervall
IN-operatorn bestämmer om ett värde matchar något värde i en lista eller underfråga. Samtidigt kontrollerar du att använda NOT IN om ett värde inte matchar.
Operatörerna BETWEEN och IN filtrerar data baserat på flera värden. Men skillnaden ligger i uppsättningen av värden som matchas. BETTWEEN använder ett intervall. Men IN använder kommaseparerade värden i en lista eller rader i en underfråga.
Kontrollera exemplet nedan.
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;
Titta på listan över värden som används av IN. Det behöver inte vara en lista med ökande värden. Det sista värdet i listan (3.7) är också det minsta bland siffrorna.
Tips #10:Välj mellan BETWEEN eller>=med <=
Vid körning konverterar SQL Server BETWEEN till>=med <=operatorer. Hur vet vi det?
Titta på koden nedan.
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;
Båda frågorna kommer att ha samma resultatuppsättning som den i figur 5.
Figur 5 . Resultatet har angetts med antingen BETWEEN eller>=med <=.
De har också samma utförandeplan, som ses i figur 6.
Figur 6 . Exekveringsplan med 2 frågor som jämför användningen av BETWEEN, och>=och <=operatorer.
Men här är grejen.
Lägg märke till det första indexet Sök operatorn i figur 6. Se sedan Sök predikat . Ser du nyckelordet BETWEEN? Det finns ingen, eller hur? Eftersom den konverteras till>=med <=operatorer. Det är de operatorer som finns i Seek Predicates .
Men det finns mer.
Om du för musen till den andra indexsökningen operatorn kommer du att se samma egenskaper som den första indexsökningen .
Så det verkar som om operatorn BETWEEN är en genväg till>=med <=operatorer . Du kommer att skriva mer om du använder det senare. Du kommer att se samma omvandling ske när BETWEEN används i siffror och strängar.
I slutändan är det upp till dig om du använder BETWEEN eller>=och <=operatorerna. Konverteringstiden det tar att konvertera BETWEEN är försumbar. Men om du fortfarande inte vill ha den extra, försumbara tiden, använd>=och <=operatorer.
Bottomline
SQL BETWEEN är bra för att hämta data inklusive intervallet. Och det är inte så svårt att använda. Även DATETIME-värdena är hanterbara med BETWEEN. Se bara till att täcka tidsdelen ordentligt. Det motsvarar också att använda>=med <=. Det är upp till dig vilken du föredrar att använda.
Du kan bokmärka den här sidan för att få SQL BETWEEN-tips för datum, siffror och strängar när du behöver dem.
Om du har några knep med BETWEEN som vi inte täckte, kan du dela dem med oss i kommentarsektionen. Och om du gillar den här artikeln, vänligen dela den genom att trycka på knapparna för sociala medier.
Lycka till med kodningen, alla!