大規模なデータベースで、あるテーブルから別のテーブルへの結合パスを見つける簡単な方法 (またはツール) はありますか?
現在、データベースに 150 を超えるテーブルがあるプロジェクトに取り組んでいます。以下は、私がやろうとしていることの一種のユースケースです。
使用事例:
入力
- テーブルAを選択
- テーブルBを選択
出力
- テーブル間の利用可能なすべてのパスを出力します。
- 最も効率的なルートを出力します。
大規模なデータベースで、あるテーブルから別のテーブルへの結合パスを見つける簡単な方法 (またはツール) はありますか?
現在、データベースに 150 を超えるテーブルがあるプロジェクトに取り組んでいます。以下は、私がやろうとしていることの一種のユースケースです。
使用事例:
入力
出力
データベースを介して非常に複雑なパスがいくつかあると想定しているため、1 つのクエリだけ、またはいくつかのクエリでそれを実行することはできません。私はそれを (継承したプロジェクトで) 実行し、いくつかの興味深いことを学びました。しかし、それを行うにはプログラムを書かなければなりませんでした。
私がしたことは、ディエゴが彼の回答で参照しているスキーマビューを使用し、グラフ理論の問題を解決するためのいくつかの方法を適用することでした(ここでは、テーブルがノードであり、外部キーがグラフ内にリンクされているため、本質的にそれが得られているためです)。
基本的に、私の記憶が正しければ (これは数年前のことです)、1 つのテーブルから始めて、それぞれが参照する他のテーブルの名前をキューに入れることで、そのすべての外部キーを処理します。自己参照とループをチェックします (処理したテーブルのハッシュ セットまたはリストが必要です)。次に、キューから次のテーブルをポップして繰り返します。最終的には、他のテーブルに遭遇するか、元のテーブルから「到達」できるすべてのテーブルを処理することになります。
これはあなたを助けるはずです。テーブル、FK を持つ列、参照されるテーブルと列、および FK 名が表示されます。
SELECT
K_Table = FK.TABLE_NAME,
FK_Column = CU.COLUMN_NAME,
PK_Table = PK.TABLE_NAME,
PK_Column = PT.COLUMN_NAME,
Constraint_Name = C.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN (
SELECT i1.TABLE_NAME, i2.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
) PT ON PT.TABLE_NAME = PK.TABLE_NAME
Zen と上記のコードからコードを借りて、これを作成しました。これまでのところ非常にうまく機能しているようです。
IF OBJECT_ID('tempdb.dbo.#TableSchema') IS NOT NULL BEGIN DROP TABLE #TableSchema END
SELECT
PK_Table = PK.TABLE_NAME,
PK_Column = PT.COLUMN_NAME,
K_Table = FK.TABLE_NAME,
FK_Column = CU.COLUMN_NAME,
Constraint_Name = C.CONSTRAINT_NAME
INTO #TableSchema
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
INNER JOIN (
SELECT i1.TABLE_NAME, i2.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME
WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY'
) PT ON PT.TABLE_NAME = PK.TABLE_NAME
CREATE TABLE [#TablesList] (
c_from NVARCHAR(450),
c_to NVARCHAR(450),
PRIMARY KEY (c_from, c_to)
);
INSERT INTO [#TablesList]
SELECT DISTINCT PK_Table,K_Table from #TableSchema
IF OBJECT_ID('__TablesLink__') IS NOT NULL BEGIN DROP TABLE [__TablesLink__] END
CREATE TABLE [__TablesLink__] (c_path NVARCHAR(MAX));-- PRIMARY KEY);
WITH PathCTE
AS
(SELECT c_from, c_to,
CAST('>' + CAST(c_from AS NVARCHAR(MAX)) + '>' +
CAST(c_to AS NVARCHAR(MAX)) + '>' AS NVARCHAR(MAX)) AS c_path
FROM [#TablesList] AS C1
UNION ALL
SELECT C.c_from, C.c_to,
CAST(P.c_path + C.c_to + '>' AS NVARCHAR(max))
FROM PathCTE AS P
JOIN [#TablesList] AS C
ON P.c_to = C.c_from
WHERE P.c_path NOT LIKE '%>' +
CAST(C.c_from AS NVARCHAR(max)) +
'>' +
CAST(C.c_to AS NVARCHAR(max)) +
'>%')
INSERT INTO [__TablesLink__]
SELECT c_path FROM PathCTE;
SELECT c_path
FROM [__TablesLink__]
WHERE c_path LIKE '>' + 'tableA' + '>%'
AND c_path LIKE '%>'+ 'tableZ' +'>';