Моя хранимая процедура выполняется не по порядку? - PullRequest
0 голосов
/ 14 января 2010

Краткая история: Я пишу хранимую процедуру для поддержки устаревшей системы отчетов (с использованием SQL Server Reporting Services 2000) в устаревшем веб-приложении. В соответствии с исходным стилем реализации каждый отчет имеет отдельную хранимую процедуру в базе данных, которая выполняет все запросы, необходимые для возврата «окончательного» набора данных, который может быть просто воспроизведен сервером отчетов.

В связи с бизнес-требованиями этого отчета возвращенный набор данных имеет неизвестное количество столбцов (это зависит от пользователя, который выполняет отчет, но может иметь 4-30 столбцов).

На протяжении всей хранимой процедуры я сохраняю столбец UserID, чтобы отслеживать идентификатор пользователя для выполнения дополнительных запросов. В конце, однако, я делаю что-то вроде этого:

UPDATE #result
SET Name = ppl.LastName + ', ' + ppl.FirstName
FROM #result r
LEFT JOIN Users u ON u.id = r.userID
LEFT JOIN People ppl ON ppl.id = u.PersonID

ALTER TABLE #result
DROP COLUMN [UserID]

SELECT * FROM #result r ORDER BY Name

По сути, я установил для столбца Имя varchar (который ранее оставался пустым, пока выполнял некоторую логику поворота) желаемый формат имени в виде простого текста.

Когда закончите, я хочу удалить столбец UserID, так как пользователь отчета не должен видеть это.

Наконец, возвращенный набор данных имеет один столбец для имени пользователя и произвольное количество столбцов INT с суммарными показателями производительности. По этой причине я не могу просто исключить столбец UserID, поскольку SQL не поддерживает «SELECT * EXCEPT [UserID]» или тому подобное.

С этим известным (любые указатели стилей приветствуются, но не являются центральными для этой проблемы), вот проблема:

Когда я выполняю эту хранимую процедуру, я получаю ошибку выполнения:

Invalid column name 'userID'.

Однако, если я закомментирую свой оператор DROP COLUMN и сохраню идентификатор пользователя, хранимая процедура будет работать правильно.

Что происходит? Конечно, похоже, что операторы выполняются не по порядку и отбрасывают столбец, прежде чем я смогу использовать его для установки строк имен!

[Редактировать 1] Я определил UserID ранее (вся хранимая процедура содержит около 200 лож, в основном не относящихся к делу логики, поэтому я вставлю фрагменты:

    CREATE TABLE #result ([Name] NVARCHAR(256), [UserID] INT);

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

Моя «испорченная» хранимая процедура также работает должным образом в SQL Server 2008 - это либо ошибка 2000 года, либо я совершенно не понимаю, как работал SQL Server.

Спасибо всем за участие!

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

DECLARE @workaroundTableName NVARCHAR(256), @workaroundQuery NVARCHAR(2000)
SET @workaroundQuery = 'SELECT [Name]';
DECLARE cur_workaround CURSOR FOR
SELECT COLUMN_NAME FROM [tempdb].INFORMATION_SCHEMA.Columns WHERE TABLE_NAME LIKE '#result%' AND COLUMN_NAME <> 'UserID'
OPEN cur_workaround;
FETCH NEXT FROM cur_workaround INTO @workaroundTableName
WHILE @@FETCH_STATUS = 0
BEGIN
    SET @workaroundQuery = @workaroundQuery + ',[' + @workaroundTableName + ']'
    FETCH NEXT FROM cur_workaround INTO @workaroundTableName
END
CLOSE cur_workaround;
DEALLOCATE cur_workaround;
SET @workaroundQuery = @workaroundQuery + ' FROM #result ORDER BY Name ASC'
EXEC(@workaroundQuery);

Спасибо всем!

Ответы [ 4 ]

4 голосов
/ 14 января 2010

Гораздо более простым решением было бы не отбрасывать столбец, но не возвращать его при окончательном выборе.

Есть множество причин, по которым вам все равно не следует возвращать select * из вашей процедуры.

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

На основании сообщения об ошибке чувствительна ли к регистру база данных, и поэтому существует разница между userID и UserID?

1 голос
/ 14 января 2010

Это работает для меня:

CREATE TABLE #temp_t
 (
  myInt int,
  myUser varchar(100)
 )

INSERT INTO #temp_t(myInt, myUser) VALUES(1, 'Jon1')
INSERT INTO #temp_t(myInt, myUser) VALUES(2, 'Jon2')
INSERT INTO #temp_t(myInt, myUser) VALUES(3, 'Jon3')
INSERT INTO #temp_t(myInt, myUser) VALUES(4, 'Jon4')

ALTER TABLE #temp_t
DROP Column myUser

SELECT * FROM #temp_t

DROP TABLE #temp_t

Там написано, что столбец неверен для вас. Вы проверили орфографию и убедитесь, что в вашей временной таблице даже есть этот столбец.

0 голосов
/ 15 января 2010

Во время компиляции SQL Server, вероятно, расширяет * в полный список столбцов. Таким образом, во время выполнения SQL Server выполняет «SELECT UserID, Name, LastName, FirstName, ...» вместо «SELECT *». Динамическая сборка финального SELECT в строку и последующее EXECing в конце хранимой процедуры может быть подходящим способом.

0 голосов
/ 14 января 2010

Вы можете попробовать обернуть все, что предшествует DROP COLUMN, в транзакцию BEGIN ... COMMIT.

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