将包含视图的代码转换为存储过程

Posted

技术标签:

【中文标题】将包含视图的代码转换为存储过程【英文标题】:Converting code containing views to stored procedure 【发布时间】:2012-09-11 04:16:49 【问题描述】:

我将这段代码拼凑在一起,以创建一个基于每个经销商的发票小计总和的数据透视表。它有效,并产生正确的结果。但是,当我尝试将其转换为存储过程时,臭名昭著的波浪形红线出现在 SQL Server 管理工作室的“CREATE VIEW Revenues”下,并且错误显示:

'CREATE VIEW 必须是批处理中的唯一语句',我不知道足够的 T-SQL 来继续,因为我需要能够从 ASP.NET/C# Web 应用程序执行它。

我正在尝试通过放置来创建一个 SP:

1)

USE [Sherwood]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROC [dbo].[usp_GetRevenues] 

@StartDate AS DateTime = '20120301',
@EndDate AS DateTime = '20120401'
AS
SET NOCOUNT ON;

BEGIN

在前面,末尾有一个 END 语句。

2) 参数对于能够过滤几个月的数据是必需的,但我似乎无法通过代码传递参数或使用变量。

提前致谢。

代码如下 - 显示我需要在哪里过滤变量。该代码仅适用于 where 子句中格式为 '1/1/2012' 的日期,但需要能够传递变量,如图所示。

--=================================

CREATE VIEW Revenues
AS
SELECT  
i.DateOrdered
,LTRIM(STR(DATEPART(MONTH,i.DateOrdered))) AS [Month]  
,LTRIM(STR(YEAR(i.Dateordered))) AS [Year]  
,c.CustomerCode
,SUM(i.Jobprice) AS Subtotal 
FROM Invoices i
JOIN
Customers c
ON i.CustomerID = c.ID
WHERE i.DateOrdered >= @StartDate 
AND i.DateOrdered <= @EndDate **<-- and here.**  
GROUP BY ROLLUP (YEAR(i.DateOrdered), 
MONTH(i.DateOrdered), i.DateOrdered, c.CustomerCode);
GO

IF OBJECT_ID('Revenues2') IS NOT NULL
DROP VIEW Revenues2
GO

CREATE VIEW Revenues2
AS
SELECT 
 LTRIM(STR([YEAR])) + '-' + STUFF([Month],1,0, REPLICATE('0', 2 - LEN([Month]))) 
 AS [Date] 
,Subtotal
,CustomerCode
FROM Revenues
WHERE CustomerCode IS NOT NULL
GO

DECLARE @query VARCHAR(4000)  
DECLARE @years VARCHAR(2000)  
SELECT  @years = STUFF(( SELECT DISTINCT 
                    '],[' + [Date]  
                    FROM  Revenues2 
                    ORDER BY '],[' + [Date]  
                    FOR XML PATH('')  
                    ), 1, 2, '') + ']' 

SET @query =  
'SELECT * FROM  
(  
  SELECT Subtotal,[Date],CustomerCode  
   FROM Revenues2  
)t  
PIVOT (SUM(Subtotal) FOR [Date] 
IN ('+ @years +')) AS pvt' 

EXECUTE (@query) 

--============================================

问候

悬崖

【问题讨论】:

您使用的是哪个版本的 SQL SERVER? 【参考方案1】:

我可能错了,但在我看来,当您转换为 SP 时,您并没有删除/评论“CREATE VIEW”部分。这是错误的,因为您无法在存储过程的定义中定义视图 - 因此“CREATE VIEW must be(...)”投诉。

此外,您的代码有点脆弱:一旦您正确创建了 SP,下次运行它会出错,并显示“SP 已使用,您应该使用 ALTER PROC”或其他信息像那样(我是凭记忆写的)。

这样的代码应该可以解决这两个问题:

USE [Sherwood]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

-- It's preferable to set these options before creating an SP,
-- rather than within its execution
SET NOCOUNT ON
GO
IF OBJECT_ID('usp_GetRevenues') IS NOT NULL
    DROP PROC usp_GetRevenues
