Назад | Перейти на главную страницу

Обнаружение предполагаемых внешних ключей из JOINS в скриптах

Я наследую базу данных с 400 таблицами и зарегистрированными только 150 ограничениями внешнего ключа. Зная, что я делаю с приложением, и глядя на столбцы таблицы, легко сказать, что их должно быть намного больше.

Боюсь, что текущее прикладное программное обеспечение сломается, если я начну добавлять недостающие FK, потому что разработчики, вероятно, стали полагаться на эту «свободу», но первый шаг в решении проблемы - составить список отсутствующих FK, чтобы мы можем оценить их как команду.

Что еще хуже, ссылающиеся столбцы не имеют соглашения об именах.

Отношения неофициально закодированы в сотни специальных запросов и хранимых процедур, поэтому я надеюсь программно проанализировать эти файлы в поисках СОЕДИНЕНИЙ между фактическими таблицами (но не табличными переменными и т. Д.).

В этом подходе я предвижу следующие проблемы: новые строки, необязательные псевдонимы и подсказки таблиц, разрешение псевдонимов.

Я чувствую твою боль.

Свобода SQL поиск Надстройка SSMS может быть вам полезна.

В общем, да, регулярное выражение может справиться с этим, но вы должны знать о точке уменьшения отдачи при попытке вызвать магию регулярного выражения. Возможно, вам будет лучше просто просмотреть и выполнить поиск в коде, пока вы намечаете взаимосвязи.

Поиск SQL может значительно упростить вам задачу.

Вот что я придумал. Этот запрос ищет столбцы, похожие на внешний ключ (int, bigint, guid), которые не являются первичным ключом таблицы и которые в настоящее время не зарегистрированы с ограничением внешнего ключа. Конечно, у меня есть несколько столбцов «Порядок сортировки» и «Количество», но это действительно сужает список с меньшими усилиями, чем анализ сценариев SQL.

WITH ExistingFKCs AS
(
    SELECT
        CU.TABLE_NAME, -- Referencing Table
        CU.COLUMN_NAME -- Referencing Column
    FROM 
        INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C
        JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME
)
SELECT 
    T.TABLE_NAME AS [Table Name], 
    COL.COLUMN_NAME AS [Column Name]
FROM 
    INFORMATION_SCHEMA.TABLES T 
    JOIN INFORMATION_SCHEMA.COLUMNS COL ON 
        T.TABLE_TYPE = 'BASE TABLE' AND
        COL.TABLE_NAME = T.TABLE_NAME
    LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PKC ON 
        PKC.CONSTRAINT_TYPE = 'Primary Key' AND 
        PKC.TABLE_NAME = COL.TABLE_NAME
    LEFT JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE PKCU ON 
        PKCU.TABLE_NAME = PKC.TABLE_NAME AND 
        PKCU.CONSTRAINT_NAME = PKC.CONSTRAINT_NAME AND
        PKCU.COLUMN_NAME = COL.COLUMN_NAME
    LEFT JOIN ExistingFKCs EFKS ON
        EFKS.TABLE_NAME = COL.TABLE_NAME AND
        EFKS.COLUMN_NAME = COL.COLUMN_NAME
WHERE 
    PKCU.COLUMN_NAME IS NULL
    AND EFKS.COLUMN_NAME IS NOT NULL
    AND COL.DATA_TYPE IN ('int', 'bigint','uniqueidentifier')
ORDER BY T.TABLE_NAME, COL.COLUMN_NAME

Мощный синтаксический анализатор SQL может помочь в автоматическом анализе сотен специальных запросов и хранимых процедур, а по дереву синтаксического анализа запросов, сгенерированному синтаксическим анализатором SQL, вы можете легко найти взаимосвязь переменных таблицы / столбцов.

Вот пример:

SELECT a.ASSMT_NO,
   b.LINK_PARAM,
   c.EXPL                                               AS LINK_PG,
   (SELECT count()
    FROM   GRAASPST t
    WHERE  t.ASSMT_NO = a.ASSMT_NO
           AND t.ROLE != '02')                          AS PSN_CNT,
   (SELECT count()
    FROM   GRAASPST t
    WHERE  t.ASSMT_NO = a.ASSMT_NO
           AND t.ROLE != '02'
           AND ASSMT_FIN_YN = 'Y')                      AS PSN_FIN_CNT,
   (SELECT Avg(assmt_pts)
    FROM   GRAASSMT t
    WHERE  t.ASSMT_NO = a.ASSMT_NO
           AND t.ASSMT_TGT_SEQ_NO = a.ASSMT_TGT_SEQ_NO) AS ASSMT_PTS_AVG,
   a.ASSMT_RES,
   a.ASSMT_RPT_SUB_TITLE
FROM   GRAASTAT a
   JOIN GRAASRET b
     ON b.DELIB_REQ_NO = a.DELIB_REQ_NO
   JOIN GRTCODDT c
     ON c.DIV_CD = 'GR013'
        AND c.CD = b.DELIB_SLCT
   JOIN CMUSERMT d
     ON d.USERID = a.REGID
WHERE  a.ASSMT_NO = :ASSMT_NO
ORDER  BY a.ASSMT_TGT_SEQ_NO 

Проанализировав этот запрос, вы можете получить что-то вроде этого:

JoinTable1         JoinColumn1       JoinTable2    JoinColumn2     
GRAASRET       DELIB_REQ_NO      GRAASTAT      DELIB_REQ_NO    
GRTCODDT       CD            GRAASRET      DELIB_SLCT      
CMUSERMT       USERID        GRAASTAT      REGID              
GRAASPST       ASSMT_NO      GRAASTAT      ASSMT_NO        
GRAASSMT       ASSMT_NO      GRAASTAT      ASSMT_NO        
GRAASSMT       ASSMT_TGT_SEQ_NO  GRAASTAT      ASSMT_TGT_SEQ_NO

Вы можете проверить это демо для получения подробной информации.