Как назначить результат выбора переменной? - PullRequest
69 голосов
/ 30 апреля 2009

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

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

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

  1. получает список идентификаторов счетов из таблицы счетов и сохраняет их в Cursor
  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?

Ответы [ 5 ]

90 голосов
/ 27 января 2011

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

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

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

declare @userId uniqueidentifier
SELECT TOP 1 @userId = UserId FROM aspnet_Users
43 голосов
/ 30 апреля 2009
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:
Этот вопрос получил намного больше тяги, чем я ожидал. Обратите внимание, что я не защищаю использование курсора в своем ответе, а скорее показываю, как назначить значение на основе вопроса.

19 голосов
/ 30 апреля 2009

Попробуйте

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.

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

14 голосов
/ 01 мая 2009

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

UPDATE tarinvoice set confirmtocntctkey = PrimaryCntctKey 
FROM tarinvoice INNER JOIN tarcustomer ON tarinvoice.custkey = tarcustomer.custkey
WHERE confirmtocntctkey is null and tranno like '%115876'
11 голосов
/ 29 октября 2013

Чтобы безопасно назначить переменную, вы должны использовать инструкцию 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 при назначении переменных?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...