sql >> Database teknologi >  >> RDS >> Sqlserver

Vejledning til CTE i SQL Server

Det almindelige tabeludtryk alias CTE i SQL Server giver et midlertidigt resultatsæt i T-SQL. Du kan henvise til det i en SQL Select-, SQL Insert-, SQL Delete- eller SQL Update-sætning.

Muligheden er tilgængelig fra SQL Server 2005 og fremefter, og hjælper udviklerne med at skrive komplekse og lange forespørgsler, der involverer mange JOINs, aggregering og datafiltrering. Normalt bruger udviklere underforespørgsler til at skrive T-SQL-koder, og SQL Server gemmer disse CTE i hukommelsen midlertidigt, indtil forespørgselsudførelsen afsluttes. Når forespørgslen er færdig, fjernes den fra hukommelsen.

CTE i SQL Server:Syntaks

MED ([kolonnenavne])AS( )
  • Den bruger et CTE-navn til at henvise til den for at udføre sætningerne Vælg, Indsæt, Opdater, Slet eller Flet.
  • Kolonnenavne er kommaseparerede. De skal matche de kolonner, der er defineret i forespørgselsdefinitionen.
  • Forespørgselsdefinitionen involverer udvalgte sætninger fra en enkelt tabel eller joinforbindelser mellem flere tabeller.
  • Du kan henvise til CTE-udtrykket for at hente resultaterne.

For eksempel bruger følgende grundlæggende CTE-forespørgsel følgende dele:

  • Fælles tabeludtryksnavn – SalesCustomerData
  • Kolonnerliste – [Kunde-ID],[Fornavn],[Efternavn],[Virksomhedsnavn],[E-mailadresse],[Telefon]
  • Forespørgselsdefinitionen inkluderer en select-sætning, der henter data fra tabellen [SalesLT].[Customer]
  • Den sidste del bruger select-sætningen på CTE-udtrykket og filtrerer poster ved hjælp af where-sætningen.
MED SalesKundedata ([KundeID],[Fornavn],[Efternavn],[Virksomhedsnavn],[E-mailadresse],[Telefon])AS(VÆLG [Kunde-id] ,[Fornavn] ,[Efternavn] ,[Virksomhedsnavn ] ,[E-mailadresse] ,[Telefon] FRA [SalesLT].[Kunde] )VÆLG * FRA SalgsKundedata, hvor fornavn som 'Raj%' BESTIL EFTER Kunde-ID desc 

I et andet eksempel beregner vi det gennemsnitlige samlede salg fra CTE. Forespørgselsdefinitionen inkluderer GROUP BY-sætningen. Senere bruger vi AVG()-funktionen til at beregne gennemsnitsværdien.

MED Salesdata ([SalesOrderID],[Total])AS(SELECT [SalesOrderID] ,count(*) AS total FROM [SalesLT].[SalesOrderHeader] GROUP BY [SalesOrderID])SELECT gns.(total) FROM salgsdata 

Du kan også bruge CTE til at indsætte data i SQL-tabellen. CTE-forespørgselsdefinitionen inkluderer de nødvendige data, som du kan hente fra eksisterende tabeller ved hjælp af joins. Senere, forespørg CTE for at indsætte data i måltabellen.

Her bruger vi SELECT INTO-sætningen til at oprette en ny tabel med navnet [CTETest] ud fra outputtet fra CTE select-sætningen.

MED CTEDataInsertAS (VÆLG s.[ProduktID] ,s.[Navn] ,pm.[Navn] AS [ProductModel] ,pmx.[Kultur] ,pd.[Beskrivelse]FRA [SalgLT].[Produkt ] p INNER JOIN [SalesLT].[ProductModel] pm ON p.[ProductModelID] =pm.[ProductModelID] INNER JOIN [SalesLT].[ProductModelProductDescription] pmx ON pm.[ProductModelID] =pmx.[ProductModelID] INNER JOIN ].[ProductDescription] pd ON pmx.[ProductDescriptionID] =pd.[ProductDescriptionID])VÆLG * I CTETest FRA CTEDataInsertGO

Du kan også angive en eksisterende tabel, der matcher kolonnerne med de indsatte data.

MED CTEDataInsertAS (VÆLG s.[ProduktID] ,s.[Navn] ,pm.[Navn] AS [ProductModel] ,pmx.[Kultur] ,pd.[Beskrivelse]FRA [SalgLT].[Produkt ] p INNER JOIN [SalesLT].[ProductModel] pm ON p.[ProductModelID] =pm.[ProductModelID] INNER JOIN [SalesLT].[ProductModelProductDescription] pmx ON pm.[ProductModelID] =pmx.[ProductModelID] INNER JOIN ].[ProductDescription] pd ON pmx.[ProductDescriptionID] =pd.[ProductDescriptionID])INSERT i CTETest vælg * FRA CTEDataInsertGO

