从动态sql中检索值

时间:2017-12-01 09:58:38

标签: sql sql-server dynamic-sql

我在客户端有一个奇怪的设置。有一个表定义了一些类别。其中一个字段是包含此类别详细信息的视图。这些类别是动态设置的,因此表中的视图列。我想要完成的是选择这些类别,并从每个类别的相关视图中获取一些统计数据。

我知道我不能在返回表的函数中执行此操作,因为我需要动态构建查询而函数不能使用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循环等。

1 个答案:

答案 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]来获取所需的数据,而不是临时表。