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

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

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

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

  • получает список идентификаторов счетов-фактур из таблицы счетов и сохраняет их в Cursor
  • Получить идентификатор счета из курсора → переменная tmp_key
  • foreach tmp_key находит идентификатор первичного контакта клиента счета-фактуры из таблицы клиентов
  • обновляет ключ контакта клиента с идентификатором первичного контакта
  • закрыть курсор

Вот мой код:

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 следующего оператора обновления? Создать переменную курсора или другую локальную переменную с типом типа?

Ответ 1

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

EDIT:
Этот вопрос получил гораздо больше тяги, чем я ожидал. Обратите внимание, что я не рекомендую использовать курсор в своем ответе, а скорее укажу, как назначить значение на основе вопроса.

Ответ 2

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

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

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

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

Ответ 3

Попробуйте это

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.

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

Ответ 4

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

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

Ответ 5

Чтобы присвоить переменную безопасно, вам нужно использовать оператор 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 не возвращает сообщений

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

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

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

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

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