sql >> Databáze >  >> RDS >> Database

Počítání odkazů na záznam v tabulce pomocí cizích klíčů

Nedávno jsem potřeboval vyřešit úkol pro svůj vlastní účel:vypočítat počet externích záznamů propojených cizím klíčem pro každý záznam v tabulce (Soubor). Úloha byla vyřešena pro konkrétní strukturu tabulky Soubor, ale v případě potřeby lze řešení přepracovat na univerzální.

Upřesním, že řešení bylo vyvinuto pro nenačtenou databázi, bez milionů záznamů a aktualizace každou minutu, takže o výkon nebylo příliš starostí.

Hlavním důvodem bylo, že počet externích odkazů na tabulku File se mohl během vývoje měnit a bylo by prostě nerozumné neustále přepisovat dotaz. V systému byla plánována určitá modularita, proto nejsou přesně známy všechny finální tabulky.

Skript pro vytvoření dvou štítků:

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)

Získáme tabulky File a TestForFiles. Tabulka TestForFiles odkazuje na tabulku File podle pole IdFileForTest.

Získáváme následující soubor dat:

Skript vygeneruje dotaz na sčítání počtu záznamů v tabulce:

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;

Vygeneruje se následující dotaz:

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

Po provedení máme takový obsah tabulky:

Opět byl úkol vyřešen pro konkrétní tabulku File, počítání funguje pouze pro případy, kdy jsou v poli IdFile cizí klíče.

Tento článek přeložil Tým Codingsightse svolením autora.


  1. Jak extrahovat den, měsíc a rok z data v SQLite

  2. Převod dotazů SELECT DISTINCT ON z Postgresql na MySQL

  3. Jak najít tabulku, kde jsou uzamčeny statistiky

  4. Je poskytovatel OraOLEDB v .NET nespolehlivý na polích CLOB?