Microsoft SQL Server
Общие выражения таблицы
Поиск…
Синтаксис
- WITH cte_name [( column_name_1 , column_name_2 , ...)] AS ( cte_expression )
замечания
Необходимо отделить CTE от предыдущего оператора с символом с запятой ( ;
).
т.е. с помощью ;WITH CommonTableName (...) SELECT ... FROM CommonTableName ...
Область CTE представляет собой единую партию и только ниже ее определения. Пакет может содержать несколько CTE, а CTE может ссылаться на другой CTE, определенный ранее в пакете, но CTE не может ссылаться на другой CTE, который определен позже в партии.
Иерархия сотрудников
Настройка таблицы
CREATE TABLE dbo.Employees
(
EmployeeID INT NOT NULL PRIMARY KEY,
FirstName NVARCHAR(50) NOT NULL,
LastName NVARCHAR(50) NOT NULL,
ManagerID INT NULL
)
GO
INSERT INTO Employees VALUES (101, 'Ken', 'Sánchez', NULL)
INSERT INTO Employees VALUES (102, 'Keith', 'Hall', 101)
INSERT INTO Employees VALUES (103, 'Fred', 'Bloggs', 101)
INSERT INTO Employees VALUES (104, 'Joseph', 'Walker', 102)
INSERT INTO Employees VALUES (105, 'Žydrė', 'Klybė', 101)
INSERT INTO Employees VALUES (106, 'Sam', 'Jackson', 105)
INSERT INTO Employees VALUES (107, 'Peter', 'Miller', 103)
INSERT INTO Employees VALUES (108, 'Chloe', 'Samuels', 105)
INSERT INTO Employees VALUES (109, 'George', 'Weasley', 105)
INSERT INTO Employees VALUES (110, 'Michael', 'Kensington', 106)
Выражение общей таблицы
;WITH cteReports (EmpID, FirstName, LastName, SupervisorID, EmpLevel) AS
(
SELECT EmployeeID, FirstName, LastName, ManagerID, 1
FROM Employees
WHERE ManagerID IS NULL
UNION ALL
SELECT e.EmployeeID, e.FirstName, e.LastName, e.ManagerID, r.EmpLevel + 1
FROM Employees AS e
INNER JOIN cteReports AS r ON e.ManagerID = r.EmpID
)
SELECT
FirstName + ' ' + LastName AS FullName,
EmpLevel,
(SELECT FirstName + ' ' + LastName FROM Employees WHERE EmployeeID = cteReports.SupervisorID) AS ManagerName
FROM cteReports
ORDER BY EmpLevel, SupervisorID
Выход:
ФИО EmpLevel ManagerName Кен Санчес 1 ноль Кит Холл 2 Кен Санчес Fred Bloggs 2 Кен Санчес Жидре Клыбе 2 Кен Санчес Джозеф Уокер 3 Кит Холл Питер Миллер 3 Fred Bloggs Сэм Джексон 3 Жидре Клыбе Хлоя Самуэльс 3 Жидре Клыбе Джордж Уизли 3 Жидре Клыбе Майкл Кенсингтон 4 Сэм Джексон Найти nth самую высокую зарплату с помощью CTE
Таблица сотрудников:
| ID | FirstName | LastName | Gender | Salary | +------+-----------+----------+--------+--------+ | 1 | Jahangir | Alam | Male | 70000 | | 2 | Arifur | Rahman | Male | 60000 | | 3 | Oli | Ahammed | Male | 45000 | | 4 | Sima | Sultana | Female | 70000 | | 5 | Sudeepta | Roy | Male | 80000 | +------+-----------+----------+--------+--------+
CTE (общее выражение таблицы):
WITH RESULT AS ( SELECT SALARY, DENSE_RANK() OVER (ORDER BY SALARY DESC) AS DENSERANK FROM EMPLOYEES ) SELECT TOP 1 SALARY FROM RESULT WHERE DENSERANK = 1
Чтобы найти вторую самую высокую зарплату, просто замените N на 2. Аналогично, чтобы найти 3-ей самую высокую зарплату, просто замените N на 3.
Удаление повторяющихся строк с помощью CTE
Таблица сотрудников:
| ID | FirstName | LastName | Gender | Salary | +------+-----------+----------+--------+--------+ | 1 | Mark | Hastings | Male | 60000 | | 1 | Mark | Hastings | Male | 60000 | | 2 | Mary | Lambeth | Female | 30000 | | 2 | Mary | Lambeth | Female | 30000 | | 3 | Ben | Hoskins | Male | 70000 | | 3 | Ben | Hoskins | Male | 70000 | | 3 | Ben | Hoskins | Male | 70000 | +------+-----------+----------+--------+--------+
CTE (общее выражение таблицы):
WITH EmployeesCTE AS ( SELECT *, ROW_NUMBER()OVER(PARTITION BY ID ORDER BY ID) AS RowNumber FROM Employees ) DELETE FROM EmployeesCTE WHERE RowNumber > 1
Результат выполнения:
| ID | FirstName | LastName | Gender | Salary | +------+-----------+----------+--------+--------+ | 1 | Mark | Hastings | Male | 60000 | | 2 | Mary | Lambeth | Female | 30000 | | 3 | Ben | Hoskins | Male | 70000 | +------+-----------+----------+--------+--------+
Создайте таблицу дат, используя CTE
DECLARE @startdate CHAR(8), @numberDays TINYINT SET @startdate = '20160101' SET @numberDays = 10; WITH CTE_DatesTable AS ( SELECT CAST(@startdate as date) AS [date] UNION ALL SELECT DATEADD(dd, 1, [date]) FROM CTE_DatesTable WHERE DATEADD(dd, 1, [date]) <= DateAdd(DAY, @numberDays-1, @startdate) ) SELECT [date] FROM CTE_DatesTable OPTION (MAXRECURSION 0)
Этот пример возвращает таблицу столбцов с одной колонкой, начиная с даты, указанной в переменной @startdate, и возвращает следующую дату @numberDays.
Рекурсивный CTE
Этот пример показывает, как получить каждый год с этого года до 2011 года (2012 - 1).
WITH yearsAgo ( myYear ) AS ( -- Base Case: This is where the recursion starts SELECT DATEPART(year, GETDATE()) AS myYear UNION ALL -- This MUST be UNION ALL (cannot be UNION) -- Recursive Section: This is what we're doing with the recursive call SELECT yearsAgo.myYear - 1 FROM yearsAgo WHERE yearsAgo.myYear >= 2012 ) SELECT myYear FROM yearsAgo; -- A single SELECT, INSERT, UPDATE, or DELETE
myYear 2016 2015 2014 2013 2012 2011 Вы можете управлять рекурсией (переполнение стека кода в коде) с помощью MAXRECURSION в качестве опции запроса, которая ограничивает количество рекурсивных вызовов.
WITH yearsAgo ( myYear ) AS ( -- Base Case SELECT DATEPART(year , GETDATE()) AS myYear UNION ALL -- Recursive Section SELECT yearsAgo.myYear - 1 FROM yearsAgo WHERE yearsAgo.myYear >= 2002 ) SELECT * FROM yearsAgo OPTION (MAXRECURSION 10);
Msg 530, уровень 16, состояние 1, строка 2Приложение завершено. Максимальная рекурсия 10 была исчерпана до завершения заявки.
CTE с несколькими операторами AS
;WITH cte_query_1 AS ( SELECT * FROM database.table1 ), cte_query_2 AS ( SELECT * FROM database.table2 ) SELECT * FROM cte_query_1 WHERE cte_query_one.fk IN ( SELECT PK FROM cte_query_2 )
С помощью обычных табличных выражений можно создавать несколько запросов с использованием операторов AS, разделенных запятыми. Затем запрос может ссылаться на любой или все эти запросы разными способами, даже если они присоединяются к ним.
Modified text is an extract of the original Stack Overflow DocumentationЛицензировано согласно CC BY-SA 3.0Не связан с Stack Overflow