sql >> Database >  >> RDS >> Database

Referenties tellen naar een record in een tabel via Foreign Keys

Ik heb onlangs de taak voor mijn eigen doel moeten oplossen:het berekenen van het aantal externe records dat is gekoppeld door een externe sleutel voor elk record in een tabel (Bestand). De taak is opgelost voor de specifieke structuur van de bestandstabel, maar indien nodig kan de oplossing worden herwerkt tot een universele.

Ik zal verduidelijken dat de oplossing is ontwikkeld voor een niet-geladen database, zonder miljoenen records en elke minuut een update, dus er was niet veel bezorgdheid over de prestaties.

De belangrijkste reden was dat het aantal externe links naar de tabel Bestand tijdens de ontwikkeling kon veranderen en dat het gewoon onredelijk zou zijn om de query voortdurend te herschrijven. Er was een zekere modulariteit in het systeem gepland, daarom zijn niet alle finaletafels precies bekend.

Het script voor het maken van twee 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)

We krijgen de tabellen File en TestForFiles. De TestForFiles-tabel verwijst naar de File-tabel door het IdFileForTest-veld.

We verkrijgen de volgende dataset:

Het script genereert een query om het aantal records in de tabel te tellen:

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;

De volgende vraag wordt gegenereerd:

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

Na de uitvoering hebben we de volgende tabelinhoud:

Wederom is de taak opgelost voor een specifieke bestandstabel, tellen werkt alleen voor gevallen waarin er externe sleutels in het IdFile-veld staan.

Dit artikel is vertaald door Codingsight-team met toestemming van de auteur.


  1. SQLite-volgorde op datum1530019888000

  2. MySQL-fout 1153 - Heb een pakket groter dan 'max_allowed_packet' bytes

  3. PostgreSQL-schema maken

  4. een lijst imploderen voor gebruik in een python MySQLDB IN-clausule