Sql server T-SQL游标+;动态SQL(引用特定主键的行数)
我必须计算一个键在表中被使用的次数。我有以下代码,用于获取引用该键的所有表:Sql server T-SQL游标+;动态SQL(引用特定主键的行数),sql-server,tsql,Sql Server,Tsql,我必须计算一个键在表中被使用的次数。我有以下代码,用于获取引用该键的所有表: 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 f
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'
结果:
这是我必须对返回的每一行进行的查询,最后对所有行进行求和:
SELECT COUNT(*)
FROM SchemaName.TableName t
WHERE t.ColumnName = @LanguageId
我一直在阅读有关游标和动态SQL的文章,但我无法找到一种方法使其工作(从未使用过任何游标和动态SQL)
不需要使用游标/动态SQL。如果有更简单的方法,我很感激
编辑:我设法做到了。
EDIT2:一些重构和实际需求的完整实现
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
...
我需要计算LanguageId=1的次数(对于引用该语言表的所有表)。代码正在运行,但想知道是否有一种更简单的方法来实现/改进它。我不太确定您的具体要求,但这可能会帮助您 此SQL将获取所有FK列信息:
SELECT fkeys.[name] AS FKName,
OBJECT_NAME(fkeys.parent_object_id) AS TableName,
(SELECT STUFF((SELECT ',' + c.[name]
FROM sys.foreign_keys fk INNER JOIN sys.tables t ON fk.parent_object_id = t.object_id
INNER JOIN sys.columns as c ON t.object_id = c.object_id
INNER JOIN sys.foreign_key_columns AS fc ON c.column_id = fc.parent_column_id
AND fc.constraint_object_id = fk.object_id
AND fc.parent_object_id = fk.parent_object_id
WHERE fk.[name] = fkeys.[name]
FOR XML PATH ('')), 1, 1, '')) AS FKFolumns,
OBJECT_NAME(fkeys.referenced_object_id) AS ReferencedTableName,
(SELECT STUFF((SELECT ',' + c.[name]
FROM sys.foreign_keys fk INNER JOIN sys.tables t ON fk.referenced_object_id = t.object_id
INNER JOIN sys.columns as c ON t.object_id = c.object_id
INNER JOIN sys.foreign_key_columns AS fc ON c.column_id = fc.referenced_column_id
AND fc.constraint_object_id = fk.object_id
AND fc.referenced_object_id = fk.referenced_object_id
WHERE fk.[name] = fkeys.[name]
FOR XML PATH ('')), 1, 1, '')) AS ReferencedFKColumns
FROM sys.foreign_keys fkeys
您可以使用它来提取引用给定表和列的计数:
WITH AllFKInfo AS (
SELECT fkeys.[name] AS FKName,
OBJECT_NAME(fkeys.parent_object_id) AS TableName,
(SELECT STUFF((SELECT ',' + c.[name]
FROM sys.foreign_keys fk INNER JOIN sys.tables t ON fk.parent_object_id = t.object_id
INNER JOIN sys.columns as c ON t.object_id = c.object_id
INNER JOIN sys.foreign_key_columns AS fc ON c.column_id = fc.parent_column_id
AND fc.constraint_object_id = fk.object_id
AND fc.parent_object_id = fk.parent_object_id
WHERE fk.[name] = fkeys.[name]
FOR XML PATH ('')), 1, 1, '')) AS FKFolumns,
OBJECT_NAME(fkeys.referenced_object_id) AS ReferencedTableName,
(SELECT STUFF((SELECT ',' + c.[name]
FROM sys.foreign_keys fk INNER JOIN sys.tables t ON fk.referenced_object_id = t.object_id
INNER JOIN sys.columns as c ON t.object_id = c.object_id
INNER JOIN sys.foreign_key_columns AS fc ON c.column_id = fc.referenced_column_id
AND fc.constraint_object_id = fk.object_id
AND fc.referenced_object_id = fk.referenced_object_id
WHERE fk.[name] = fkeys.[name]
FOR XML PATH ('')), 1, 1, '')) AS ReferencedFKColumns
FROM sys.foreign_keys fkeys
)
SELECT ReferencedTableName, ReferencedFKColumns, COUNT(ReferencedFKColumns) AS CountOfReferences
FROM AllFKInfo
GROUP BY ReferencedTableName, ReferencedFKColumns
ORDER BY ReferencedTableName, ReferencedFKColumns
帖子中的答案很有效,可能不是最好的解决方案,但确实有效
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;
如果您使用正在使用的数据库软件(例如,
sql server
)标记您的问题,这会有所帮助tsql
并不能很好地说明这一点。我有点搞不清楚您到底想要什么。您只需要所有外键引用的列表,还是要在DB中搜索使用给定键值的所有表?此外,您可以将SchemaName、TableName和FieldName声明为“sysname”,而不是nvarchar(4000)。SQLServer中的所有架构名称都是sysname类型(如果您好奇的话,它是nvarchar(128))。只要有可能,您应该将游标声明为“快进”。此外,您的SQL似乎不处理复合主键。@pmbAustin感谢您提供的提示,对其进行了更改,现在查询似乎运行得非常快。是的,我想计算一个键被引用了多少次。根据表名和帖子本身,我想他想知道有多少种语言被翻译了。因此,他获取与语言表相关的所有表,然后需要对这些表中的特定语言id进行计数。根据变量名,关键是要知道用户是否可以更改默认语言(要求100%的翻译完成,这就是为什么要比较当前默认值和所需值的总数。谢谢你的回答。我需要LoadIt解释的内容(我会编辑主要帖子以更好地解释)。但基本上我需要知道一种特定的语言,比如“Id:1语言:英语”我需要首先从表语言中了解引用键的所有表,然后对LanguageId1进行引用计数