2010-02-16 4 views
3

У меня есть столбец TypeCode varchar (20), который имеет значения, такие как «1», «2», «3», «FOO», «BAR». Мне нужно найти максимальное целое число, которое меньше значения параметра. Что-то вроде этого:Предотвращение перезаписи запросов в SQL Server

select max(TypeCode) TypeCode 
    from table1 a 
    left join table2 b on b.table1id = a.id 
     and b.TypeCode not in ('FOO', 'BAR') 
    where b.TypeCode < @MaxType 

Который работает большую часть времени, но в некоторых запросов SQL Server решает преобразовать его в нечто вроде этого (в соответствии с планом запроса).

select max(TypeCode) TypeCode 
    from table1 a 
    left join table2 b on b.table1id = a.id 
     and b.TypeCode < @MaxType 
     and b.TypeCode not in ('FOO', 'BAR') 

Этот запрос, очевидно, дает следующее сообщение об ошибке:

Conversion failed when converting the varchar value 'FOO' to data type int. 

Я пытался создать представление table2 без «Foo» и значения «BAR» и присоединение вида, но вместо этого план запроса еще тоже самое.

Знаете ли вы, как предотвратить изменение оптимизатора?

PS: Я знаю, что дизайн таблицы не самый лучший, но это устаревшая база данных, и я не могу ее изменить.

ответ

2

Настоящая проблема заключается в том, что вы комбинируете символьную и целую семантику в том же запросе.

Есть три возможных решения, которые я могу думать:

  1. Изменить параметр @MaxType, чтобы быть varchar(9). Если вы сравниваете только однозначные числа, в алфавитном порядке все в порядке. В противном случае это не сработает.

  2. Используйте конструкцию CASE или ISNULL(NULLIF(...)) в заявлении WHERE. Это будет работать, но это не поддается продвижению и заставит оптимизатор игнорировать любые индексы, которые у вас есть в коде типа. Не хорошо.

  3. Создал постоянный, вычисляемый, нулевой целочисленный столбец (т. Е. TypeCodeID) и индексирует его отдельно. Поместите CASE в качестве выражения столбца. Это займет некоторое дополнительное пространство данных/индекса, но если вам нужна хорошая производительность, это лучший способ пойти. Затем вместо того, чтобы писать NOT IN ('Foo', 'Bar'), вы можете просто написать первое условие (TypeCode < @MaxType), потому что строки с Foo и Bar в столбце TypeCode будут содержать NULL в новой колонке TypeCodeID.

Я полагаю, что есть и четвертый ответ, который должен изменить ваш дизайн, и это было бы лучшей идеей, если это возможно. Если столбец может содержать символьные данные, вы действительно не должны пытаться выполнять численные сравнения.У меня есть сильное подозрение, что данные символа существуют в этом столбце, потому что они поступают от пользователей и не проверяются/дезинфицируются должным образом, поэтому у него есть значения мусора, такие как N/A или Unknown. Если это так, ваша БД действительно должна обеспечивать целостность данных, для чего предназначена СУБД. Я знаю, что вы говорите, что «не можете его изменить», но я не думаю, что этот ответ был бы полным, если бы я не рекомендовал против таких опасных практик.

0

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

Вы, вероятно, может сделать эту работу с сазе - что-то вроде:

SELECT MAX(TypeCode) TypeCode 
FROM table1 a 
    LEFT JOIN table2 b ON b.table1id = a.id 
WHERE CASE WHEN b.TypeCode IN ('FOO', 'BAR') THEN 99999999999 ELSE CAST(b.TypeCode AS int) END < @MaxType 

Вам необходимо проверить работу, чтобы это увидеть, если это приемлемо, но он должен работать.

Смежные вопросы