Du kan også opdatere eller slette poster i SQL-tabellen ved hjælp af det fælles tabeludtryk. Følgende forespørgsler bruger DELETE- og UPDATE-sætninger med CTE.

Opdater erklæring i CTE

MED Salgsdata ([SalesOrderID],[Freight])AS(VÆLG [SalesOrderID] ,[Fragt] FRA [SalesLT].[SalesOrderHeader] )OPDATERING SalesData SÆT [Fragt]=100,00 WHERE [SalesOrderID]=71774Go  

Slet erklæring i CTE

MED Salesdata ([SalesOrderID],[Fragt])AS(VÆLG [SalesOrderID] ,[Fragt] FRA [SalesLT].[SalesOrderHeader] )slet SalesData WHERE [SalesOrderID]=71774GOSELECT * FRA [SalesLT]. [SalesOrderHeader] WHERE SalesOrderID=71774 

Flere CTE'er

Du kan erklære flere CTE'er i T-SQL-scriptet og bruge join-operationerne på dem. Til den multiple CTE bruger T-SQL et komma som en separator.

I den følgende forespørgsel har vi to CTE'er:

  1. CTESale
  2. CTESalesDescription

Senere, i select-sætningen, henter vi resultater ved hjælp af INNER JOIN på begge CTE'er.

Med CTESalesAS (VÆLG s.[ProduktID] ,s.[Navn] ,pm.[Navn] AS [Produktmodel] ,pmx.[Kultur] ,pmx.[Produktbeskrivelse-ID] FRA [SalesLT].[Produkt ] p INNER JOIN [SalesLT].[ProductModel] pm ON p.[ProductModelID] =pm.[ProductModelID] INNER JOIN [SalesLT].[ProductModelProductDescription] pmx ON pm.[ProductModelID] =pmx.[ProductModelID] INNER JOIN ].[ProductDescription] pd ON pmx.[ProductDescriptionID] =pd.[ProductDescriptionID]),CTESalesDescriptionAS (VÆLG beskrivelse SOM beskriv,[ProductDescriptionID]fra [SalesLT].[ProductDescription] )SELECT productid, [Name],[ProductModel], describeFROM CTESales INNER JOIN CTESalesDescription ON CTESales.[ProductDescriptionID] =CTESalesDescription.[ProductDescriptionID]

Rekursive almindelige tabeludtryk

Den rekursive CTE kører i en gentagen procedurel løkke, indtil betingelsen er opfyldt. Følgende T-SQL-eksempel bruger en ID-tæller og vælger poster, indtil WHERE-betingelsen er opfyldt.

Erklær @ID int =1;;med RecursiveCTE som (VÆLG @ID som ID UNION ALLE VÆLG ID+ 1 FRA RecursiveCTE WHERE ID <5 ) VÆLG * FRA RekursivCTE 

En anden anvendelse af rekursiv CTE i SQL Server er at vise hierarkiske data. Antag, at vi har en medarbejder tabel, og den har optegnelser for alle medarbejdere, deres afdelinger og deres lederes ID'er.

--Scriptreference:Microsoft DocsCREATE TABLE dbo.MyEmployees ( Medarbejder-ID SMALLINT NOT NULL, Fornavn NVARCHAR(30) NOT NULL, Efternavn NVARCHAR(40) NOT NULL, Titel NVARCHAR(50) NOT NULL, DeptID SMALLINT NULL, ManagerID INT NULL, BEGRÆNSNING PK_EmployeeID PRIMÆR NØGLE KLYNGET (EmployeeID ASC) ); INSERT INTO dbo.MyEmployees VALUES (1, N'Ken', N'Sánchez', N'Chief Executive Officer',16,NULL),(273, N'Brian', N'Welcker', N'Vice President of Sales ',3,1) ,(274, N'Stephen', N'Jiang', N'North American Sales Manager',3.273) ,(275, N'Michael', N'Blythe', N'Sales Representative', 3.274) ,(276, N'Linda', N'Mitchell', N'Sales Representative',3.274) ,(285, N'Syed', N'Abbas', N'Pacific Sales Manager',3.273) ,(286) , N'Lynn', N'Tsoflias', N'Sales Representative',3.285) ,(16, N'David',N'Bradley', N'Marketing Manager', 4, 273) ,(23, N'Mary ', N'Gibson', N'Marketing Specialist', 4, 16);

Nu skal vi generere medarbejderhierarkidata. Vi kan bruge rekursiv CTE med UNION ALL i select-sætningen.

