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进行引用计数