问题
I know using cursors is a bad idea, but I just do not know how to solve this. I would like to iterate over my table list (select [table_name] from information_schema.tables) and issue a specific select statement on each of them.
Here is my attempt:
DECLARE c CURSOR READ_ONLY FAST_FORWARD FOR
SELECT [TABLE_NAME]
FROM INFORMATION_SCHEMA.TABLES
WHERE [TABLE_NAME] like 'TS%'
DECLARE @tableName char(7)
OPEN c
FETCH NEXT FROM c INTO @tableName
WHILE (@@FETCH_STATUS = 0)
BEGIN
-- which distinct ports has been used by inbound connections (listening sockets)?
SELECT [protocol], [src_ip], [dst_ip], [src_port], [dst_port], [path]
FROM (SELECT *, ROW_NUMBER() over (partition by [dst_port], [protocol] order by [id]) as RowNumber
FROM @tableName -- <<<<<< THIS IS WHERE IT FAILS
where [path] = 'RECEIVE') as a
WHERE a.RowNumber = 1 order by [dst_port];
FETCH NEXT FROM c into @tableName
END
CLOSE c
DEALLOCATE c
This fails with
Must declare the table variable "@tableName"
What would be a better way to "iterate" like "foreach" over my tables? Thanks in advance
回答1:
For that kind of scenario I don't think there is a better performing way than what you're already doing. There is the undocumented stored procedure sp_MSforeachtable but I wouldn't recommend it as it is not supported by Microsoft and under the hood will be doing a similar process to what you're already doing.
回答2:
Solution without cursor -
DECLARE @SQL NVARCHAR(MAX)
SELECT @SQL = STUFF((
SELECT '
SELECT [protocol], [src_ip], [dst_ip], [src_port], [dst_port], [path]
FROM (
SELECT *, rn = ROW_NUMBER() OVER (partition by dst_port, protocol ORDER BY id)
FROM [' + SCHEMA_NAME([schema_id]) + '].[' + name + ']
WHERE [path] = ''RECEIVE''
) a
WHERE a.rn = 1
ORDER BY dst_port;'
FROM sys.objects
WHERE [type] = 'U'
AND name LIKE 'TS%'
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
PRINT @SQL
EXEC sys.sp_executesql @SQL
Output -
SELECT [protocol], [src_ip], [dst_ip], [src_port], [dst_port], [path]
FROM (
SELECT *, rn = ROW_NUMBER() OVER (partition by dst_port, protocol ORDER BY id)
FROM [dbo].[table1]
WHERE [path] = 'RECEIVE'
) a
WHERE a.rn = 1
ORDER BY dst_port;
SELECT [protocol], [src_ip], [dst_ip], [src_port], [dst_port], [path]
FROM (
SELECT *, rn = ROW_NUMBER() OVER (partition by dst_port, protocol ORDER BY id)
FROM [dbo].[table2]
WHERE [path] = 'RECEIVE'
) a
WHERE a.rn = 1
ORDER BY dst_port;
来源:https://stackoverflow.com/questions/20904223/sql-server-iterate-over-all-tables-contained-in-a-database