Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
              Gäller för:SQL Server
Azure SQL Database
Azure SQL Managed Instance
SQL-databas i Förhandsversion av Microsoft Fabric
När du analyserar T-SQL-koden i databasprojektet kan en eller flera varningar kategoriseras som designproblem. Du bör åtgärda designproblem för att undvika följande situationer:
- Efterföljande ändringar i databasen kan bryta program som är beroende av den.
 - Koden kanske inte ger det förväntade resultatet.
 - Koden kan brytas om du kör den med framtida versioner av SQL Server.
 
I allmänhet bör du inte förhindra ett designproblem eftersom det kan bryta ditt program, antingen nu eller i framtiden.
De angivna reglerna identifierar följande designproblem:
- SR0001: Undvik SELECT * i lagrade procedurer, vyer och tabellvärdesfunktioner
 - SR0008: Överväg att använda SCOPE_IDENTITY i stället för @@IDENTITY
 - SR0009: Undvik att använda typer av variabellängd som är storlek 1 eller 2
 - SR0010: Undvik att använda inaktuell syntax när du kopplar tabeller eller vyer
 - SR0013: Utdataparametern (parametern) fylls inte i i alla kodsökvägar
 - SR0014: Dataförlust kan uppstå vid gjutning från {Type1} till {Type2}
 