WITH DirectReports(Name, Title, EmployeeID, EmployeeLevel, Sort) AS (SELECT CONVERT(VARCHAR(255), e.FirstName + ' ' + e.LastName), e.Title, e.EmployeeID, 1 , CONVERT(VARCHAR(255), e.FirstName + ' ' + e.LastName) FRA dbo.MyEmployees AS e WHERE e.ManagerID IS NULL UNION ALL SELECT CONVERT(VARCHAR(255), REPLICATE ('| ' , EmployeeLevel) + e.FirstName + ' ' + e.LastName), e.Title, e.EmployeeID, EmployeeLevel + 1, CONVERT (VARCHAR(255), RTRIM(Sort) + '| ' + FirstName + ' ' + Efternavn) FRA dbo. MyEmployees AS e JOIN DirectReports AS d ON e.ManagerID =d.EmployeeID ) SELECT EmployeeID, Name, EmployeeLevel FROM DirectReports ORDER BY Sort;

CTE returnerer oplysningerne på medarbejderniveau som vist nedenfor.

Vigtige punkter vedrørende almindelige tabeludtryk

  • Vi kan ikke genbruge CTE. Dens omfang er begrænset til de ydre SELECT-, INSERT-, UPDATE- eller MERGE-sætninger.
  • Du kan bruge flere CTES; dog bør de bruge UNION ALL, UNION, INTERSECT eller EXCERPT operatorer.
  • Vi kan definere flere CTE-forespørgselsdefinitioner i den ikke-rekursive CTE.
  • Vi kan ikke bruge ORDER BY (uden TOP), INTO, OPTIONS-klausulen med forespørgselstip og FOR BROWSE i CTE-forespørgselsdefinitionen.

For eksempel bruger nedenstående script ORDER BY-sætningen uden en TOP-sætning.

MED CTEDataInsertAS (VÆLG s.[ProduktID] ,s.[Navn] ,pm.[Navn] AS [ProductModel] ,pmx.[Kultur] ,pd.[Beskrivelse]FRA [SalgLT].[Produkt ] p INNER JOIN [SalesLT].[ProductModel] pm ON p.[ProductModelID] =pm.[ProductModelID] INNER JOIN [SalesLT].[ProductModelProductDescription] pmx ON pm.[ProductModelID] =pmx.[ProductModelID] INNER JOIN ].[ProductDescription] pd ON pmx.[ProductDescriptionID] =pd.[ProductDescriptionID] BESTIL EFTER produktid) vælg * FRA CTEDataInsert GO

Det giver følgende fejl:

  • Vi kan ikke oprette et indeks på CTE.
  • De definerede kolonnenavne i CTE skal matche de kolonner, der returneres i select-sætningen.

CTE'en har ikke kolonnen [Phone] i koden nedenfor, mens select-sætningen returnerer sin værdi. Derfor får du den fremhævede fejlmeddelelse.

  • Hvis du har flere sætninger i T-SQL-scriptet, bør den forrige sætning før CTE afsluttes med et semikolon.

For eksempel indeholder den første select-sætning ikke et semikolon. Derfor får du en forkert syntaksfejl i CTE-scriptet.

Scriptet fungerer fint, hvis vi afslutter den første select-sætning ved hjælp af semikolonoperatoren.

  • Vi kan ikke bruge en dubletkolonne i select-sætningen, hvis vi ikke erklærer kolonnenavnet eksternt.

For eksempel angiver følgende CTE-definition duplikatkolonnen [Telefon]. Det returnerer en fejl.

Men hvis du definerer eksterne kolonner, vil det ikke forårsage fejl. Det er påkrævet, når du har brug for en enkelt kolonne flere gange i outputtet til forskellige beregninger.

Vigtigt:Common Table Expressions (CTE) er ikke en erstatning for de midlertidige tabeller eller tabelvariabler.

  • Temperaturtabeller oprettes i TempDB, og vi kan definere indeksbegrænsninger svarende til en almindelig tabel. Vi kan ikke referere til temp-tabellen flere gange i en session
  • Tabelvariabler findes også i TempDB og fungerer som variabler, der eksisterer under batchudførelsen. Vi kan ikke definere et indeks på tabelvariablerne.
  • CTE er til et enkelt referenceformål, og vi kan ikke definere indekset på det. Den findes i hukommelsen og falder på efter reference.

Konklusion

Common Table Expressions (CTE) giver udviklerne mulighed for at skrive ren og effektiv kode. Generelt kan du bruge CTE, hvor du ikke kræver flere referencer som en midlertidig tabel, og vi undersøgte forskellige scenarier for SELECT, INSERT, UPDATE, DETELTE-sætning og rekursive CTE'er.

Ved hjælp af moderne værktøjer, såsom SQL Complete SSMS Add-in, bliver håndteringen af ​​CTE'er endnu nemmere. Tilføjelsen kan foreslå CTE'er på farten, hvilket gør opgaverne, der involverer CTE, meget mere ligetil. Se også Microsofts dokumentation for flere detaljer om CTE.


  1. Brug sys.trigger_event_types til at vise triggerhændelsestyper i SQL Server

  2. Skift datoformat (i DB eller output) til dd/mm/åååå - PHP MySQL

  3. Hvordan sundhedsindustrien bruger databaser

  4. Sådan transponeres mysql-tabelrækker til kolonner