sql >> Base de Datos >  >> RDS >> Database

Contar referencias a un registro en una tabla a través de claves externas

Recientemente necesitaba resolver la tarea para mi propio propósito:calcular la cantidad de registros externos vinculados por una clave externa para cada registro en una tabla (Archivo). La tarea se resolvió para la estructura específica de la tabla de archivos, pero si es necesario, la solución se puede modificar a una universal.

Aclararé que la solución se desarrolló para una base de datos descargada, sin millones de registros y con una actualización cada minuto, por lo que no hubo mucha preocupación por el rendimiento.

La razón principal fue que la cantidad de enlaces externos a la tabla de archivos podría cambiar durante el desarrollo y simplemente no sería razonable reescribir constantemente la consulta. Se planeó una cierta modularidad en el sistema, por lo tanto, no se conocen exactamente todas las tablas finales.

La secuencia de comandos para crear dos etiquetas:

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)

Obtenemos las tablas File y TestForFiles. La tabla TestForFiles hace referencia a la tabla File por el campo IdFileForTest.

Obtenemos el siguiente conjunto de datos:

El script genera una consulta para contar el número de registros en la tabla:

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;

Se genera la siguiente consulta:

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

Después de la ejecución, tenemos tales contenidos de tabla:

Una vez más, la tarea se resolvió para una tabla de archivo específica, el conteo solo funciona para los casos en que hay claves externas en el campo IdFile.

Este artículo fue traducido por El equipo de Codingsight con el permiso del autor.