Database
 sql >> Datenbank >  >> RDS >> Database

Zählen von Verweisen auf einen Datensatz in einer Tabelle über Fremdschlüssel

Ich musste kürzlich die Aufgabe für meinen eigenen Zweck lösen:die Anzahl der externen Datensätze zu berechnen, die durch einen Fremdschlüssel für jeden Datensatz in einer Tabelle (Datei) verknüpft sind. Die Aufgabe wurde für die spezifische Struktur der File-Tabelle gelöst, aber bei Bedarf kann die Lösung zu einer universellen umgearbeitet werden.

Ich möchte klarstellen, dass die Lösung für eine nicht geladene Datenbank entwickelt wurde, ohne Millionen von Datensätzen und einer Aktualisierung im Minutentakt, sodass es keine großen Bedenken hinsichtlich der Leistung gab.

Der Hauptgrund war, dass sich die Anzahl der externen Links zur Dateitabelle während der Entwicklung ändern könnte und es einfach unvernünftig wäre, die Abfrage ständig neu zu schreiben. Eine gewisse Modularität war im System vorgesehen, daher sind nicht alle Finaltabellen genau bekannt.

Das Skript zum Erstellen von zwei Labels:

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)

Wir erhalten die Tabellen File und TestForFiles. Die TestForFiles-Tabelle verweist auf die File-Tabelle durch das IdFileForTest-Feld.

Wir erhalten folgenden Datensatz:

Das Skript generiert eine Abfrage, um die Anzahl der Datensätze in der Tabelle zu zählen:

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;

Die folgende Abfrage wird generiert:

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

Nach der Ausführung haben wir solche Tabelleninhalte:

Wieder einmal wurde die Aufgabe für eine bestimmte Dateitabelle gelöst, das Zählen funktioniert nur für Fälle, in denen Fremdschlüssel im IdFile-Feld vorhanden sind.

Dieser Artikel wurde übersetzt von CodingsightTeam mit Genehmigung des Autors.