2014-01-03 10 views
4

Я знаю, что использование курсоров - плохая идея, но я просто не знаю, как это решить. Я хотел бы перебрать мой список таблиц (select [table_name] from information_schema.tables) и выдать конкретный оператор select для каждого из них.SQL Server: Итерация по всем таблицам, содержащимся в базе данных

Вот моя попытка:

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 

Это терпит неудачу с

Необходимо объявить переменную таблицы "@tableName"

Что было бы лучшим способом "итерация" как «foreach» над моими столами? Заранее спасибо

+1

Ошибка вызвана тем, что мы не можем иметь SELECT * FROM @variable в сервере SQL. нам нужно будет использовать динамический sql для выполнения этого запроса. Добавление комментария, поскольку я не видел этого нигде. – nee21

ответ

1

Для такого сценария я не думаю, что есть более эффективный способ, чем то, что вы уже делаете. Существует недокументированная хранимая процедура sp_MSforeachtable, но я бы не рекомендовал ее, так как она не поддерживается Microsoft, и под капотом будет выполняться аналогичный процесс с тем, что вы уже делаете.

1

Решение без курсора -

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 

Выход -

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; 
+1

Не используйте '['+ name +']', но используйте '+ quotename (name) +', которые были квадратными скобками в имени таблицы, не будут нарушать вещи. (также оберните предложение schema_name() в вызове quotename) –

+0

Очень умный! К сожалению, моя база данных содержит 268 таблиц, которые превысят NVARCHAR (MAX) (до 4000). Каждый размер операторов составляет 292 байта, а 268 - 78256. Ой! – Matze

+1

Существует ограничение на 'NVARCHAR (MAX)' - это 2^31-1 байта (2 ГБ) – Devart

Смежные вопросы