Оператор обновления работает с временной таблицей, но не с табличными переменными.

Я определил эту таблицу:

CREATE TABLE #stagingtable
(
    id int identity(1,1),
    typeflag int default 0,
    resourcetype varchar(25),
    resource varchar(40),
    est int,
    planned int,
    actual int
)

And then I am looking for places where the resourcetype is not the same as the resourcetype in the previous row, so I wrote the following UPDATE:

UPDATE #stagingtable
SET typeflag = 1 
WHERE id = (
    SELECT min(id)
    FROM #stagingtable
)
OR resourcetype <> (
    SELECT resourcetype
    FROM #stagingtable rt2
    WHERE rt2.id = (
        SELECT MAX(id) 
        FROM #stagingtable rt3
        WHERE rt3.id < #stagingtable.id
    )
)

Это сработало отлично. Однако среда, в которой я нахожусь, не позволяет мне использовать временные таблицы (RDL!). Поэтому я изменил свою таблицу на табличную переменную:

DECLARE @stagingtable TABLE
(
    id int identity(1,1),
    typeflag int default 0,
    resourcetype varchar(25),
    resource varchar(40),
    est int,
    planned int,
    actual int
)

But the following code doesn't work. 

UPDATE @stagingtable
SET typeflag = 1 
WHERE id = (
    SELECT min(id)
    FROM @stagingtable
)
OR resourcetype <> (
    SELECT resourcetype
    FROM @stagingtable rt2
    WHERE rt2.id = (
        SELECT MAX(id) 
        FROM @stagingtable rt3
        WHERE rt3.id < @stagingtable.id
    )
)

Я получаю сообщение:

Сообщение 137, уровень 16, состояние 1, строка 431. Необходимо объявить скалярную переменную «@stagingtable».

Есть ли способ изменить оператор обновления, чтобы он работал?


person Geoff Snowman    schedule 22.05.2017    source источник
comment
@variables являются локальными для пакета. Я предполагаю, что у вас где-то есть команда GO или вы запускаете ее в другом доступном месте. Вы можете попробовать @@variable, но если вы пытаетесь сохранить эту переменную в любое время, это не лучший способ. почему бы просто не использовать #temp?   -  person scsimon    schedule 22.05.2017


Ответы (2)


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

WHERE rt3.id < @stagingtable.id

DECLARE @stagingtable TABLE
(
    id int identity(1,1),
    typeflag int default 0,
    resourcetype varchar(25),
    resource varchar(40),
    est int,
    planned int,
    actual int
)


UPDATE @stagingtable
SET typeflag = 1 
WHERE id = (
    SELECT min(id)
    FROM @stagingtable
)
OR resourcetype <> (
    SELECT resourcetype
    FROM @stagingtable rt2
    WHERE rt2.id = (
        SELECT MAX(id) 
        FROM @stagingtable rt3
        WHERE rt3.id < rt2.id
    )
)
person Rigerta    schedule 22.05.2017
comment
хороший улов на псевдониме - person scsimon; 22.05.2017
comment
Я не думаю, что это работает, потому что rt2.id не совпадает с stagingtable.id - person Geoff Snowman; 22.05.2017
comment
@GeoffSnowman, что тебе там нужно делать? к основной таблице, к которой вы не можете получить доступ как к простой переменной, это все еще таблица, вам понадобится соединение, чтобы получить из нее строки... - person Rigerta; 22.05.2017
comment
Смотрите мой ответ ниже. - person Geoff Snowman; 22.05.2017
comment
Я только что проверил это, запустив запрос, и синтаксис rt3.id‹rt2.id действительно дает неправильные ответы. При таком подходе флаг типа не устанавливается ни для какой строки, кроме первой строки. В приведенном ниже запросе флаг типа устанавливается для любой строки, где тип ресурса не совпадает с типом ресурса в предыдущей строке. - person Geoff Snowman; 22.05.2017
comment
В любом случае, спасибо за предложение. :) - person Geoff Snowman; 22.05.2017
comment
Вы должны отметить свой ответ как правильный ответ, если у кого-то когда-либо возникала такая же проблема. - person Rigerta; 22.05.2017
comment
Вы не можете принять свой собственный ответ, пока вопрос не будет поднят на некоторое время. Час или два, я думаю. - person Donnie; 22.05.2017

Мне удалось придумать правильный синтаксис, заключающийся в добавлении квадратных скобок вокруг имени переменной:

UPDATE @stagingtable
SET typeflag = 1 
WHERE id = (
    SELECT min(id)
    FROM @stagingtable
)
OR resourcetype <> (
    SELECT resourcetype
    FROM @stagingtable rt2
    WHERE rt2.id = (
        SELECT MAX(id) 
        FROM @stagingtable rt3
        WHERE rt3.id < [@stagingtable].id
    )
)
person Geoff Snowman    schedule 22.05.2017
comment
Используйте update ... from, чтобы вы могли использовать псевдоним самой внешней таблицы. Как и сейчас, тяжело это читать и рассказывать, что происходит, а потом кого-то запутаешь. (stackoverflow.com/questions/4981481/) - person Donnie; 22.05.2017