从动态 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]
来获取您需要的数据而不是临时表。
我在客户那里有一个奇怪的设置。有一个 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]
来获取您需要的数据而不是临时表。