Sql中使用With创建多张临时表

CREATE PROC [dbo].[sp_VisitCount]
(
    @count INT
)
AS BEGIN
DECLARE @current DATETIME
SET @current=GETDATE();

WITH 
TodayVisitTable AS
(
    SELECT CorpName,COUNT(CorpName) AS TodayVisit
    FROM dbo.VisitRecords 
    WHERE YEAR(VisitTime)=YEAR(@current)
    AND MONTH(VisitTime)=MONTH(@current)
    AND DAY(VisitTime)=DAY(@current)
    GROUP BY CorpName
),
TotalVisitTable AS
(
    SELECT CorpName,COUNT(CorpName) AS TotalVisit
    FROM dbo.VisitRecords
    GROUP BY CorpName
),
QUERY AS 
(
    SELECT Row_number() OVER (ORDER BY TodayVisit DESC,TotalVisit DESC) AS RowNum,TotalVisitTable.CorpName,TodayVisit,TotalVisit
    FROM  TotalVisitTable
    LEFT JOIN TodayVisitTable ON TodayVisitTable.CorpName = TotalVisitTable.CorpName
)
SELECT RowNum,CorpName,ISNULL(TodayVisit,0) AS TodayVisit,TotalVisit
  FROM QUERY
 WHERE RowNum <= @count
 END

 

转载于:https://www.cnblogs.com/mtsl/p/4234589.html

