Хотя это конкретно не дает ответа на вопрос, я хотел обобщить мои вышеупомянутые комментарии в ответ, чтобы показать, почему ваш дизайн так несовершенен и почему он не будет работать; и поэтому зачем вам это исправлять. Обратите внимание, что у нас недостаточно информации, чтобы предложить, что это за исправление, кроме как заявить, что вам нужно потратить значительное время на исправление дизайна до нормализованного подхода.
Во-первых, Единственный способ достичь конечной цели - это использовать Dynami c SQL. Если бы вы указали только одно значение столбца, тогда вы на самом деле были бы «в порядке», так как вы могли бы написать такой оператор:
SELECT DT.ID,
DT.CustomField,
DT.[Value],
D.[Name]
FROM dbo.DenormalisedTable DT
JOIN dbo.tblDriver D ON DT.ForeignTable = N'tblDriver'
AND DT.ftIndex = D.ID
WHERE DT.ftRow = N'Name';
К сожалению, вы go должны заявить, что это не ' Это означает, что вам понадобится запрос, подобный приведенному ниже (для двух имеющихся у нас примеров таблиц):
SELECT DT.ID,
DT.CustomField,
DT.[Value],
CASE DT.ForeignTable WHEN N'tblDriver' THEN CASE DT.CustomField WHEN N'Name' THEN D.[Name] END
WHEN N'tblOrigin' THEN CASE DT.CustomField WHEN N'Name' THEN O.[Name] END
END
FROM dbo.DenormalisedTable DT
LEFT JOIN dbo.tblDriver D ON DT.ForeignTable = N'tblDriver'
AND DT.ftIndex = D.ID
LEFT JOIN dbo.tblOrigin O ON DT.ForeignTable = N'tblOrigin'
AND DT.ftIndex = O.ID;
Очевидно, однако, что у него есть много других таблиц и, скорее всего, другие столбцы ( не только столбец name
) для динамического получения значений. В итоге вы получите что-то вроде этого:
SELECT DT.ID,
DT.CustomField,
DT.[Value],
CASE DT.ForeignTable WHEN N'tblDriver' THEN CASE DT.CustomField WHEN N'Name' THEN D.[Name]
WHEN N'Age' THEN D.Age
WHEN N'Dob' THEN D.Dob
END
WHEN N'tblOrigin' THEN CASE DT.CustomField WHEN N'Name' THEN D.[Name]
WHEN N'Age' THEN D.Age
WHEN N'Dob' THEN D.Dob
END
WHEN ... --20 more WHENs, 50? Plus all the inner CASE expressions
WHEN N'tblOwner' THEN CASE DT.CustomField WHEN N'FirstTraded' THEN Onr.FirstTraded
...
END
END AS ColumnValue
FROM dbo.DenormalisedTable DT
LEFT JOIN dbo.tblDriver D ON DT.ForeignTable = N'tblDriver'
AND DT.ftIndex = D.ID
LEFT JOIN dbo.tblOrigin O ON DT.ForeignTable = N'tblOrigin'
AND DT.ftIndex = O.ID
LEFT JOIN ...
---20 more JOINs, 50?
LEFT JOIN dbo.tblOwner Onr ON DT.ForeignTable = N'tblOwner'
AND DT.ftIndex = Onr.ID;
Однако здесь есть некоторые серьезные проблемы. Первым будет неявное преобразование типов данных
Например, обратите внимание, что здесь у меня есть столбцы Name
, Age
и Dob
. Этот выбор был сделан намеренно, так как существуют все совершенно разные типы данных; строка, числовое значение и дата и время соответственно. Если выражение CASE
возвращает разные типы данных, тогда Приоритет типа данных будет использоваться для определения возвращаемого типа данных. Скорее всего, это приведет к типу данных даты и времени, а это означает, что ваши числовые столбцы и / или (n)varchar
не смогут выполнить оператор из-за ошибок преобразования. Это означает, что вышеперечисленное не работает. Хотя вы можете CONVERT
каждое выражение, возвращаемое в THEN
s, это серьезно влияет на данные и может легко привести к тому, что данные будут потребляемыми или не будут отображаться так, как вы хотите.
Эта проблема также относится к предложениям ON
, которые предполагают , что каждый столбец ID
имеет один и тот же тип данных (int
?), Поскольку наличие разных типов данных полностью нарушит это. Если это не так, вам нужно будет использовать TRY_CONVERT
для соответствующего типа данных, что подводит нас к следующему пункту: Performance .
Performance будет ужасно . Не будем биться вокруг бу sh. Подобный запрос не будет работать должным образом из-за огромного количества операций чтения, необходимых для разных таблиц. Вам повезет, это вернет данные за считанные минуты, а возможно, и часы, в зависимости от размера вашей базы данных. Добавление чего-то вроде TRY_CONVERT
в ON
уничтожает любую (небольшую) вероятность того, что СУБД могла использовать индекс для поиска.
Наконец, у нас есть масштабируемость. Написание вышеизложенного было бы само по себе задачей, а это значит, что вам нужно иметь для использования динамического c SQL. Но проблема, которую вы пытаетесь решить здесь, - это проблема с производительностью, и я также сказал вам, что это решение будет медленным , а я означает медленным . Оператор Dynami c не улучшит этого, и соображения, которые вам понадобятся, чтобы заставить этот оператор работать в первую очередь, были бы немалыми; так что давайте даже не go идти по этому пути, так как он уже выброшен в окно.
Итак, единственное решение здесь, чтобы получить эффективный запрос, - это исправить ваш дизайн. Нормализуйте свои данные и не храните такую информацию, как место в таблице подстановочной таблицы. Подобные конструкции, хотя и могут «выглядеть» интуитивно понятными для пользователя, имеют не масштабирование и не работают хорошо. Такие конструкции обычно возникают при рассмотрении РСУБД, как на язык программирования, и применении того же logi c. SQL не является языком программирования и работает иначе; в чем он преуспевает и с чем борется, совершенно разные.
TL; DR: действующий дизайн является причиной медленного выполнения вашего запроса. Вы не можете обойти это, поскольку ваш запрос (какой бы он ни был) не является причиной root. Только исправление конструкции устранит проблему с производительностью, и именно на это вам потребуется потратить значительное время и ресурсы на исправление.