来自Information_Schema

时间:2017-04-24 23:41:55

标签: sql sql-server tsql recursion information-schema

我设置了多语种数据库(实际上它比这更复杂 - 但我保持简单)。可转换数据放在名为Fact的表中。数据链接到一个名为FactLink的表(只有一个名为FactLinkID的列。它被表中的多个列引用。但有时FactLink表可以是当数据组成它自己的集合时间接引用。例如,

CREATE TABLE FactLink
( FactLinkID INT NOT NULL IDENTITY(1,1) Primary KEY
)

CREATE TABLE [Language]
( LanguageID INT NOT NULL IDENTITY(1,1) Primary KEY
, Code varchar(50) not null
)

CREATE TABLE Fact
( FactLinkID INT NOT NULL
, LanguageID INT NOT NULL
, PRIMARY KEY CLUSTERED (FactLinkID ASC, LanguageID ASC)
, CONSTRAINT fk_Fact_FactLinkID FOREIGN KEY (FactLinkID) REFERENCES dbo.FactLink (FactLinkID)
, CONSTRAINT fk_Fact_LanuageID FOREIGN KEY (LanguageID) REFERENCES dbo.[Language] (LanguageID)
)

CREATE TABLE LimitedTranslateableItem
( LimitedTranslateableItemID INT NOT NULL PRIMARY KEY
, [Order] INT NOT NULL
, CONSTRAINT fk_LimitedTranslateableItem_Table1ID FOREIGN KEY (LimitedTranslateableItemID) REFERENCES dbo.FactLink (FactLinkID)
)

CREATE TABLE [All]
( AllID INT NOT NULL IDENTITY(1,1) PRIMARY KEY
, TranslateableItemID INT NOT NULL
, LimitedTranslateableItemID INT NOT NULL
, CONSTRAINT fk_All_TranslateableItemID FOREIGN KEY (TranslateableItemID) REFERENCES dbo.FactLink (FactLinkID)
, CONSTRAINT fk_All_LimitedTranslateableItemID FOREIGN KEY (LimitedTranslateableItemID) REFERENCES dbo.LimitedTranslateableItem (LimitedTranslateableItemID)
)

我想直接或间接地获取引用FactLink表的所有列。获得直接链接很容易。我想我需要通过Recursive CTE获得间接链接。但我不知道该怎么做。我是Recursive CTE的新手。这也是问题的一部分但是,对FactLink约束的引用与匹配约束的行不同。

-- Get constraint for FactLink table
DECLARE @FactLinkPKConstraint sysname
SELECT @FactLinkPKConstraint = t.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS t
WHERE t.TABLE_NAME = 'FactLink'
  AND t.CONSTRAINT_TYPE = 'PRIMARY KEY'

SELECT
      t.TABLE_SCHEMA
    , t.TABLE_NAME
    , t.CONSTRAINT_NAME
    , t.COLUMN_NAME
    , rc.UNIQUE_CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE t
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
    ON rc.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE t.TABLE_NAME = 'All'
  AND t.TABLE_SCHEMA = 'dbo'
  AND rc.UNIQUE_CONSTRAINT_NAME = @FactLinkPKConstraint

这是我到目前为止所拥有的:

;WITH CTE AS (
SELECT
      t.TABLE_SCHEMA
    , t.TABLE_NAME
    , t.CONSTRAINT_NAME
    , t.COLUMN_NAME
    , rc.UNIQUE_CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE t
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
    ON rc.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE t.TABLE_NAME = 'All'
  AND t.TABLE_SCHEMA = 'dbo'
UNION ALL
SELECT
      t.TABLE_SCHEMA
    , t.TABLE_NAME
    , t.CONSTRAINT_NAME
    , t.COLUMN_NAME
    , rc.UNIQUE_CONSTRAINT_CATALOG
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE t
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
    ON rc.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE rc.UNIQUE_CONSTRAINT_NAME IN (
    SELECT ct.UNIQUE_CONSTRAINT_NAME
    FROM CTE ct
    WHERE ct.UNIQUE_CONSTRAINT_NAME <> @FactLinkPKConstraint)
  --AND t.TABLE_NAME NOT IN (SELECT c.TABLE_NAME FROM CTE c)
)
SELECT *
FROM CTE t

当然,由于Recursive CTE无法在子查询中引用,因此无法正常工作。它并没有让我得到与FactLink表约束匹配的行。

也许当我睡在这上面时,我已经弄清楚了。但是一些指示会有所帮助。

提前致谢!

更新

这是我能想到的最好的。它并不完全符合我的标准,但实际上有点好,因为它发现了比我原先计划的更多的依赖性。这将获得FactLink表也引用的表的All列。

;WITH AFactLinkPKConstraint AS (
SELECT t.CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS t
WHERE t.TABLE_NAME = 'FactLink'
  AND t.CONSTRAINT_TYPE = 'PRIMARY KEY' 
), APrimary AS (
SELECT *
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE t
WHERE t.CONSTRAINT_NAME IN (
    SELECT DISTINCT rc.UNIQUE_CONSTRAINT_NAME
    FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE t
    JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
        ON rc.CONSTRAINT_NAME = t.CONSTRAINT_NAME
    WHERE t.TABLE_NAME = 'All' )
)
SELECT *
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE t
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
    ON rc.CONSTRAINT_NAME = t.CONSTRAINT_NAME
    AND rc.UNIQUE_CONSTRAINT_NAME = (SELECT pk.CONSTRAINT_NAME FROM AFactLinkPKConstraint pk)
JOIN APrimary p
    ON p.TABLE_NAME = t.TABLE_NAME
    AND p.TABLE_SCHEMA = t.TABLE_SCHEMA

1 个答案:

答案 0 :(得分:0)

以下是我测试过的两个 Scenario

不使用cte:

  DECLARE @FactLinkPKConstraint sysname
  SELECT @FactLinkPKConstraint = t.CONSTRAINT_NAME
  FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS t
  WHERE t.TABLE_NAME = 'FactLink'
  AND t.CONSTRAINT_TYPE = 'PRIMARY KEY'


 SELECT
      TABLE_SCHEMA
    , TABLE_NAME
    , CONSTRAINT_NAME
    , COLUMN_NAME
    , UNIQUE_CONSTRAINT_NAME from

 (SELECT
      t.TABLE_SCHEMA
    , t.TABLE_NAME
    , t.CONSTRAINT_NAME
    , t.COLUMN_NAME
    , rc.UNIQUE_CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE t
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
    ON rc.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE t.TABLE_NAME = 'All'
  AND t.TABLE_SCHEMA = 'dbo'
UNION ALL
SELECT
      t.TABLE_SCHEMA
    , t.TABLE_NAME
    , t.CONSTRAINT_NAME
    , t.COLUMN_NAME
    , rc.UNIQUE_CONSTRAINT_CATALOG
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE t
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
    ON rc.CONSTRAINT_NAME = t.CONSTRAINT_NAME) as result
WHERE UNIQUE_CONSTRAINT_NAME =@FactLinkPKConstraint
  --AND t.TABLE_NAME NOT IN (SELECT c.TABLE_NAME FROM CTE c)

使用cte:

  DECLARE @FactLinkPKConstraint sysname
  SELECT @FactLinkPKConstraint = t.CONSTRAINT_NAME
  FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS t
  WHERE t.TABLE_NAME = 'FactLink'
  AND t.CONSTRAINT_TYPE = 'PRIMARY KEY'

 ;with cte as
 (
    select @FactLinkPKConstraint  as col1
 ),
 FactLinkPKConstraint as 
 (
    select * from cte
 ),result as
 (

 SELECT
      t.TABLE_SCHEMA
    , t.TABLE_NAME
    , t.CONSTRAINT_NAME
    , t.COLUMN_NAME
    , rc.UNIQUE_CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE t
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
    ON rc.CONSTRAINT_NAME = t.CONSTRAINT_NAME
WHERE t.TABLE_NAME = 'All'
  AND t.TABLE_SCHEMA = 'dbo'
UNION ALL
SELECT
      t.TABLE_SCHEMA
    , t.TABLE_NAME
    , t.CONSTRAINT_NAME
    , t.COLUMN_NAME
    , rc.UNIQUE_CONSTRAINT_CATALOG
FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE t
JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
    ON rc.CONSTRAINT_NAME = t.CONSTRAINT_NAME
 )
 select * from result where UNIQUE_CONSTRAINT_NAME = (select col1 from FactLinkPKConstraint) 

  --AND t.TABLE_NAME NOT IN (SELECT c.TABLE_NAME FROM CTE c)