Откройте для себя предполагаемые иностранные ключи от JOINS в скриптах
Я наследую базу данных с 400 таблицами и только 150 зарегистрированными ограничениями внешнего ключа. Зная, что я делаю с приложением и просматривая столбцы таблицы, легко сказать, что должно быть намного больше.
Я боюсь, что текущее прикладное программное обеспечение сломается, если я начну добавлять недостающие FK, потому что разработчики, вероятно, стали полагаться на эту "свободу", но первый шаг в исправлении проблемы - составить список отсутствующих FK, так что мы можем оценить их как команду.
Что еще хуже, ссылочные столбцы не имеют общего соглашения об именах.
Отношения неофициально закодированы в сотнях специальных запросов и хранимых процедур, поэтому я надеюсь, что эти файлы будут проанализированы программным путем в поисках JOINS между реальными таблицами (но не переменными таблиц и т. Д.).
Проблемы, которые я предвижу в этом подходе: новые строки, дополнительные псевдонимы и табличные подсказки, разрешение псевдонимов.
- Есть идеи получше? (Кроме выхода)
- Есть какие-то готовые инструменты, которые могут решить эту проблему?
- Я не думаю, что регулярные выражения могут справиться с этим. Вы не согласны?
- Парсеры SQL? Я пытался использовать Microsoft.SqlServer.Management.SqlParser.Parser, но все, что раскрывается, это лексер - не может получить AST из него - все эти вещи являются внутренними.
3 ответа
Мощный анализатор 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
Вы можете проверить это демо для подробной информации.
Я чувствую твою боль.
Бесплатная надстройка SQL Search SSMS может быть полезна для вас.
В общем, да, регулярные выражения могут справиться с этим, но вы должны знать о точке с уменьшением отдачи при попытке вызвать магию регулярных выражений. Возможно, вам будет лучше просто просмотреть и выполнить поиск по коду во время составления карты отношений.
SQL Search может сделать это намного проще для вас.
Вот что я придумал. Этот запрос ищет столбцы, подобные внешнему ключу (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