从动态 sql 中检索值

Retrieve values from dynamic sql

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

我知道我不能在返回 table 的函数中执行此操作,因为我需要动态构建查询并且函数不能使用 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')

我想用视图名构建动态查询并执行

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 循环等

您可以将此查询简化为:

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] 来获取您需要的数据而不是临时表。