GO
CREATE PROC [dbo].[usp_GetRevenues] 
    @StartDate AS DateTime = '20120301',
    @EndDate AS DateTime = '20120401' AS
-- BEGIN --This is really optional
SELECT  
i.DateOrdered
,LTRIM(STR(DATEPART(MONTH,i.DateOrdered))) AS [Month]  
,LTRIM(STR(YEAR(i.Dateordered))) AS [Year]  
,c.CustomerCode
,SUM(i.Jobprice) AS Subtotal 
FROM dbo.Invoices i
JOIN dbo.Customers c
ON i.CustomerID = c.ID
WHERE i.DateOrdered >= @StartDate 
AND i.DateOrdered <= @EndDate **<-- and here.**  
GROUP BY ROLLUP (YEAR(i.DateOrdered), 
MONTH(i.DateOrdered), i.DateOrdered, c.CustomerCode);
GO

【讨论】:

我创建了视图,因为我必须对来自先前 SELECT 语句的数据集执行操作。我是创建和删除临时表还是处理这种情况的最佳方法是什么,你能否给我一些想法如何编码 - 因为我不知道 - 因此是视图。感谢您的帮助。【参考方案2】:

你可以改用临时表来试试这个。

类似

SELECT   
i.DateOrdered 
,LTRIM(STR(DATEPART(MONTH,i.DateOrdered))) AS [Month]   
,LTRIM(STR(YEAR(i.Dateordered))) AS [Year]   
,c.CustomerCode 
,SUM(i.Jobprice) AS Subtotal  
INTO #Revenues
FROM Invoices i 
JOIN 
Customers c 
ON i.CustomerID = c.ID 
WHERE i.DateOrdered >= @StartDate  
AND i.DateOrdered <= @EndDate **<-- and here.**   
GROUP BY ROLLUP (YEAR(i.DateOrdered),  
MONTH(i.DateOrdered), i.DateOrdered, c.CustomerCode)

SELECT  
 LTRIM(STR([YEAR])) + '-' + STUFF([Month],1,0, REPLICATE('0', 2 - LEN([Month])))  
 AS [Date]  
,Subtotal 
,CustomerCode 
INTO #Revenues2
FROM #Revenues 
WHERE CustomerCode IS NOT NULL 

DECLARE @query VARCHAR(4000)   
DECLARE @years VARCHAR(2000)   
SELECT  @years = STUFF(( SELECT DISTINCT  
                    '],[' + [Date]   
                    FROM  #Revenues2  
                    ORDER BY '],[' + [Date]   
                    FOR XML PATH('')   
                    ), 1, 2, '') + ']'  

SET @query =   
'SELECT * FROM   
(   
  SELECT Subtotal,[Date],CustomerCode   
   FROM #Revenues2   
)t   
PIVOT (SUM(Subtotal) FOR [Date]  
IN ('+ @years +')) AS pvt'  

EXECUTE (@query)

DROP TABLE #Revenues
DROP TABLE #Revenues2

【讨论】:

临时表。好主意,它几乎可以编译。我在 SET @query 第 56 行内的 SELECT 语句上收到语法错误。实际错误是 Msg 102, Level 15, State 1, Procedure usp_GetRevenues, Line 56 Incorrect syntax near 'END'。 删除 BEGIN 和 END 产生了很大的不同,临时表绝对是要走的路 - 它编译并运行。感谢您的帮助 - 悬崖

以上是关于将包含视图的代码转换为存储过程的主要内容,如果未能解决你的问题,请参考以下文章

将存储过程 PL/SQL 转换为 Java

MYSQL数据太大时怎么优化 视图?存储过程? - 技术问答

将结果行强制转换为对象

SQL Server 存储过程包含 SQL 或调用查看

mySQL 存储过程中未知的无效类型转换

如何改进包含存储过程使用的多个自联接的视图