SR0001: Undvik SELECT * i lagrade procedurer, vyer och tabellvärdesfunktioner
Om du använder ett jokertecken i en lagrad procedur, vy eller tabellvärdesfunktion för att markera alla kolumner i en tabell eller vy kan antalet eller formen på returnerade kolumner ändras om den underliggande tabellen eller vyn ändras. Formen på en kolumn är en kombination av dess typ och storlek. Den här variansen kan orsaka problem i program som använder den lagrade proceduren, vyn eller tabellvärdesfunktionen eftersom dessa konsumenter förväntar sig ett annat antal kolumner.
Så här åtgärdar du överträdelser
Du kan skydda användare av den lagrade proceduren, vyn eller tabellvärdesfunktionen från schemaändringar genom att ersätta jokertecknet med en fullständigt kvalificerad lista med kolumnnamn.
Example
I följande exempel definieras först en tabell med namnet [Table2] och sedan två lagrade procedurer. Den första proceduren innehåller en SELECT *, som bryter mot regeln SR0001. Den andra proceduren undviker SELECT * och listar uttryckligen kolumnerna i SELECT-instruktionen.
CREATE TABLE [dbo].[Table2]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL,
[Comment] NVARCHAR (50)
)
ON [PRIMARY]
CREATE PROCEDURE [dbo].[procWithWarning]
AS
BEGIN
-- Contains code that breaks rule SR0001
SELECT *
FROM [dbo].[Table2]
END
CREATE PROCEDURE [dbo].[procFixed]
AS
BEGIN
-- Explicitly lists the column names in a SELECT statement
SELECT [dbo].[Table2].[ID], [dbo].[Table2].[c1], [dbo].[Table2].[Comment]
FROM [dbo].[Table2]
END
SR0008: Överväg att använda SCOPE_IDENTITY i stället för @@IDENTITY
Eftersom @@IDENTITY är ett globalt identitetsvärde kan det ha uppdaterats utanför det aktuella omfånget och fått ett oväntat värde. Utlösare, inklusive kapslade utlösare som används av replikering, kan uppdatera @@IDENTITY utanför ditt aktuella omfång.
Så här åtgärdar du överträdelser
För att lösa det här problemet måste du ersätta referenser till @@IDENTITY med SCOPE_IDENTITY, som returnerar det senaste identitetsvärdet i användarutdragets omfång.
Example
I det första exemplet används @@IDENTITY i en lagrad procedur som infogar data i en tabell. Tabellen publiceras sedan för sammanslagningsreplikering, vilket lägger till utlösare i tabeller som publiceras. Därför kan @@IDENTITY returnera värdet från infogningsåtgärden till en replikeringssystemtabell i stället för infogningsåtgärden i en användartabell.
Tabellen Sales.Customer har ett maximalt identitetsvärde på 29483. Om du infogar en rad i tabellen returnerar @@IDENTITY och SCOPE_IDENTITY() olika värden. SCOPE_IDENTITY() returnerar värdet från infogningsåtgärden i användartabellen, men @@IDENTITY returnerar värdet från infogningsåtgärden till replikeringssystemets tabell.
Det andra exemplet visar hur du kan använda SCOPE_IDENTITY() för att komma åt det infogade identitetsvärdet och lösa varningen.
CREATE PROCEDURE [dbo].[ProcedureWithWarning]
@param1 INT,
@param2 NCHAR(1),
@Param3 INT OUTPUT
AS
BEGIN
INSERT INTO Sales.Customer ([TerritoryID],[CustomerType]) VALUES (@param1,@param2);
SELECT @Param3 = @@IDENTITY
END
CREATE PROCEDURE [dbo].[ProcedureFixed]
@param1 INT,
@param2 NCHAR(1),
@param3 INT OUTPUT
AS
BEGIN
INSERT INTO Sales.Customer ([TerritoryID],[CustomerType]) VALUES (@param1,@param2);
SELECT @Param3 = SCOPE_IDENTITY()
END
SR0009: Undvik att använda typer av variabellängd som är storlek 1 eller 2
När du använder datatyper med variabel längd, till exempel VARCHAR, NVARCHAR och VARBINARY, medför du en extra lagringskostnad för att spåra längden på värdet som lagras i datatypen. Dessutom lagras kolumner med variabel längd efter alla kolumner med fast längd, vilket kan få prestandakonsekvenser. Du får också en varning om du deklarerar en typ av variabellängd, till exempel VARCHAR, men du anger ingen längd. Den här varningen beror på att standardlängden är 1 om den är ospecificerad.
Så här åtgärdar du överträdelser
Om längden på typen är mycket liten (storlek 1 eller 2) och konsekvent deklarerar du dem som en typ av fast längd, till exempel CHAR, NCHAR och BINARY.
Example
Det här exemplet visar definitioner för två tabeller. Den första tabellen deklarerar en sträng med variabel längd för att ha längd 2. Den andra tabellen deklarerar en sträng med fast längd i stället, vilket undviker varningen.
CREATE TABLE [dbo].[TableWithWarning]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL PRIMARY KEY,
[c2] INT,
[c3] INT,
[SmallString] VARCHAR(2)
)
ON [PRIMARY]
CREATE TABLE [dbo].[FixedTable]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL PRIMARY KEY,
[c2] INT,
[c3] INT,
[SmallString] CHAR(2)
)
ON [PRIMARY]
Data för typer av variabel längd lagras fysiskt efter data för typer av fast längd. Därför orsakar du dataförflyttning om du ändrar en kolumn från variabel till fast längd i en tabell som inte är tom.
SR0010: Undvik att använda inaktuell syntax när du ansluter tabeller eller vyer
Kopplingar som använder den inaktuella syntaxen finns i två kategorier:
- Inre koppling: För en inre koppling jämförs värdena i de kolumner som kopplas med hjälp av en jämförelseoperator som =, <, >=och så vidare. Inre kopplingar returnerar endast rader om minst en rad från varje tabell matchar kopplingsvillkoret.
 - Yttre koppling: Yttre kopplingar returnerar alla rader från minst en av tabellerna eller vyerna som anges i FROM-satsen, så länge raderna uppfyller ett WHERE- eller HAVING-sökvillkor. Om du använder = eller = för att ange en yttre koppling använder du inaktuell syntax.
 
Så här åtgärdar du överträdelser
Om du vill åtgärda en överträdelse i en inre koppling använder du syntaxen INNER JOIN .
Om du vill åtgärda en överträdelse i en yttre koppling använder du lämplig OUTER JOIN syntax. Du kan välja mellan följande alternativ:
- VÄNSTER YTTRE KOPPLING ELLER VÄNSTER KOPPLING
 - HÖGER YTTRE KOPPLING ELLER HÖGERKOPPLING
 
