J'ai récemment eu besoin de résoudre la tâche pour mon propre usage :calculer le nombre d'enregistrements externes liés par une clé étrangère pour chaque enregistrement d'une table (Fichier). La tâche a été résolue pour la structure spécifique de la table Fichier, mais si nécessaire, la solution peut être retravaillée en une solution universelle.
Je préciserai que la solution a été développée pour une base de données déchargée, sans des millions d'enregistrements et une mise à jour toutes les minutes, donc il n'y avait pas beaucoup de souci concernant les performances.
La raison principale était que le nombre de liens externes vers la table File pouvait changer au cours du développement et qu'il serait tout simplement déraisonnable de réécrire constamment la requête. Une certaine modularité a été prévue dans le système, par conséquent, toutes les tables finales ne sont pas exactement connues.
Le script pour créer deux étiquettes :
CREATE TABLE [dbo].[File]( [IdFile] [int] IDENTITY(1, 1) NOT NULL, [NameFile] [nvarchar](max) NOT NULL, [CountUsage] [int] NOT NULL, PRIMARY KEY (IdFile) ) SET identity_insert [dbo].[File] ON; INSERT INTO [dbo].[File] ([IdFile], [NameFile],[CountUsage]) VALUES (1, 'test1', 0), (2, 'test2', 1000) SET identity_insert [dbo].[File] OFF; CREATE TABLE [dbo].[TestForFiles]( [IdTest] [int] IDENTITY(1, 1) NOT NULL, [IdFileForTest] [int] NOT NULL, PRIMARY KEY (IdTest) ) ALTER TABLE [dbo].[TestForFiles] WITH CHECK ADD CONSTRAINT [FK_TestForFiles_File] FOREIGN KEY([IdFileForTest]) REFERENCES [dbo].[File] ([IdFile]) ALTER TABLE [dbo].[TestForFiles] CHECK CONSTRAINT [FK_TestForFiles_File] INSERT INTO [dbo].[TestForFiles] ([IdFileForTest]) VALUES (1), (1), (1), (2)
Nous obtenons les tables File et TestForFiles. La table TestForFiles fait référence à la table File par le champ IdFileForTest.
Nous obtenons l'ensemble de données suivant :
Le script génère une requête pour compter le nombre d'enregistrements dans la table :
DECLARE @sql_tables nvarchar(max) = null; SELECT @sql_tables = CASE WHEN @sql_tables IS NULL THEN '' ELSE @sql_tables + CHAR(13) + CHAR(10) + ' UNION ALL' + CHAR(13) + CHAR(10) END + ' SELECT ' + c.name + ' AS IdFile, count(*) AS FileCount FROM ' + t.name + ' GROUP BY ' + c.name FROM sys.foreign_key_columns AS fk INNER JOIN sys.tables AS t ON fk.parent_object_id = t.object_id INNER JOIN sys.columns AS c ON fk.parent_object_id = c.object_id AND fk.parent_column_id = c.column_id INNER JOIN sys.columns AS c2 ON fk.referenced_object_id = c2.object_id AND fk.referenced_column_id = c2.column_id WHERE fk.referenced_object_id = (SELECT object_id FROM sys.tables WHERE name = 'File') AND c2.name = 'IdFile'; IF @sql_tables IS NOT NULL BEGIN DECLARE @sql nvarchar(max) = 'UPDATE dbo.[File]' + CHAR(13) + CHAR(10) + 'SET CountUsage = t2.FileCount' + CHAR(13) + CHAR(10) + 'FROM dbo.[File]' + CHAR(13) + CHAR(10) + 'INNER JOIN (' + CHAR(13) + CHAR(10) + ' SELECT IdFile, SUM(FileCount) AS FileCount ' + CHAR(13) + CHAR(10) + ' FROM (' + CHAR(13) + CHAR(10) + @sql_tables + CHAR(13) + CHAR(10) + ' ) t' + CHAR(13) + CHAR(10) + ' GROUP BY IdFile' + CHAR(13) + CHAR(10) + ') t2 ON t2.IdFile = dbo.[File].IdFile'; print @sql; EXEC sp_executesql @sql; END;
La requête suivante est générée :
UPDATE dbo.[File] SET CountUsage = t2.FileCount FROM dbo.[File] INNER JOIN ( SELECT IdFile, SUM(FileCount) AS FileCount FROM ( SELECT IdFileForTest AS IdFile, count(*) AS FileCount FROM TestForFiles GROUP BY IdFileForTest ) t GROUP BY IdFile ) t2 ON t2.IdFile = dbo.[File].IdFile
Après l'exécution, nous avons un tel contenu de table :
Encore une fois, la tâche a été résolue pour une table File spécifique, le comptage ne fonctionne que pour les cas où il y a des clés étrangères sur le champ IdFile.
Cet article a été traduit par L'équipe de Codingsight avec la permission de l'auteur.