Как избежать нескольких CAST-ов в SQL-запросе? - PullRequest
2 голосов
/ 30 октября 2008

У меня есть следующий sql-запрос для преобразования данных, но возможно ли сохранить значение int в некоторой переменной, чтобы избежать приведения несколько раз?

update prospekts set sni_kod = case

when 
    cast(sni_kod as int) >= 1000 and cast(sni_kod as int) <= 1499 
    or cast(sni_kod as int) >= 1600 and cast(sni_kod as int) <= 2439
then '1'
when 
    cast(sni_kod as int) >= 7000 and cast(sni_kod as int) <= 7499 
then 'W'
else
     sni_kod
end 

В сценарии гораздо больше случаев, просто показываю первый. Я не могу использовать ничего, кроме простого текстового скрипта.

Обновление Использование SQL Server 2000

Спасибо

Anders

Ответы [ 9 ]

3 голосов
/ 30 октября 2008

Хорошо ... вот мое переписывание вашего кода ...

UPDATE prospekts SET sni_kod = 
    CASE
        WHEN ISNUMERIC(@sni_kod)=1 THEN
            CASE 
                WHEN cast(@sni_kod as int) BETWEEN 1000 AND 1499 OR cast(@sni_kod as int) BETWEEN 1600 AND 2439 THEN '1'
                WHEN cast(@sni_kod as int) BETWEEN 7000 AND 7499 THEN 'W'
                ELSE @sni_kod
            END
        ELSE @sni_kod
    END

Таким образом, он будет пытаться выполнить CAST, только если это числовое значение, поэтому вы не получите исключений приведения, как другие люди упоминали в комментариях.

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

Однако, не видя полного заявления, это лучшее, что я могу предложить.

2 голосов
/ 30 октября 2008

Это просто одноразовый скрипт, как кажется? Если это так, и вы просто пытаетесь сэкономить при наборе текста, напишите как:

update prospekts set sni_kod = case
when 
    xxx >= 1000 and xxx <= 1499 
    or xxx >= 1600 and xxx <= 2439
then '1'
when 
    xxx >= 7000 and xxx <= 7499 
then 'W'
else
     sni_kod
end

... а затем выполните глобальный поиск и замените его текстовым редактором.

Или, может быть, вы обеспокоены производительностью приведения несколько раз за строку, когда это возможно? Но опять же, если этот скрипт один, действительно ли это важно?

2 голосов
/ 30 октября 2008

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

Пример:

SELECT CONVERT(INT, '123'), CONVERT(INT, '123')

T-SQL будет запускать этот метод только один раз (без потери производительности).

С учетом вышесказанного, единственное другое беспокойство, которое вы могли бы иметь, это набрать группу ... и если это так, то комментарий "xxx / find and replace", упомянутый Тони Эндрюсом, достаточно хорош.

1 голос
/ 30 октября 2008

вы можете использовать подзапрос или CTE:

With xxx AS (
     i_sni_kod = cast(sni_kod as int)
     ...)
UPDATE prospekts set sni_kod = case 
    when i_sni_kod >= 100 ...
0 голосов
/ 30 октября 2008

Я вижу, что кто-то опубликовал решение, которое присоединяется к подзапросу в предложении from. Вот решение с -just- подзапросом в предложении from.

DECLARE @MyTable TABLE
(
  theKey int identity(1,1) PRIMARY KEY,
  theValue varchar(30)
)
------    
INSERT INTO @MyTable SELECT '1'
INSERT INTO @MyTable SELECT '2'
INSERT INTO @MyTable SELECT '3'
------

UPDATE sub
SET theValue =
  CASE
    WHEN convertedvalue % 2 = 0 THEN 'even'
    ELSE theValue
  END
FROM
(
  SELECT
    CASE
      WHEN Isnumeric(theValue) = 1
      THEN convert(int, theValue)
      ELSE null
    END as convertedValue, *
  FROM @MyTable mt
) as sub
------
SELECT *
FROM @MyTable
0 голосов
/ 30 октября 2008

Оператор UPDATE, который вы показываете; Я полагаю, он будет запущен только один раз? Если он запускается второй раз, приведение к int завершится неудачно, когда он найдет «W», который был добавлен в предыдущем запуске. Наилучшим вариантом здесь является изменение типа данных столбца sni_kod. Может быть, вы могли бы объяснить, что содержит этот столбец, почему он должен содержать данные как int, так и varchar? Наконец, SQL-сервер почти наверняка выполняет приведение только один раз. Он довольно хорошо находит повторяющиеся выражения и подзапросы в запросе и запускает их только один раз. Если вы не уверены, посмотрите на план выполнения.

0 голосов
/ 30 октября 2008

Что-то вроде этого может работать:

update prospekts set sni_kod = 1
from prospekts
    join (select prospekts.primarykey, cast(prospekts.sni_kod as int) as sni_kod_int from prospekts) p2 on prospekts.primarykey = p2.primarykey
WHERE (p2.sni_kod_int >=1000 and p2.sni_kod_int <= 1499)
    or (p2.sni_kod_int >=1600 and p2.sni_kod_int <= 2439)
0 голосов
/ 30 октября 2008

Это похоже на проблему с вашей моделью, а не с вашим запросом. Почему этот столбец не просто int?

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

0 голосов
/ 30 октября 2008

Работает ли это в вашей СУБД?

update (select prospekts.*, cast(sni_kod as int) sni_kod_int from prospekts)
set sni_kod = case
when 
    sni_kod_int >= 1000 and sni_kod_int <= 1499 
    or sni_kod_int >= 1600 and sni_kod_int <= 2439
then 1
else
     sni_kod
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...