Exempel på den inaktuella syntaxen och den uppdaterade syntaxen finns i följande exempel. Mer information om kopplingar finns i Kopplingar.
Examples
De sex exemplen visar följande alternativ:
- Exempel 1 visar den inaktuella syntaxen för en inre koppling.
 - Exempel 2 visar hur du kan uppdatera exempel 1 för att använda aktuell syntax.
 - Exempel 3 visar den inaktuella syntaxen för en vänster yttre koppling.
 - Exempel 4 visar hur du kan uppdatera exempel 2 för att använda aktuell syntax.
 - Exempel 5 visar den inaktuella syntaxen för en höger yttre koppling.
 - Exempel 6 visar hur du kan uppdatera exempel 5 för att använda aktuell syntax.
 
-- Example 1: Deprecated syntax for an inner join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] T2, [dbo].[Table1] T1
WHERE [T1].[ID] = [T2].[ID]
-- Example 2: Current syntax for an inner join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] AS T2
INNER JOIN [dbo].[Table1] as T1
ON [T2].[ID] = [T2].[ID]
-- Example 3: Deprecated syntax for a left outer join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] T2, [dbo].[Table1] T1
WHERE [T1].[ID] *= [T2].[ID]
-- Example 4: Fixed syntax for a left outer join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] AS T2
LEFT OUTER JOIN [dbo].[Table1] as T1
ON [T2].[ID] = [T2].[ID]
-- Example 5: Deprecated syntax for a right outer join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] T2, [dbo].[Table1] T1
WHERE [T1].[ID] =* [T2].[ID]
-- Example 6: Fixed syntax for a right outer join
SELECT [T2].[c3], [T1].[c3]
FROM [dbo].[Table2] AS T2
RIGHT OUTER JOIN [dbo].[Table1] as T1
ON [T2].[ID] = [T2].[ID]
SR0013: Utdataparametern (parametern) fylls inte i i alla kodsökvägar
Den här regeln identifierar kod där utdataparametern inte är inställd på ett värde i en eller flera kodsökvägar via den lagrade proceduren eller funktionen. Den här regeln identifierar inte i vilka sökvägar utdataparametern ska anges. Om flera utdataparametrar har det här problemet visas en varning för varje parameter.
Så här åtgärdar du överträdelser
Du kan åtgärda det här problemet på ett av två sätt. Du kan åtgärda det här problemet enklast om du initierar utdataparametrarna till ett standardvärde i början av procedurens brödtext. Alternativt kan du också ange utdataparametern till ett värde i de specifika kodsökvägar där parametern inte har angetts. Du kan dock förbise en ovanlig kodsökväg i en komplex procedur.
Important
Att ange ett värde i procedurdeklarationen, till exempel CREATE PROC MyProcedure (@param1 INT = 10 OUTPUT) löser inte problemet. Du måste tilldela ett värde till utdataparametern i procedurens brödtext.
Example
I följande exempel visas två enkla procedurer. Den första proceduren anger inte värdet för utdataparametern , @Sum. Den andra proceduren initierar parametern @Sum i början av proceduren, vilket säkerställer att värdet anges i alla kodsökvägar.
CREATE PROCEDURE [dbo].[procedureHasWarning]
(
@Value1 BIGINT,
@Value2 INT,
@Value3 INT,
@Sum INT OUTPUT
)
AS
BEGIN
-- No initialization of the output parameter
--
-- Additional statements here.
--
RETURN 0;
END
--
CREATE PROCEDURE [dbo].[procedureFixed]
(
@Value1 BIGINT,
@Value2 INT,
@Value3 INT,
@Sum INT OUTPUT
)
AS
BEGIN
-- Initialize the out parameter
SET @Sum = 0;
--
-- Additional statements here
--
RETURN 0;
END
SR0014: Dataförlust kan uppstå vid gjutning från {Type1} till {Type2}
Om datatyper är inkonsekvent tilldelade till kolumner, variabler eller parametrar konverteras de implicit när den Transact-SQL kod som innehåller dessa objekt körs. Den här typen av konvertering minskar inte bara prestandan utan orsakar även i vissa fall subtil dataförlust. En tabellgenomsökning kan till exempel köras om varje kolumn i en WHERE-sats måste konverteras. Värre är att data kan gå förlorade om en Unicode-sträng konverteras till en ASCII-sträng som använder en annan kodsida.
Den här regeln gör INTE:
- Kontrollera typen av en beräknad kolumn eftersom typen inte är känd innan körtid.
 - Analysera allt i ett CASE-uttryck. Den analyserar inte heller returvärdet av ett CASE-uttryck.
 - Analysera indataparametrarna eller returvärdet för ett anrop till ISNULL
 
