Как присвоить результат выбора переменной?

StackOverflow https://stackoverflow.com/questions/807712

  •  03-07-2019
  •  | 
  •  

Вопрос

Как сохранить выбранное значение поля в переменной из запроса и использовать его в операторе обновления?

Вот моя процедура:

Я пишу хранимую процедуру T-SQL SQL Server 2005, которая выполняет следующие действия:

  1. получает список идентификаторов счетов-фактур из таблицы счетов-фактур и сохраняет их в курсоре
  2. Получить идентификатор счета из курсора -> переменная tmp_key
  3. foreach tmp_key находит основной идентификатор контакта клиента счета из таблицы клиентов
  4. обновляет ключ контакта клиента с идентификатором основного контакта
  5. закрыть курсор

Вот мой код:

DECLARE @tmp_key int
DECLARE @get_invckey cursor 

set @get_invckey = CURSOR FOR 
    select invckey from tarinvoice where confirmtocntctkey is null and tranno like '%115876'

OPEN @get_invckey 

FETCH NEXT FROM @get_invckey into @tmp_key

WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    SELECT c.PrimaryCntctKey as PrimaryContactKey
    from tarcustomer c, tarinvoice i
    where i.custkey = c.custkey and i.invckey = @tmp_key

    UPDATE tarinvoice set confirmtocntctkey = PrimaryContactKey where invckey = @tmp_key
    FETCH NEXT FROM @get_invckey INTO @tmp_key
END 

CLOSE @get_invckey
DEALLOCATE @get_invckey

Как сохранить PrimaryContactKey и использовать его снова в предложении set следующего оператора обновления?Создаю ли я курсорную переменную или просто другую локальную переменную типа int?

Это было полезно?

Решение

DECLARE @tmp_key int
DECLARE @get_invckey cursor 

SET @get_invckey = CURSOR FOR 
    SELECT invckey FROM tarinvoice WHERE confirmtocntctkey IS NULL AND tranno LIKE '%115876'

OPEN @get_invckey 

FETCH NEXT FROM @get_invckey INTO @tmp_key

DECLARE @PrimaryContactKey int --or whatever datatype it is

WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    SELECT @PrimaryContactKey=c.PrimaryCntctKey
    FROM tarcustomer c, tarinvoice i
    WHERE i.custkey = c.custkey AND i.invckey = @tmp_key

    UPDATE tarinvoice SET confirmtocntctkey = @PrimaryContactKey WHERE invckey = @tmp_key
    FETCH NEXT FROM @get_invckey INTO @tmp_key
END 

CLOSE @get_invckey
DEALLOCATE @get_invckey

РЕДАКТИРОВАТЬ:
Этот вопрос вызвал гораздо больше внимания, чем я ожидал.Обратите внимание: я не призываю использовать курсор в своем ответе, а скорее показываю, как присвоить значение на основе вопроса.

Другие советы

У меня была такая же проблема и...

declare @userId uniqueidentifier
set @userId = (select top 1 UserId from aspnet_Users)

или даже короче:

declare @userId uniqueidentifier
SELECT TOP 1 @userId = UserId FROM aspnet_Users

Попробуй это

SELECT @PrimaryContactKey = c.PrimaryCntctKey
FROM tarcustomer c, tarinvoice i
WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key

UPDATE tarinvoice SET confirmtocntctkey = @PrimaryContactKey 
WHERE invckey = @tmp_key
FETCH NEXT FROM @get_invckey INTO @tmp_key

Вы должны объявить эту переменную вне цикла как стандартную переменную TSQL.

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

Зачем вообще нужен курсор?Им можно заменить весь сегмент кода, что будет работать намного быстрее при большом количестве строк.

UPDATE tarinvoice set confirmtocntctkey = PrimaryCntctKey 
FROM tarinvoice INNER JOIN tarcustomer ON tarinvoice.custkey = tarcustomer.custkey
WHERE confirmtocntctkey is null and tranno like '%115876'

Чтобы безопасно назначить переменную, вам необходимо использовать оператор SET-SELECT:

SET @PrimaryContactKey = (SELECT c.PrimaryCntctKey
    FROM tarcustomer c, tarinvoice i
    WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key)

Убедитесь, что у вас есть как начальная, так и конечная скобка!

Причина, по которой версия SET-SELECT является самым безопасным способом установки переменной, двояка.

1.SELECT возвращает несколько сообщений

Что произойдет, если следующий выбор приведет к появлению нескольких сообщений?

SELECT @PrimaryContactKey = c.PrimaryCntctKey
FROM tarcustomer c, tarinvoice i
WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key

@PrimaryContactKey будет присвоено значение из последний пост в результате.

Фактически @PrimaryContactKey каждому сообщению в результате будет присвоено одно значение, поэтому оно, следовательно, будет содержать значение последнего сообщения, которое обрабатывала команда SELECT.

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

С помощью инструкции SET-SELECT вашей переменной будет присвоено значение null.

2.SELECT не возвращает сообщений

Что произойдет при использовании второй версии кода, если ваш выбор вообще не вернет результат?

Вопреки тому, во что вы можете поверить, значение переменной не будет нулевым - оно сохранится это предыдущее значение!

Это связано с тем, что, как указано выше, SQL присваивает значение переменной. один раз за сообщение - это означает, что он ничего не будет делать с переменной, если результат не содержит сообщений.Таким образом, переменная по-прежнему будет иметь то значение, которое она имела до выполнения оператора.

С помощью инструкции SET-SELECT значение будет null.

Смотрите также: SET или SELECT при назначении переменных?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top