我在客户端有一个奇怪的设置。有一个表定义了一些类别。其中一个字段是包含此类别详细信息的视图。这些类别是动态设置的,因此表中的视图列。我想要完成的是选择这些类别,并从每个类别的相关视图中获取一些统计数据。
我知道我不能在返回表的函数中执行此操作,因为我需要动态构建查询而函数不能使用sp_executesql
唯一的选择似乎是在存储过程中写这个,但我希望可能有更好的方法。
CREATE TABLE Categories
(CategoryID int,
CategoryView varchar(255)
)
GO
CREATE VIEW Cat_Objects
AS
Select * from sys.objects
GO
CREATE VIEW Cat_Procedures
AS
Select * from sys.procedures
GO
INSERT Categories VALUES (1, 'Cat_Objects')
INSERT Categories VALUES (2, 'Cat_Procedures')
我想用viewname构建一个动态查询并执行
Select Count(1), MIN(create_date), Max(create_date) from Cat_Objects
所以这是我的解决方案,但看起来非常笨重。
DECLARE @CategoryID int,
@View varchar(255)
Select * into #objects from Categories
DECLARE @Table TABLE (
CatID int,
ObjectCnt int,
MinCreateDate DATETIME,
MaxCreateDate DATETIME)
WHILE(0 < (Select count(1) from #objects))
BEGIN
SET ROWCOUNT 1
Select @CategoryID = CategoryID, @View = CategoryView from #objects
SET ROWCOUNT 0
DECLARE @query NVARCHAR(MAX) = N'Select @objectCntOUT=COUNT(1), @minCreateDateOUT=MIN(create_date), @maxCreateDateOUT=MAX(create_date)
FROM ' + @View
PRINT @query
DECLARE @ParmDefinition NVARCHAR(500) = N'@objectCntOUT INT OUTPUT, @minCreateDateOUT DATETIME OUTPUT, @maxCreateDateOUT DATETIME OUTPUT';
Declare @objectCnt int,
@minCreateDate DATETIME,
@maxCreateDate DATETIME
exec sp_executesql @query, @ParmDefinition, @objectCntOUT=@objectCnt OUTPUT, @minCreateDateOUT=@minCreateDate OUTPUT, @maxCreateDateOUT=@maxCreateDate OUTPUT
INSERT @Table VALUES(@CategoryID, @objectCnt, @minCreateDate, @maxCreateDate)
DELETE #objects WHERE CategoryID = @CategoryID
END
Select * from @Table
问题是:是否可以做得更好?没有while循环等。
答案 0 :(得分:2)
您可以将此查询简化为:
IF OBJECT_ID(N'tempdb..##ResultTable') IS NOT NULL DROP TABLE ##ResultTable
CREATE TABLE ##ResultTable (
CatID int,
ObjectCnt int,
MinCreateDate DATETIME,
MaxCreateDate DATETIME
)
DECLARE @query NVARCHAR(MAX) = N''
SELECT @query = @query + N'INSERT INTO ##ResultTable
SELECT CAST(''' +CAST(CategoryID as nvarchar(100)) +''' as int),
COUNT(1),
MIN(create_date),
MAX(create_date)
FROM ' + QUOTENAME(CategoryView) + ';' +CHAR(13)
FROM Categories
EXEC sp_executesql @query
SELECT *
FROM ##ResultTable
如果您PRINT @query
,您将获得:
INSERT INTO ##ResultTable
SELECT CAST('1' as int),
COUNT(1),
MIN(create_date),
MAX(create_date)
FROM [Cat_Objects];
INSERT INTO ##ResultTable
SELECT CAST('2' as int),
COUNT(1),
MIN(create_date),
MAX(create_date)
FROM [Cat_Procedures];
<强>更新#1 强>
您可以使用UNION ALL
:
DECLARE @query NVARCHAR(MAX) = N''
SELECT @query = @query + N'UNION ALL
SELECT CAST(''' +CAST(CategoryID as nvarchar(100)) +''' as int),
COUNT(1),
MIN(create_date),
MAX(create_date)
FROM ' + QUOTENAME(CategoryView) +CHAR(13)
FROM Categories
SELECT @query = 'INSERT INTO ##ResultTable'+CHAR(13) + STUFF(@query,1,10,'')
打印:
INSERT INTO ##ResultTable
SELECT CAST('1' as int),
COUNT(1),
MIN(create_date),
MAX(create_date)
FROM [Cat_Objects]
UNION ALL
SELECT CAST('2' as int),
COUNT(1),
MIN(create_date),
MAX(create_date)
FROM [Cat_Procedures]
<强>更新#2 强>
还有一种方法可以创建一些视图然后用动态SQL改变它:
CREATE VIEW [dbo].[SomeViewName]
AS
SELECT NULL AS D
并使用这部分:
DECLARE @query NVARCHAR(MAX) = N''
SELECT @query = @query + N'UNION ALL
SELECT CAST(''' +CAST(CategoryID as nvarchar(100)) +''' as int),
COUNT(1),
MIN(create_date),
MAX(create_date)
FROM ' + QUOTENAME(CategoryView) +CHAR(13)
FROM Categories
SELECT @query = 'ALTER VIEW [dbo].[SomeViewName] AS '+CHAR(13) + STUFF(@query,1,10,'')
之后,您可以使用[dbo].[SomeViewName]
来获取所需的数据,而不是临时表。