Först och främst kan du inte klara dig utan dem, eller hur?
SQL-datakonverteringar eller mer specifikt datatypkonverteringar är en viktig del av en databasutvecklares eller DBA:s vanliga programmeringsarbete.
Vad händer nu om din chef skrev på ett kontrakt med ett annat företag för att förse dem med en fil i textformat som kommer från din SQL Server-databas?
Det här låter som en spännande utmaning!
Men du fick reda på att du skulle behöva hantera ett datum till en sträng, ett nummer till en sträng och en massa andra SQL-datakonverteringar. Är du fortfarande redo för utmaningen?
Inte utan din arsenal av datakonverteringsknep!
Vad finns tillgängligt direkt?
När jag först började med T-SQL-programmering var det första jag såg som passade syftet med konverteringen KONVERTERING () funktion.
Dessutom finns ordet "konvertera" där, eller hur?
Även om detta kan vara sant, är det bara ett av de fyra sätten att utföra det här jobbet. Och jag använde den för nästan ALLA mina SQL-datakonverteringar. Jag är glad att jag kommit långt förbi det. Eftersom jag har lärt mig att de fyra metoderna har sin egen plats i din kod.
Innan vi kommer till ämnet för inlägget, låt mig presentera de fyra out-of-the-box-metoderna för att utföra SQL-datakonvertering:
- CAST ()
- KONVERTERA ()
- PARSE ()
- TRY_CAST (), TRY_CONVERT (), TRY_PARSE ()
Vart och ett av avsnitten nedan kommer:
- Förklara vad det är
- Berätta när du ska använda den (användningsfall)
- Presentera dess begränsningar
- Ge exempel och förklara det
Allt som presenteras i den här artikeln är på vanlig, enkel engelska så mycket som möjligt. När du har läst klart hela inlägget vet du vilken metod som är lämplig för en given situation.
Så, utan vidare, låt oss dyka in.
1. SQL-datakonvertering med CAST()
Även om alla metoder du kommer att se kan konvertera datatyper, bör ditt första val vid konvertering definitivt vara CAST ().
Här är anledningarna till varför:
- Det är den snabbaste konverteringsfunktionen av alla. Vi ska försöka bevisa detta senare i det här inlägget.
- Det ingår i SQL-92 språkspecifikationsstandarder. Så när du behöver portera din kod till andra SQL-produkter, som MySQL, är funktionen också tillgänglig.
Här är en mycket enkel syntax för CAST ():
CAST( <expression> AS <data_type>[(length)] )
Låt oss först undersöka syntaxen:
- <uttryck> är vilket giltigt uttryck som helst som resulterar i ett värde som kan konverteras till måldatatypen.
- <data_type> är måldatatypen.
- längd är valfritt och det hänför sig till storleken på data.
När ska den användas
Om det enda du behöver är att konvertera ett värde till en annan datatyp, CAST () är precis vad du behöver.
Begränsning
På den negativa sidan, CAST () kan inte ge dig en formaterad utdata direkt som ett formaterat datum- och tidsvärde.
Exempel
A. Konvertera en sträng till ett datum:
SELECT CAST('09/11/2004 4:30PM' as datetime2)
Och att köra ovanstående uttalande kommer att resultera i:
B. Konvertera ett tal till en sträng:
SELECT CAST(10.003458802 as varchar(max))
Och resultatet av ovanstående konvertering är:
Nu, om du behöver något annat som att formatera den konverterade datan, kan nästa metod hjälpa dig.
2. SQL-datakonvertering med CONVERT()
Nästa alternativ för datakonvertering är att använda CONVERT (). Som jag sa tidigare, det är den jag använde mest tidigare.
Här är syntaxen:
CONVERT( <data_type>[(length)], <expression> [, <style>])
Från syntaxen ovan, notera att <stilen> parametern är valfri. Och om du inte tillhandahåller det kommer funktionen att likna CAST ().
Det var där min förvirring började när jag var ny på SQL.
När ska den användas
Om du konverterar data med ett snabbformat, KONVERTERA () är din vän. Vilket innebär att du behandlar <stilen> parameter korrekt.
Begränsningar
- CAST () är snabbare än CONVERTERA (), så om du bara behöver konvertera data, använd CAST (). Om utdata ska formateras, använd KONVERTERA ().
- KONVERTERA () är inte en SQL-92-standard, så om du behöver porta den till andra RDBMS, undvik att använda den.
Exempel
A. Konvertera ett datum till ett strängformat ååååmmdd
I följande exempel kommer jag att använda exempeldatabasen AdventureWorks och omvandla [StartDatum ] kolumnen till ååååmmdd :
USE AdventureWorks
GO
SELECT
[BillOfMaterialsID]
,CONVERT(varchar(10), [StartDate],112) as StartDate
FROM [Production].BillOfMaterials]
GO
Observera att stil 112 används för att formatera datum till ååååmmdd .
B. Konvertera ett tal till en sträng med kommatecken på var tredje siffra till vänster om decimalkomma.
På liknande sätt kommer följande exempel att illustrera AdventureWorks exempeldatabas, så formaterar vi talet med kommatecken och med 2 decimaler.
USE AdventureWorks
GO
SELECT
[TransactionID]
,[ProductID]
,CONVERT(varchar(10),[TransactionDate] ,112) as StartDate
,[Quantity]
,CONVERT(varchar(10),[ActualCost],1) as ActualCost
FROM [Production].TransactionHistory
GO
Observera att format 1 används för [Faktisk kostnad ]. Och tack vare CONVERT (), kan vi formatera dessa kolumner på ett ögonblick.
Men vad händer om du behöver konvertera ett längre datumuttryck? Kommer att KONVERTERA () fungera i så fall? Läs vidare för att lära dig om nästa metod.
3. SQL-datakonvertering med PARSE()
Nästa metod vi ska överväga är PARSE ().
Kolla in syntaxen:
PARSE( <string value> AS <datatype> [USING <culture>])
När ska den användas
- För att konvertera strängar till datum eller siffror med en specifik kultur.
- När strängen inte kan konverteras till ett datum eller ett tal med CAST () eller KONVERTERA (). Se exemplen för mer information.
Begränsningar
- Konvertering är endast möjlig för sträng till datum och sträng till siffror
- Blir på närvaron av .Net Framework Common Language Runtime (CLR) på servern.
- Ingår inte i SQL-92 standardspecifikationer, så portering till andra RDBMS är ett problem.
- Har prestandaoverhead när det gäller att analysera strängen.
Exempel
A. Konvertera en lång datumsträng
SELECT PARSE('Monday, June 8, 2020' as datetime USING 'en-US')
Exemplet ovan är en lång datumsträng som ska konverteras till en datetime värde att använda amerikansk engelsk kultur. Och det är här PARSE () kommer att göra sitt bästa.
Det beror på att koden ovan kommer att misslyckas om du använder CAST () eller KONVERTERA ().
B. Konvertera ett penningvärde med en valutasymbol
SELECT PARSE('€1024,01' as money using 'de-DE')
Försök nu att göra omvandlingen med CAST () och KONVERTERA ()
SELECT CONVERT(money,'€1024,01')
SELECT CAST('€1024,01' as money)
Uttalandet kommer inte att skapa fel, ändå, ta en titt på detta oväntade resultat:
Som ett resultat av detta har värdet konverterats till 102401.00 istället för 1024.01.
Hittills har vi upptäckt att de tre första metoderna är benägna att göra fel om du inte kontrollerar dem. Ändå kan den fjärde metoden vara din lösning på det felaktiga resultatet.
4. SQL-datakonvertering med TRY_CAST(), TRY_CONVERT() eller TRY_PARSE()
Slutligen är den sista metoden för SQL-datakonvertering att använda en variant av de första 3 men med prefixet TRY_.
Men ändå, vad är skillnaden?
De har samma parametrar som de föregående 3 utan prefixet TRY_. Men skillnaden är att de returnerar NULL om värdet inte kan konverteras. Nu, om värdet inte kan konverteras av någon av de tre explicit, uppstår ett fel. Se exemplen nedan för en bättre förståelse.
När ska den användas
Du kan använda vilken som helst av de tre med villkorliga uttalanden som CASE NÄR eller IIF för att testa för fel.
Begränsningar
De tre av dem har samma begränsningar som de utan prefixet TRY_, förutom värden som inte kan konverteras.
Exempel
A. Använd TRY_CAST() för att testa om konverteringen kommer att lyckas med IIF:
SELECT IIF(TRY_CAST('111b' AS real) IS NULL, 'Cast failed', 'Cast succeeded') AS Result
Koden ovan returnerar "Cast misslyckades" eftersom "111b" inte kan konverteras till riktig . Ta bort "b" från värdet, och det kommer att returnera "Cast lyckad".
B. Använder TRY_CONVERT() på datum med ett specifikt format
SET DATEFORMAT dmy;
SELECT TRY_CONVERT(datetime2, '12/31/2010') AS Result
Detta kommer att returnera NULL eftersom formatet använder dmy eller dag-månad-år. Och inmatningsuttrycket för TRY_CONVERT () är i formatet mdy eller månad-dag-år. Felet utlöstes eftersom månadsvärdet är 31.
C. Använder TRY_PARSE() som genererar ett körtidsfel
SELECT
CASE WHEN TRY_PARSE('10/21/2133' AS smalldatetime USING 'en-US') IS NULL
THEN 'True'
ELSE 'False'
END AS Result
Den här koden kommer att generera ett körtidsfel enligt nedan:
Det är det för de 4 out-of-the-box-metoderna i SQL-datakonvertering. Men det kommer mer.
Vad sägs om SQL-datakonvertering med implicit konvertering?
Låt oss nu överväga implicit konvertering. Detta är en tyst metod.
Varför tyst?
För du kanske gör det redan, men du är omedveten om det. Eller åtminstone, du vet att det händer, men du ignorerar det.
Detta är med andra ord den typ av konvertering som SQL automatiskt gör utan några funktioner.
Låt mig ge dig ett exempel:
DECLARE @char CHAR(25)
DECLARE @varchar VARCHAR(25)
DECLARE @nvarchar NVARCHAR(25)
DECLARE @nchar NCHAR(25)
SET @char = 'Live long and prosper'
SET @varchar = @char
SET @nvarchar = @varchar
SET @nchar = @nvarchar
SELECT @char AS [char], @varchar AS [varchar], @nvarchar AS [nvarchar], @nchar AS [nchar]
Ovanstående kod kommer att exekveras framgångsrikt. Testa det själv så får du ett liknande resultat som det nedan:
Låt oss prova detta med datum:
DECLARE @datetime datetime
DECLARE @smalldatetime smalldatetime
DECLARE @datetime2 datetime2
SET @datetime = '12/31/2050 14:34'
SET @smalldatetime = @datetime
SET @datetime2 = @smalldatetime
SELECT @datetime as [datetime], @smalldatetime as [smalldatetime], @datetime2 as [datetime2]
Som förväntat kommer detta att ge ett framgångsrikt resultat:
Låt oss prova det den här gången med siffror:
DECLARE @int int
DECLARE @real real
DECLARE @decimal decimal
DECLARE @float float
SET @int = 1701
SET @real = @int
SET @decimal = @real
SET @float = @decimal
SELECT @int as [int], @real as [real], @decimal as [decimal], @float as [float]
Fortfarande en framgång, eller hur?
Hittills har vi använt enkla värden som kommer att vara lämpliga för en ganska liknande typ av data. Låt oss gå in på nästa nivå:siffror till strängar.
DECLARE @number int
DECLARE @string varchar(5)
SET @number = 1701
SET @string = @number
SELECT @number as [number], @string as [string]
Detta kommer att konverteras framgångsrikt som du kan se från resultatet nedan:
Det finns många fler tillfällen då SQL Server kommer att försöka "gissa" hur man konverterar data. Som du kan se från den här referensen finns det många fall jämfört med de som kräver explicit konvertering.
Eftersom SQL Server tillåter detta, betyder det att du fritt kan tillåta detta att hända över hela din kod?
Varningar i implicit konvertering
För det första kan det vara bekvämt. Men när gränserna för varje datatyp har nåtts kommer du att inse att implicit konvertering är lite farlig om den inte är markerad.
Betrakta ett exempel nedan:
DECLARE @char char(25)
DECLARE @varchar varchar(25)
DECLARE @nvarchar nvarchar(25)
DECLARE @nchar nchar(25)
SET @nvarchar = N'I ❤ U!'
SET @nchar = @nvarchar
SET @char = @nchar
SET @varchar = @nchar
SELECT @char as [char], @varchar as [varchar], @nvarchar as [nvarchar], @nchar as [nchar]
Såg du emojivärdet? Det kommer att räknas som ett unicode-värde.
Även om alla påståenden ovan kommer att köras framgångsrikt, men variablerna med icke-unicode-typer som varchar och röding kommer att få oväntade resultat. Se resultatet nedan:
Ändå är det inte det enda problemet. Fel dyker upp när värdet hamnar utanför intervallet. Tänk på ett exempel med datum:
DECLARE @datetime datetime
DECLARE @smalldatetime smalldatetime
DECLARE @datetime2 datetime2
SET @datetime = '12/31/2374 14:34'
SET @smalldatetime = @datetime
SET @datetime2 = @smalldatetime
SELECT @datetime as [datetime], @smalldatetime as [smalldatetime], @datetime2 as [datetime2]
Tilldelningen av datetime värde till smalldatetime variabel kommer att utlösa felet som du kan se nedan:
Men det finns en annan varning, som du också bör vara medveten om när du hanterar implicit konvertering:prestationsoverhead. Eftersom detta är ett hett ämne, förtjänar det att ha ett separat avsnitt.
Prestandakonsekvenser av olika SQL-datakonverteringsmetoder
Tro det eller ej, olika SQL-datakonverteringsmetoder kommer att ha olika prestanda i faktiska situationer. Och du bör åtminstone vara medveten om detta så att du kan undvika prestationsfällor.
Hur fungerar CAST(), CONVERT() och PARSE()
Låt oss först undersöka hur CAST (), KONVERTERA () och PARSE () prestera under naturliga förhållanden genom att jämföra vilket som är snabbare. Vi anpassar och bevisar konceptet med vårt exempel hämtat härifrån. Tänk på koden nedan:
USE AdventureWorks
GO
SET STATISTICS TIME ON
SELECT CAST([NationalIDNumber] as int) FROM [HumanResources].[Employee]
SELECT CONVERT(int,[NationalIDNumber]) FROM [HumanResources].[Employee]
SELECT PARSE([NationalIDNumber] as int) FROM [HumanResources].[Employee]
SET STATISTICS TIME OFF
GO
Låt oss nu undersöka koden som använder AdventureWorks databas från Microsoft:
- STÄLL PÅ STATISTIKTIDEN kommer att mata ut CPU-tiden och förfluten tid i var och en av SELECT uttalanden
- Då är kolumnen vi väljer att konvertera i demonstrationssyfte [NationalIDNumber ], som har en typ av nvarchar(15) .
- Konverteringen är också från en sträng till ett heltal:nvarchar(15) till int .
- Och sist, vi återställer STÄLL IN STATISTIKTID till dess tidigare värde
Lägg märke till resultatet i Meddelanden fliken i frågeresultatet:
Här är vad vi har kommit fram till med det här exemplet:
- Det bevisar att CAST () presterar snabbast (1 ms.) och PARSE () utför långsammast (318 ms.).
- Vi följer denna prioritet när vi bestämmer vilken funktion som ska användas för att konvertera data:(1 ) CAST () (2 ) KONVERTERA () (3 ) PARSE ().
- Kom ihåg när varje funktion är relevant och överväg begränsningarna när du bestämmer vilken funktion du ska använda.
Hur implicit konvertering fungerar
Vid det här laget bör du kunna se att jag rekommenderar användning av funktioner som CAST() för att konvertera data. Och i det här avsnittet kommer du att se varför.
Överväg den här frågan med WideWorldImporters databas från Microsoft. Innan du kör det, vänligen aktivera Inkludera faktisk exekveringsplan i SQL Server Management Studio .
USE WideWorldImporters
GO
SELECT
[CustomerID]
,[OrderID]
,[OrderDate]
,[ExpectedDeliveryDate]
FROM [Sales].[Orders]
WHERE [CustomerID] like '487%'
I frågan ovan filtrerar vi resultatet av försäljningsorder med [Kund-ID ] som "487 %". Detta är bara för att visa vilken effekt den implicita konverteringen av en int datatypen har på varchar .
Därefter granskar vi genomförandeplanen nedan:
Som du kan se finns det en varning i SELECT ikon. Håll därför musen för att se verktygstipset. Lägg sedan märke till varningsmeddelandet, nämligen CONVERT_IMPLICIT .
Innan vi fortsätter, detta CONVERT_IMPLICIT varning uppstår när det är nödvändigt att utföra en implicit konvertering för SQL Server. Låt oss titta närmare på problemet. Som beskrivs nedan har varningen två delar:
- CONVERT_IMPLICIT kan påverka "CardinalityEstimate" i ett frågeplansval.
- CONVERT_IMPLICIT kan påverka "SeekPlan" i ett frågeplansval.
Båda indikerar att din fråga kommer att gå långsammare. Men vi vet förstås varför. Vi tvingar avsiktligt fram en implicit konvertering genom att använda en GILLA operator för ett heltalsvärde.
Vad är poängen med det?
- Implicit konvertering av data gör att SQL Server använder CONVERT_IMPLICIT , vilket gör din fråga långsammare.
- För att åtgärda det här problemet, eliminera användningen av implicit konvertering. I vårt fall använde vi [Kund-ID ] GILLA "487%", vi kan fixa det genom att ändra [Kund-ID ] =487. Om du åtgärdar frågan ändras frågeexekveringsplanen, tar bort varningen tidigare och ändrar indexskanningsoperatorn till en indexsökning. I slutändan förbättras prestandan.
Lyckligt slut? Ja!
Hämtmat
Som visas kan vi inte bara låta SQL Server göra konverteringen med en implicit konvertering. Jag rekommenderar dig att följa företrädet när det gäller att bestämma vad du ska använda när du konverterar data.
- För det första, om du bara behöver konvertera som den är, använd CAST (). Det är en mer standardiserad funktion när det gäller portering till andra RDBM.
- För det andra, om du behöver formaterad data, använd KONVERTERA ().
- För det tredje, om båda CAST () och KONVERTERA () misslyckas med att göra jobbet, använd PARSE ().
- Slutligen, för att testa för fel vid konvertering, använd TRY_CAST (), TRY_CONVERT (), eller TRY_PARSE ().
Nåväl, det var allt för nu. Jag hoppas att detta hjälper dig med dina nästa kodningsäventyr. Bryt ett ben!
För att lära dig mer om ämnet SQL-datakonvertering från Microsoft:
- CASTA och KONVERTERA
- PARSE
- TRY_CAST, TRY_CONVERT och TRY_PARSE