J'ai commencé à lire à propos de Common Table Expression et je ne peux pas penser à un cas d'utilisation où j'aurais besoin de les utiliser. Ils sembleraient redondants car la même chose peut être faite avec des tables dérivées. Y a-t-il quelque chose qui me manque ou que je ne comprends pas bien? Quelqu'un peut-il me donner un exemple simple de limitations avec des requêtes de sélection régulières, dérivées ou de tables temporaires pour rendre le cas de CTE? Des exemples simples seraient très appréciés.
Un exemple, si vous devez référencer/joindre le même ensemble de données plusieurs fois, vous pouvez le faire en définissant un CTE. Par conséquent, cela peut être une forme de réutilisation de code.
La récursivité est un exemple d'auto-référencement: Requêtes récursives utilisant CTE
Pour des définitions Microsoft passionnantes Tiré de Books Online:
Un CTE peut être utilisé pour:
Créez une requête récursive. Pour plus d'informations, voir Requêtes récursives à l'aide d'expressions de table communes.
Remplacez une vue lorsque l'utilisation générale d'une vue n'est pas requise; c'est-à-dire qu'il n'est pas nécessaire de stocker la définition dans des métadonnées.
Activer le regroupement d’une colonne dérivée d’une sous-sélection scalaire, ou d’une fonction non déterministe ou disposant d’un accès externe.
Référencez la table résultante plusieurs fois dans la même instruction.
Je les utilise pour décomposer des requêtes complexes, en particulier des jointures complexes et des sous-requêtes. Je trouve que je les utilise de plus en plus comme des "pseudo-vues" pour m'aider à comprendre l'esprit de la requête.
Mon seul reproche à leur sujet est qu'ils ne peuvent pas être réutilisés. Par exemple, je peux avoir un proc stocké avec deux instructions de mise à jour pouvant utiliser le même CTE. Mais la "portée" du CTE n'est que la première requête.
Le problème, c'est que les "exemples simples" n'ont probablement pas vraiment besoin de CTE!
Toujours très utile.
Je vois deux raisons d’utiliser cte.
Pour utiliser une valeur calculée dans la clause where. Cela me semble un peu plus propre qu'une table dérivée.
Supposons qu'il y ait deux tables - Questions et réponses réunies par Questions.ID = Réponses.Question_Id (et identifiant du quiz)
WITH CTE AS
(
Select Question_Text,
(SELECT Count(*) FROM Answers A WHERE A.Question_ID = Q.ID) AS Number_Of_Answers
FROM Questions Q
)
SELECT * FROM CTE
WHERE Number_Of_Answers > 0
Voici un autre exemple où je veux obtenir une liste de questions et réponses. Je veux que les réponses soient regroupées avec les questions dans les résultats.
WITH cte AS
(
SELECT [Quiz_ID]
,[ID] AS Question_Id
,null AS Answer_Id
,[Question_Text]
,null AS Answer
,1 AS Is_Question
FROM [Questions]
UNION ALL
SELECT Q.[Quiz_ID]
,[Question_ID]
,A.[ID] AS Answer_Id
,Q.Question_Text
,[Answer]
,0 AS Is_Question
FROM [Answers] A INNER JOIN [Questions] Q ON Q.Quiz_ID = A.Quiz_ID AND Q.Id = A.Question_Id
)
SELECT
Quiz_Id,
Question_Id,
Is_Question,
(CASE WHEN Answer IS NULL THEN Question_Text ELSE Answer END) as Name
FROM cte
GROUP BY Quiz_Id, Question_Id, Answer_id, Question_Text, Answer, Is_Question
order by Quiz_Id, Question_Id, Is_Question Desc, Name
L'un des scénarios que j'ai trouvé utile pour utiliser CTE est lorsque vous souhaitez obtenir des lignes de données DISTINCT basées sur une ou plusieurs colonnes tout en renvoyant toutes les colonnes de la table. Avec une requête standard, vous devez d’abord vider les valeurs distinctes dans une table temporaire, puis essayer de les joindre à la table originale pour récupérer le reste des colonnes, ou vous pouvez écrire une requête de partition extrêmement complexe pouvant renvoyer les résultats une exécution, mais selon toute probabilité, il sera illisible et posera un problème de performances.
Mais en utilisant CTE (comme l'a répondu Tim Schmelter sur Sélectionnez la première instance d'un enregistrement )
WITH CTE AS(
SELECT myTable.*
, RN = ROW_NUMBER()OVER(PARTITION BY patientID ORDER BY ID)
FROM myTable
)
SELECT * FROM CTE
WHERE RN = 1
Comme vous pouvez le constater, cela est beaucoup plus facile à lire et à maintenir. Et par rapport à d’autres requêtes, ses performances sont bien meilleures.
Peut-être est-il plus utile de penser qu’un CTE remplace une vue utilisée pour une requête unique. Mais ne nécessite pas la surcharge, les métadonnées ou la persistance d'une vue formelle. Très utile lorsque vous avez besoin de:
Voici un exemple de copier-coller avec lequel jouer:
WITH [cte_example] AS (
SELECT 1 AS [myNum], 'a num' as [label]
UNION ALL
SELECT [myNum]+1,[label]
FROM [cte_example]
WHERE [myNum] <= 10
)
SELECT * FROM [cte_example]
UNION
SELECT SUM([myNum]), 'sum_all' FROM [cte_example]
UNION
SELECT SUM([myNum]), 'sum_odd' FROM [cte_example] WHERE [myNum] % 2 = 1
UNION
SELECT SUM([myNum]), 'sum_even' FROM [cte_example] WHERE [myNum] % 2 = 0;
Prendre plaisir
Aujourd'hui, nous allons en apprendre davantage sur l'expression de table commune, une nouvelle fonctionnalité introduite dans SQL Server 2005 et également disponible dans les versions ultérieures.
Expression de table commune: - L'expression de table commune peut être définie comme un ensemble de résultats temporaire ou, en d'autres termes, comme substitut de vues dans SQL Server. L'expression de table commune n'est valide que dans le lot d'instructions où elle a été définie et ne peut pas être utilisée dans d'autres sessions.
Syntaxe de déclaration CTE (expression de table commune): -
with [Name of CTE]
as
(
Body of common table expression
)
Prenons un exemple: -
CREATE TABLE Employee([EID] [int] IDENTITY(10,5) NOT NULL,[Name] [varchar](50) NULL)
insert into Employee(Name) values('Neeraj')
insert into Employee(Name) values('dheeraj')
insert into Employee(Name) values('shayam')
insert into Employee(Name) values('vikas')
insert into Employee(Name) values('raj')
CREATE TABLE DEPT(EID INT,DEPTNAME VARCHAR(100))
insert into dept values(10,'IT')
insert into dept values(15,'Finance')
insert into dept values(20,'Admin')
insert into dept values(25,'HR')
insert into dept values(10,'Payroll')
J'ai créé deux tables employee et Dept et inséré 5 lignes dans chaque table. Maintenant, j'aimerais rejoindre ces tables et créer un jeu de résultats temporaire pour pouvoir les utiliser davantage.
With CTE_Example(EID,Name,DeptName)
as
(
select Employee.EID,Name,DeptName from Employee
inner join DEPT on Employee.EID =DEPT.EID
)
select * from CTE_Example
Permet de prendre chaque ligne de la déclaration une par une et de comprendre.
Pour définir CTE, nous écrivons la clause "with", puis nous donnons un nom à l'expression de la table. Ici, j'ai donné le nom "CTE_Example".
Ensuite, nous écrivons "As" et mettons notre code entre deux crochets (---), nous pouvons joindre plusieurs tables entre crochets.
Dans la dernière ligne, j'ai utilisé "Select * from CTE_Example", nous faisons référence à l’expression de table commune dans la dernière ligne de code. Nous pouvons donc dire que C’est comme une vue, où nous définissons et utilisons la vue dans un seul batch et CTE ne sont pas stockés dans la base de données en tant qu’objet permanent. Mais cela se comporte comme une vue. nous pouvons effectuer des déclarations de suppression et de mise à jour sur CTE et cela aura un impact direct sur la table référencée utilisée par CTE. Prenons un exemple pour comprendre ce fait.
With CTE_Example(EID,DeptName)
as
(
select EID,DeptName from DEPT
)
delete from CTE_Example where EID=10 and DeptName ='Payroll'
Dans la déclaration ci-dessus, nous supprimons une ligne de CTE_Example et les données de la table référencée "DEPT" utilisée dans le CTE seront supprimées.
C'est très utile lorsque vous souhaitez effectuer une "mise à jour ordonnée".
MS SQL ne vous permet pas d'utiliser ORDER BY avec UPDATE, mais avec l'aide de CTE, vous pouvez le faire comme suit:
WITH cte AS
(
SELECT TOP(5000) message_compressed, message, exception_compressed, exception
FROM logs
WHERE Id >= 5519694
ORDER BY Id
)
UPDATE cte
SET message_compressed = COMPRESS(message), exception_compressed = COMPRESS(exception)
Regardez ici pour plus d’informations: Comment mettre à jour et commander en utilisant ms SQL