TSQL加载db与一堆FK,算法

时间:2017-11-29 00:15:15

标签: sql-server tsql

我需要从头开始加载50多个表,这些表有很多FK约束,现在我只丢弃所有FK,以任何顺序加载表(我的数据符合所有FK),然后添加FK。 有什么方法可以做到这一点,我可以看到FK定义的顺序是至关重要的,所以让我们看看我的样本,这是正确的方法吗?

 ALTER TABLE CUST  ADD CONSTRAINT CUS_BatchID_FK FOREIGN KEY (BatchID) REFERENCES Batch(BatchID);
ALTER TABLE CYCLE ADD CONSTRAINT CL_BatchID_FK  FOREIGN KEY (BatchID) REFERENCES Batch(BatchID);
ALTER TABLE QOUTE ADD CONSTRAINT QT_BatchID_FK  FOREIGN KEY (BatchID) REFERENCES Batch(BatchID);

ALTER TABLE MD_LOC ADD CONSTRAINT MLOC_FK       FOREIGN KEY (LOC_ID) REFERENCES LOC(LOC_ID);
ALTER TABLE CUST   ADD CONSTRAINT CUST_PROV_FK  FOREIGN KEY (PROV_ID) REFERENCES PROVIDER(PROV_ID);   
ALTER TABLE REFER ADD CONSTRAINT  RF_CUST_ID_FK FOREIGN KEY (CUST_ID) REFERENCES CUST(CUST_ID); 

/*--------------------
1. load  Batch
2. load  LOC
2a. Load  MD_LOC
3.  load  PROVIDER 
3a. load CUST 
.....

即我首先加载没有FK的表,然后按顺序进行,我测试了几个表并且它可以工作,只是想确认在我使用其余表之前是否有任何遗漏。

1 个答案:

答案 0 :(得分:3)

通过考虑父/子关系之类的外键,可以实现表插入的顺序,在T-SQL中,我们可以对这种层次结构使用递归公用表表达式。以下将列出将遵守FK约束的表插入的顺序:

WITH
      ctefk (pktable, fktable) AS (
                  SELECT
                        s1.name + '.' + o1.name AS pktable
                      , ISNULL(s2.name + '.' + o2.name, '') as fktable
                  FROM sys.objects o1
                  LEFT OUTER JOIN sys.sysforeignkeys fk ON o1.object_id = fk.fkeyid
                  LEFT OUTER JOIN sys.objects o2 ON o2.object_id = fk.rkeyid
                  LEFT OUTER JOIN sys.schemas s1 ON o1.schema_id = s1.schema_id
                  LEFT OUTER JOIN sys.schemas s2 ON o2.schema_id = s2.schema_id
                  WHERE o1.type_desc = 'user_table'
                  AND o1.name NOT IN ('dtproperties', 'sysdiagrams')
                  GROUP BY
                        s1.name + '.' + o1.name
                      , ISNULL(s2.name + '.' + o2.name, '')
            ),
      cterec (tablename, fkcount) AS (
                  SELECT
                        tablename = pktable
                      , fkcount =   0
                  FROM ctefk

                  UNION ALL

                  SELECT
                        tablename = pktable
                      , fkcount =   1
                  FROM ctefk
                  CROSS APPLY cteRec
                  WHERE ctefk.fktable = cteRec.tablename
                  AND ctefk.pktable <> cteRec.tablename
            )
SELECT
      TableName
    , insertorder = DENSE_RANK() OVER (ORDER BY MAX(fkcount) ASC)
FROM (
      SELECT
            tablename = fktable
          , fkcount =   0
      FROM ctefk
      GROUP BY
            fktable

      UNION ALL

      SELECT
            tablename = tablename
          , fkcount =   SUM(ISNULL(fkcount, 0))
      FROM cterec
      GROUP BY
            tablename
) x
WHERE x.tablename <> ''
GROUP BY
      tablename
ORDER BY
      insertorder ASC
    , TableName ASC
;

注意:任何具有FK的表本身(显然)仍然是一个问题,希望这根本不会发生。上面的查询会跳过这样一个条件,因为它会导致递归循环。