<think>我们正在讨论的是SQL Server中使用WITH子句(即公用表表达式,CTE)来创建临时结果集的方法。注意:CTE本身并不是临时表,而是一个临时的命名结果集,它只在查询期间有效。但有时人们会将CTE称为“临时表”,尽管从技术上讲它并不是表。 根据引用[2]中的描述:WITH语句(CTE)是用于简化复杂查询逻辑的工具。CTE可以看作是一个临时的视图,只存在于当前查询中。 如果你想要使用WITH创建临时结果集,然后将其存储到临时表中,那么需要分两步: 1. 使用WITH定义CTE。 2. 将CTE的结果插入到一个临时表(以#开头的表)或表变量中。 但是,如果只是使用CTE,它本身并不存储为临时表,而是作为一个子查询的替代,可在一个查询中被多次引用(递归CTE)或提高可读性。 下面我将分别给出: (1) 使用CTE(WITH子句)的语法和示例(不创建临时表,只创建临时结果集)。 (2) 如何将CTE的结果存储到临时表(真正的临时表)中。 注意:引用[1]和[3]提到了临时表(以#开头的表)的特性,如生命周期和存储位置。而CTE与临时表是不同的概念。 一、使用CTE(WITH子句)的语法和示例(不创建临时表) 语法: WITH cte_name (column1, column2, ...) AS ( -- 定义CTE的查询 SELECT ... ) -- 使用CTE的查询 SELECT * FROM cte_name; 示例1:简单的CTE WITH Sales_CTE (SalesPersonID, TotalSales) AS ( SELECT SalesPersonID, SUM(TotalDue) AS TotalSales FROM Sales.SalesOrderHeader GROUP BY SalesPersonID ) SELECT SalesPersonID, TotalSales FROM Sales_CTE WHERE TotalSales > 1000000; 示例2:递归CTE(用于层次结构) WITH Employees_CTE (EmployeeID, ManagerID, Title, Level) AS ( -- 锚点成员 SELECT EmployeeID, ManagerID, Title, 0 AS Level FROM Employee WHERE ManagerID IS NULL UNION ALL -- 递归成员 SELECT e.EmployeeID, e.ManagerID, e.Title, Level + 1 FROM Employee e INNER JOIN Employees_CTE ecte ON e.ManagerID = ecte.EmployeeID ) SELECT EmployeeID, ManagerID, Title, Level FROM Employees_CTE; 二、将CTE的结果存储到临时表中 如果你希望将CTE的结果保存下来,以便在后续的查询中多次使用(特别是当数据量较大或需要重复使用时),可以将其插入到临时表。 语法: WITH cte_name (column1, column2, ...) AS ( SELECT ... ) SELECT * INTO #TempTable -- 将CTE的结果插入到临时表 FROM cte_name; -- 然后可以查询这个临时表 SELECT * FROM #TempTable; 注意:临时表(#TempTable)会在会话结束(或显式删除)时自动删除。 示例: WITH Sales_CTE (SalesPersonID, TotalSales) AS ( SELECT SalesPersonID, SUM(TotalDue) AS TotalSales FROM Sales.SalesOrderHeader GROUP BY SalesPersonID ) SELECT * INTO #SalesTemp -- 创建临时表并存储CTE的结果 FROM Sales_CTE; -- 使用临时表 SELECT * FROM #SalesTemp WHERE TotalSales > 1000000; -- 使用完后,可以显式删除(也可以等待自动删除) DROP TABLE #SalesTemp; 三、将CTE的结果存储到表变量中 另一种选择是使用表变量,尤其当数据量不大时。 语法: DECLARE @SalesTable TABLE (SalesPersonID INT, TotalSales MONEY); WITH Sales_CTE (SalesPersonID, TotalSales) AS ( SELECT SalesPersonID, SUM(TotalDue) AS TotalSales FROM Sales.SalesOrderHeader GROUP BY SalesPersonID ) INSERT INTO @SalesTable (SalesPersonID, TotalSales) SELECT SalesPersonID, TotalSales FROM Sales_CTE; -- 使用表变量 SELECT * FROM @SalesTable; 总结: - CTE(WITH子句)本身并不创建临时表,而是定义一个临时的结果集,它只在紧随其后的单个查询中有效。 - 如果需要重复使用结果集,可以考虑将CTE的结果插入到临时表(#开头)或表变量中。 - 临时表的生命周期为当前会话,而表变量的生命周期为当前批处理(或存储过程等)。 根据引用[2]中的比较,临时表适合大数据量操作,表变量适合小数据量场景,而CTE则用于简化查询逻辑。 请注意,在将CTE结果插入临时表时,临时表的列名和数据类型由CTE的查询结果决定。你也可以在临时表创建中自定义列名和数据类型(通过预先创建临时表,然后使用INSERT INTO,而不是SELECT INTO)。 例如,预先创建临时表: CREATE TABLE #SalesTemp ( SalesPersonID INT, TotalSales MONEY ); WITH Sales_CTE (SalesPersonID, TotalSales) AS ( ... ) INSERT INTO #SalesTemp (SalesPersonID, TotalSales) SELECT SalesPersonID, TotalSales FROM Sales_CTE; 这样可以对临时表的结构有更多的控制。 希望这些示例和解释能够帮助你理解如何使用WITH创建临时结果集,以及如何将其存储到临时表中。</think>### SQL Server 使用 WITH 创建临时结果集(CTE)的语法与示例 在 SQL Server 中,`WITH` 子句用于创建**公用表表达式(CTE)**,这是一种临时的命名结果集,**不是物理临时表**(如 `#temp`)。CTE 仅在当前查询范围内有效,执行后自动销毁,适合简化复杂查询逻辑[^2]。 --- ### 基础语法 ```sql WITH CTE_Name (列名1, 列名2, ...) -- 可选列名定义 AS ( -- 查询定义 SELECT 列1, 列2, ... FROM 表 WHERE 条件 ) -- 主查询(必须紧接CTE定义) SELECT * FROM CTE_Name; ``` --- ### 示例场景 假设有订单表 `Orders`: | OrderID | CustomerID | Amount | |---------|------------|--------| | 1 | A001 | 100 | | 2 | A001 | 200 | | 3 | B002 | 150 | #### 示例 1:基础 CTE(计算客户总消费) ```sql WITH CustomerSpending (CustomerID, TotalAmount) AS ( SELECT CustomerID, SUM(Amount) FROM Orders GROUP BY CustomerID ) -- 查询高消费客户(使用CTE结果) SELECT CustomerID, TotalAmount FROM CustomerSpending WHERE TotalAmount > 150; ``` **结果:** | CustomerID | TotalAmount | |------------|-------------| | A001 | 300 | --- #### 示例 2:递归 CTE(生成数字序列) ```sql WITH Numbers AS ( -- 初始值(锚点成员) SELECT 1 AS Number UNION ALL -- 递归成员 SELECT Number + 1 FROM Numbers WHERE Number < 5 ) SELECT * FROM Numbers; ``` **结果:** | Number | |--------| | 1 | | 2 | | 3 | | 4 | | 5 | --- #### 示例 3:多 CTE 链式调用 ```sql -- 第一个CTE:过滤高金额订单 WITH HighOrders AS ( SELECT OrderID, Amount FROM Orders WHERE Amount > 100 ), -- 第二个CTE:基于第一个CTE的结果 CustomerHighSpending AS ( SELECT CustomerID, SUM(Amount) AS HighTotal FROM Orders o JOIN HighOrders h ON o.OrderID = h.OrderID GROUP BY CustomerID ) -- 最终查询 SELECT * FROM CustomerHighSpending; ``` --- ### 重要注意事项 1. **非物理存储** CTE 是**逻辑临时结果集**,不存储到 `tempdb`(对比物理临时表 `#temp`)[^1][^3]。 2. **作用域限制** CTE 仅在紧随其后的 `SELECT/INSERT/UPDATE/DELETE` 语句中可用: ```sql WITH MyCTE AS (...) SELECT * FROM MyCTE; -- ✅ 有效 SELECT * FROM MyCTE; -- ❌ 无效(超出作用域) ``` 3. **与临时表的转换** 若需物理存储,可将 CTE 结果插入临时表: ```sql WITH MyCTE AS (...) SELECT * INTO #PhysicalTemp -- 创建物理临时表 FROM MyCTE; ``` --- ### 适用场景推荐 | **工具** | 最佳场景 | 数据量 | 生命周期 | |----------------|----------------------------------|----------|---------------| | **CTE (WITH)** | 简化嵌套查询/递归查询 | 中小型 | 单次查询内有效 | | **#临时表** | 跨多个查询复用结果/大表中间存储 | 大型 | 会话结束自动删除 | | **表变量** | 小数据集快速操作/存储过程参数传递 | 小型 | 批处理结束销毁 | > 根据引用[2]建议:优先用 CTE 简化代码逻辑,大数据量或跨查询复用选临时表[^2]。 --- ### 递归 CTE 深度控制 递归查询默认最大深度 100 层,可调整: ```sql OPTION (MAXRECURSION 200) -- 设置递归上限 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值