Den här tabellen sammanfattar de kontroller som omfattas av regeln SR0014:
| Language construct | Vad är kontrollerat | Example | 
|---|---|---|
| Standardvärde för parametrar | Parameterdatatyp | 
 | 
| SKAPA INDEXpredikat | Predikat är booleskt | 
 | 
| Argument för vänster- eller HÖGERfunktioner | Strängargumenttyp och längd | 
 | 
| Argument för funktionerna CAST och CONVERT | Uttryck och typer är giltiga | 
 | 
| SET statement | Vänster sida och höger sida har kompatibla typer | 
 | 
| PREDIKAT FÖR IF-instruktion | Predikat är booleskt | 
 | 
| WHILE-instruktionspredikat | Predikat är booleskt | 
 | 
| INSERT statement | Värden och kolumner är korrekta | 
 | 
| VÄLJ VAR predikat | Predikat är booleskt | 
 | 
| SELECT TOP-uttryck | Uttrycket är en heltals- eller flyttalstyp | 
 | 
| UPDATE statement | Uttryck och kolumn har kompatibla typer | 
 | 
| UPDATE predicate | Predikat är booleskt | 
 | 
| UPDATE TOP-uttryck | Uttrycket är en heltals- eller flyttalstyp | 
 | 
| DELETE PREDICATE | Predikat är booleskt | 
 | 
| TA BORT TOP-uttryck | Uttrycket är en heltals- eller flyttalstyp | 
 | 
| DEKLARERA variabeldeklaration | Initialt värde och datatyp är kompatibla | 
 | 
| EXECUTE-instruktionsargument och returtyp | Parametrar och argument | 
 | 
| RETURN statement | RETURN-uttrycket har en kompatibel datatyp | 
 | 
| Villkor för MERGE-instruktion | Villkoret är booleskt | 
 | 
Så här åtgärdar du överträdelser
Du kan undvika och lösa dessa problem genom att tilldela datatyper konsekvent och genom att explicit konvertera typer där de behövs. Mer information om hur du explicit konverterar datatyper finns på den här sidan på Microsofts webbplats: CAST och CONVERT (Transact-SQL).
Example
Det här exemplet visar två lagrade procedurer som infogar data i en tabell. Den första proceduren, procWithWarning, orsakar en implicit konvertering av en datatyp. Den andra proceduren, procFixed, visar hur du kan lägga till en explicit konvertering för att maximera prestanda och behålla alla data.
CREATE TABLE [dbo].[Table2]
(
[ID] INT NOT NULL IDENTITY(0, 1),
[c1] INT NOT NULL,
[c2] INT NOT NULL,
[c3] BIGINT NOT NULL,
[Comment] VARCHAR (25)
)
ON [PRIMARY]
CREATE PROCEDURE [dbo].[procWithWarning]
(
@Value1 INT,
@Value2 INT,
@Value3 BIGINT,
@Comment CHAR(30)
)
AS
BEGIN
INSERT INTO [Table2] ([c1], [c2], [c3], Comment)
VALUES (@Value1, @Value2, @Value3, @Comment)
END
CREATE PROCEDURE [dbo].[procFixed]
(
@Value1 INT,
@Value2 INT,
@Value3 BIGINT,
@Comment CHAR(10)
)
AS
BEGIN
INSERT INTO [Table2] ([c1], [c2], [c3], Comment)
VALUES (@Value1, @Value2, @Value3, CAST(@Comment AS VARCHAR(25)))
END