Можно ли вызвать ошибку, если присвоение переменной в выборе возвращает несколько значений? - PullRequest
4 голосов
/ 31 декабря 2010

Я только что нашел ошибку в одном из моих программ, где я забыл предложение where.Код был примерно таким:

declare @foo bigint
declare @bar bigint
select @foo = foo, @bar=bar from tbFooBar
where (....a long list of condition goes there)
     (... and an extra condition should have went there but I forgot it)

К сожалению, предложение where, которое я забыл, было полезно в очень специфических угловых случаях, и код успешно прошел тестирование.

В конце концов, запрос вернул двазначения вместо одного, и полученная ошибка была кошмаром для отслеживания (так как ее было очень трудно воспроизвести, и было совершенно не очевидно, что именно эта хранимая процедура вызывала обнаруженную нами проблему)

Отладка была бы намного проще, если бы @ foo = foo вызвал исключение вместо тихого присвоения первого значения из нескольких строк.

Почему это так?Я не могу вспомнить ситуацию, когда кто-то на самом деле хотел бы сделать это, не вызывая ошибки (имея в виду, что пункты «отдельный» и «верхний» существуют по причине)

И есть ли способзаставить sql server 2008 выдавать ошибку, если такая ситуация возникает?

Ответы [ 4 ]

8 голосов
/ 31 декабря 2010

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

declare @d datetime
select @d = arrived from attendance;
if @@ROWCOUNT > 1 begin
    RAISERROR('Was more than expected 1 row.', 16, 1)
end
2 голосов
/ 31 декабря 2010

Почему это так? Люди могут многое сделать, основываясь на том факте, что переменная - это , присвоенная каждой строке. Например, некоторые используют его для выполнения объединения строк .

@ bernd_k демонстрирует один из способов вызвать ошибку, предполагая, что вы присваиваете только одну переменную. На данный момент нет способа обобщить эту технику, если вам нужно назначить несколько переменных - вам все равно нужно убедиться, что ваш запрос возвращает только одну строку


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

declare @dummy bit
select @dummy = CASE WHEN @dummy is null then 1 ELSE 10/0 END

Это приведет к ошибке, если будет возвращено несколько строк.

1 голос
/ 31 декабря 2010

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

declare @foo bigint
select @foo = (
    Select foo 
    from tbFoo
    where (....a long list of condition goes there)
         (... and an extra condition should have went there but I forgot it)
)

Другой синтаксис предназначен для исключения ошибок.

EDIT:

Если вам нужно более 1 столбца, вы можете использовать переменную таблицы, присвоить ей результат, проверить количество строк и работать соответственно.

0 голосов
/ 31 декабря 2010

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

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