Мне нужно посчитать, сколько раз ключ используется в разных таблицах.У меня есть следующий код, который получает все таблицы, которые ссылаются на ключ:
SELECT s.SCHEMA_NAME,
OBJECT_NAME(f.parent_object_id) AS TableName,
COL_NAME(fc.parent_object_id, fc.parent_column_id) AS ColumnName
FROM sys.foreign_keys AS f
INNER JOIN sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id
OUTER APPLY
(
SELECT i.SCHEMA_NAME
FROM INFORMATION_SCHEMA.SCHEMATA i
INNER JOIN SYS.TABLES s
ON i.SCHEMA_NAME = SCHEMA_NAME(s.SCHEMA_ID)
WHERE f.parent_object_id = s.object_id
) AS s
WHERE OBJECT_NAME (f.referenced_object_id) = 'Languages'
Результат:
SchemaName, TableName, ColumnName
Ивот запрос, который я должен сделать для каждой возвращаемой строки, и, наконец, СУММ всех из них:
SELECT COUNT(*)
FROM SchemaName.TableName t
WHERE t.ColumnName = @LanguageId
Я читал о CURSOR и динамическом SQL, но я не смог найти способ сделать эторабота (никогда не использовал ни один из них).
Использование курсоров / динамического SQL не является обязательным.Если есть более простые способы, которые я ценю.
РЕДАКТИРОВАТЬ: мне удалось заставить его работать.РЕДАКТИРОВАТЬ 2: Некоторый рефакторинг и полная реализация фактического требования.
DECLARE @WantedDefaultLanguageId INT = 1;
--Internal Variables
DECLARE @DefaultLanguageId INT = (SELECT Id FROM i18n.Languages WHERE IsDefault = 1)
, @SqlCommand NVARCHAR(1000)
, @SchemaName SYSNAME
, @TableName SYSNAME
, @FieldName SYSNAME
, @CurrentValue INT
, @DefaultTotal INT = 0
, @WantedTotal INT = 0;
DECLARE relationships CURSOR
LOCAL FAST_FORWARD READ_ONLY
FOR SELECT schemaNames.SCHEMA_NAME,
OBJECT_NAME(foreignKeys.parent_object_id) AS TableName,
COL_NAME(foreignKeysColumns.parent_object_id, foreignKeysColumns.parent_column_id) AS ColumnName
FROM sys.foreign_keys AS foreignKeys
INNER JOIN sys.foreign_key_columns AS foreignKeysColumns
ON foreignKeys.OBJECT_ID = foreignKeysColumns.constraint_object_id
OUTER APPLY
(
SELECT metadata.SCHEMA_NAME
FROM INFORMATION_SCHEMA.SCHEMATA metadata
INNER JOIN SYS.TABLES AS sysTables
ON metadata.SCHEMA_NAME = SCHEMA_NAME(sysTables.SCHEMA_ID)
WHERE foreignKeys.parent_object_id = sysTables.object_id
) AS schemaNames
WHERE OBJECT_NAME (foreignKeys.referenced_object_id) = 'Languages';
IF @DefaultLanguageId = @WantedDefaultLanguageId
SELECT 1;
ELSE
BEGIN
OPEN relationships
FETCH NEXT FROM relationships
INTO @SchemaName, @TableName, @FieldName;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @SqlCommand = '
SELECT @CurrentValue = COUNT(*)
FROM ' + @SchemaName + '.' + @TableName + ' tableName
WHERE tableName.' + @FieldName + ' = ' + CAST(@DefaultLanguageId AS nvarchar(1000))
EXEC sp_executesql @SqlCommand, N'@CurrentValue INT OUTPUT', @CurrentValue OUTPUT
SET @DefaultTotal += @CurrentValue
--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
SET @SqlCommand = '
SELECT @CurrentValue = COUNT(*)
FROM ' + @SchemaName + '.' + @TableName + ' tableName
WHERE tableName.' + @FieldName + ' = ' + CAST(@WantedDefaultLanguageId AS nvarchar(1000))
EXEC sp_executesql @SqlCommand, N'@CurrentValue INT OUTPUT', @CurrentValue OUTPUT
SET @WantedTotal += @CurrentValue
--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
FETCH NEXT FROM relationships
INTO @SchemaName, @TableName, @FieldName;
END
CLOSE relationships
DEALLOCATE relationships
SELECT CASE
WHEN @WantedTotal = @DefaultTotal THEN
1
ELSE 0
END
END;
Требуется очень много времени для запуска.Этот запрос будет выполняться не очень часто, но любая помощь по его улучшению / более эффективные способы реализации этой функциональности приветствуются.(Я закрою вопрос позже).
Edit3: Хорошо, вот пример того, что мне нужно:
Table: Language
Id Language
1 English
RelationalTable1
... LanguageId
1
1
2
AllOtherRelationalTables
...
Мне нужно сделать COUNT, сколько разLanguageId = 1 (для всех таблиц, которые ссылаются на таблицу языков).Код работает, но хотел бы знать, есть ли более простой способ реализовать / улучшить его.