了解动态 SQL
Understanding dynamic SQL
在尝试理解动态 SQL 的过程中,我尝试通过动态插入 sys.tables
的每个表中的行数计数来开始简单操作。
这是我的代码:
SELECT
Name, ROW_NUMBER() OVER (ORDER BY NEWID() ) AS SomeNumb
INTO
#Dyn
FROM
sys.tables
CREATE TABLE ##Results (Cnt INT)
DECLARE @Table NVARCHAR(100)
DECLARE @Counter INT
SET @Counter = 1
SET @Table = (SELECT Name FROM #Dyn WHERE SomeNumb = @Counter)
DECLARE @Sql NVARCHAR(1000)
WHILE @Counter <= (SELECT COUNT(*) FROM #Dyn)
BEGIN
INSERT INTO ##ResultsTable
SELECT @Sql = 'SELECT COUNT(*) AS Cnt FROM #Dyn WHERE
Name = ' + @Table + 'AND SomeNumb = ' + @Counter
EXECUTE (@Sql)
SET @Counter = @Counter + 1
SET @Sql = ''
END
SELECT * FROM ##ResultsTable
唯一的好处就是不会出错。尽管这可能会给我一些方向。我知道我的 ResultsTable
存在范围问题,但我认为使用 ##
而不是 # 可以解决这个问题。
任何指点将不胜感激。
这里有一个经过审核的脚本。
IF OBJECT_ID('tempdb..#Dyn') IS NOT NULL
DROP TABLE #Dyn
SELECT Name, ROW_NUMBER() OVER (ORDER BY NEWID() ) AS SomeNumb
INTO #Dyn
FROM sys.tables
IF OBJECT_ID('tempdb..#ResultsTable') IS NOT NULL
DROP TABLE #ResultsTable
CREATE TABLE #ResultsTable (TotalRowCount INT)
DECLARE @Counter INT = 1
DECLARE @Sql NVARCHAR(MAX)
WHILE @Counter <= (SELECT COUNT(*) FROM #Dyn)
BEGIN
DECLARE @Table NVARCHAR(100) = (SELECT Name FROM #Dyn WHERE SomeNumb = @Counter)
SELECT @Sql = '
INSERT INTO #ResultsTable (TotalRowCount)
SELECT COUNT(*) AS Cnt
FROM #Dyn
WHERE Name = ''' + @Table + ''' AND SomeNumb = ' + CONVERT(NVARCHAR(10), @Counter)
EXECUTE (@Sql)
SET @Counter += 1
END
SELECT * FROM #ResultsTable
有些事情要提一下:
- 您可以在 EXEC 外部创建临时 table 并将其插入动态 SQL。
- 您的
COUNT()
的 #Dyn
table 将始终 return 1 因为只有 1 条记录具有特定的 table 名称。
- 在动态 SQL:
上打印 varchar 值(如 @Table)时,您需要添加额外的引号
- 构建动态 SQL(如
@Counter
)时,您需要将所有非文字值转换为 VARCHAR
或 NVARCHAR
。
编辑:如果你想要每个 table 的实际计数,那么你不需要查询 #Dyn
!
SELECT @Sql = '
INSERT INTO #ResultsTable (TotalRowCount)
SELECT COUNT(*) AS Cnt
FROM ' + QUOTENAME(@Table) +
EXECUTE (@Sql)
与其使用 CURSOR
或 WHILE
循环,一种方法是使用 sys.tables
和 sys.schemas
以及 FOR XML PATH
:
DECLARE @SQL nvarchar(MAX);
SET @SQL = (SELECT N'SELECT ''' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.name) +''' AS ObjectName, COUNT(*) AS [RowCount]' + NCHAR(10) +
N'FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + N';' + NCHAR(10)
FROM sys.tables t
JOIN sys.schemas s ON t.SCHEMA_ID = s.SCHEMA_ID
FOR XML PATH(N''))
PRINT @SQL;
CREATE TABLE #Cnt (ObjectName sysname, [RowCount] int);
INSERT INTO #Cnt (ObjectName, [RowCount])
EXEC sp_executesql @SQL;
SELECT *
FROM #cnt;
DROP TABLE #cnt;
或者,您可以使用未记录的过程 sp_msforeachtable
:
CREATE TABLE #Cnt (ObjectName sysname, [RowCount] int);
INSERT INTO #Cnt (ObjectName, [RowCount])
EXEC sp_msforeachtable N'SELECT ''?'' AS ObjectName, COUNT(*) AS [RowCount]
FROM ?;';
SELECT *
FROM #cnt;
DROP TABLE #cnt;
但是,如果我没记错的话,后一种方法实际上使用了 CURSOR
。
在尝试理解动态 SQL 的过程中,我尝试通过动态插入 sys.tables
的每个表中的行数计数来开始简单操作。
这是我的代码:
SELECT
Name, ROW_NUMBER() OVER (ORDER BY NEWID() ) AS SomeNumb
INTO
#Dyn
FROM
sys.tables
CREATE TABLE ##Results (Cnt INT)
DECLARE @Table NVARCHAR(100)
DECLARE @Counter INT
SET @Counter = 1
SET @Table = (SELECT Name FROM #Dyn WHERE SomeNumb = @Counter)
DECLARE @Sql NVARCHAR(1000)
WHILE @Counter <= (SELECT COUNT(*) FROM #Dyn)
BEGIN
INSERT INTO ##ResultsTable
SELECT @Sql = 'SELECT COUNT(*) AS Cnt FROM #Dyn WHERE
Name = ' + @Table + 'AND SomeNumb = ' + @Counter
EXECUTE (@Sql)
SET @Counter = @Counter + 1
SET @Sql = ''
END
SELECT * FROM ##ResultsTable
唯一的好处就是不会出错。尽管这可能会给我一些方向。我知道我的 ResultsTable
存在范围问题,但我认为使用 ##
而不是 # 可以解决这个问题。
任何指点将不胜感激。
这里有一个经过审核的脚本。
IF OBJECT_ID('tempdb..#Dyn') IS NOT NULL
DROP TABLE #Dyn
SELECT Name, ROW_NUMBER() OVER (ORDER BY NEWID() ) AS SomeNumb
INTO #Dyn
FROM sys.tables
IF OBJECT_ID('tempdb..#ResultsTable') IS NOT NULL
DROP TABLE #ResultsTable
CREATE TABLE #ResultsTable (TotalRowCount INT)
DECLARE @Counter INT = 1
DECLARE @Sql NVARCHAR(MAX)
WHILE @Counter <= (SELECT COUNT(*) FROM #Dyn)
BEGIN
DECLARE @Table NVARCHAR(100) = (SELECT Name FROM #Dyn WHERE SomeNumb = @Counter)
SELECT @Sql = '
INSERT INTO #ResultsTable (TotalRowCount)
SELECT COUNT(*) AS Cnt
FROM #Dyn
WHERE Name = ''' + @Table + ''' AND SomeNumb = ' + CONVERT(NVARCHAR(10), @Counter)
EXECUTE (@Sql)
SET @Counter += 1
END
SELECT * FROM #ResultsTable
有些事情要提一下:
- 您可以在 EXEC 外部创建临时 table 并将其插入动态 SQL。
- 您的
COUNT()
的#Dyn
table 将始终 return 1 因为只有 1 条记录具有特定的 table 名称。 - 在动态 SQL: 上打印 varchar 值(如 @Table)时,您需要添加额外的引号
- 构建动态 SQL(如
@Counter
)时,您需要将所有非文字值转换为VARCHAR
或NVARCHAR
。
编辑:如果你想要每个 table 的实际计数,那么你不需要查询 #Dyn
!
SELECT @Sql = '
INSERT INTO #ResultsTable (TotalRowCount)
SELECT COUNT(*) AS Cnt
FROM ' + QUOTENAME(@Table) +
EXECUTE (@Sql)
与其使用 CURSOR
或 WHILE
循环,一种方法是使用 sys.tables
和 sys.schemas
以及 FOR XML PATH
:
DECLARE @SQL nvarchar(MAX);
SET @SQL = (SELECT N'SELECT ''' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.name) +''' AS ObjectName, COUNT(*) AS [RowCount]' + NCHAR(10) +
N'FROM ' + QUOTENAME(s.[name]) + N'.' + QUOTENAME(t.[name]) + N';' + NCHAR(10)
FROM sys.tables t
JOIN sys.schemas s ON t.SCHEMA_ID = s.SCHEMA_ID
FOR XML PATH(N''))
PRINT @SQL;
CREATE TABLE #Cnt (ObjectName sysname, [RowCount] int);
INSERT INTO #Cnt (ObjectName, [RowCount])
EXEC sp_executesql @SQL;
SELECT *
FROM #cnt;
DROP TABLE #cnt;
或者,您可以使用未记录的过程 sp_msforeachtable
:
CREATE TABLE #Cnt (ObjectName sysname, [RowCount] int);
INSERT INTO #Cnt (ObjectName, [RowCount])
EXEC sp_msforeachtable N'SELECT ''?'' AS ObjectName, COUNT(*) AS [RowCount]
FROM ?;';
SELECT *
FROM #cnt;
DROP TABLE #cnt;
但是,如果我没记错的话,后一种方法实际上使用了 CURSOR
。