#sql #sql-server #tsql #casting #sql-server-2019
Вопрос:
Я пытаюсь добиться следующего:
Получите все значения полей, где значение
FieldValue
больше 100, когда значение хранится в виде числа.
Показатель того, сохранялось ли значение в виде числа или нет, определяется типом поля, который является другим предложением where.
Проблема, с которой я сталкиваюсь, заключается в том, что, когда я пытаюсь выполнить преобразование полей данных в моем операторе WHERE, это не удалось.
Я бегу:
SELECT FieldValue FROM CARData A
JOIN Fields B ON A.FieldId = B.FieldId
WHERE FieldTypeId = 3 AND FieldValue IS NOT NULL
И это возвращает ожидаемый результат:
Но если бы я добавил предложение WHERE для фильтрации по значению:
SELECT FieldValue FROM CARData A
JOIN Fields B ON A.FieldId = B.FieldId
WHERE FieldTypeId = 3 AND FieldValue IS NOT NULL
AND CAST(FieldValue AS BIGINT) > 100
Это выбрасывает ошибку:
Ошибка преобразования типа данных nvarchar в bigint.
Я несколько понимаю, в чем проблема — он пытается преобразовать ВСЕ значения в таблице в bigint и терпит неудачу, когда попадает в нечисловое значение.
Я попытался решить эту проблему, вложив первый запрос во второй примерно так:
SELECT RESULT.FieldValue FROM (
SELECT FieldValue FROM CARData A
JOIn Fields B ON A.FieldId = B.FieldId
WHERE
FieldTypeId = 3
AND FieldValue IS NOT NULL
AND ISNUMERIC(A.FieldValue) = 1) RESULT
WHERE CAST(FieldValue AS BIGINT) > 100
Но даже это не возвращает ничего, кроме вышеупомянутой ошибки.
Ответ №1:
Хотя верно, что изменение структуры вашего запроса может привести к тому, что SQL выберет другой план, вам следует ограничить этот метод попытками помочь оптимизатору выбрать эффективный план. Причина этого в том, что если успешное выполнение логики зависит от конкретного выбора плана, то ваш запрос может сработать сегодня, но не сработать завтра (или в процессе работы), когда SQL решит выбрать другой план.
К счастью, вам не нужно полагаться на это здесь! Используйте try_cast
SELECT FieldValue FROM CARData A
JOIN Fields B ON A.FieldId = B.FieldId
WHERE FieldTypeId = 3
AND TRY_CAST(FieldValue AS BIGINT) > 100
Мне тоже любопытно… является ли это частью курса SQL? Если да, скажите своему преподавателю, чтобы он посетил StackOverflow, чтобы мы могли сказать им, чтобы они прекратили обучать студентов использованию EAV. Если только весь смысл не в том, чтобы показать вам, насколько они ужасны! 🙂
Комментарии:
1. Прежде
TRY_CAST
чем вы могли бы использоватьCASE
выражение для принудительного короткого замыкания.2. Нет, это не учебный курс! Это проблема, которую я рассматриваю в запросе EFCore, поэтому я в конечном итоге перевел ее, переведя SQL-запросы, а затем разбил ее на простой вопрос о том, что на самом деле происходит в запросе; что в конечном итоге выглядит как вопрос курса SQL 😛 Мне, к сожалению, пришлось довольствоваться таблицей EAV, так как данные, хранящиеся здесь, относятся к динамической системе форм. Я, вероятно, мог бы переписать его, чтобы сохранить каждое значение в соответствующем типизированном столбце… В любом случае, спасибо, ваше решение работает!
3. Эй, @AaronBertrand, спасибо за комментарий. Не могли бы вы, пожалуйста, немного подробнее остановиться на этом? Вы предлагаете поместить
TRY_CAST
в aCASE
, которыйISNUMERIC
сначала проверяет?4. @Bitz Нет, я говорю, что если бы вы использовали древнюю, неподдерживаемую версию SQL Server до
TRY_CAST
того, как она существовала, вы могли бы использоватьCASE
выражение. (И я никогда ничего не говорил обISNUMERIC
этом .)5. @Bitz Не прикасайтесь
ISNUMERIC
к столбу баржи, он сломан многими способамиISNUMERIC(-.)
, возвращает 1