Как мне ссылаться на поле в динамическом запросе SQL? - PullRequest
1 голос
/ 27 августа 2011

У меня динамический SQL-запрос в SQL Server. Поэтому я создаю его, устанавливаю переменную, а затем пытаюсь отформатировать предложение where на основе даты. Тем не менее, когда я пытаюсь сделать это, я получаю «Идентификатор поля« ИМЯ ПОЛЯ »не может быть привязан. Я полагаю, что это потому, что фактические таблицы находятся в динамике от Клауса, поэтому их нельзя увидеть, пока он не скомпилирован. Есть ли способ обойти это?

Здесь я пытаюсь сказать, дайте мне всех лиц, для которых DOB между ГОДОМ + МЕСЯЦОМ, например, 201001 и 201012 будет целым 2010 годом. Вот код частично ...

    ALTER PROCEDURE get_persons_by_search_criteria

@month_from as nvarchar(2) = null,
@year_from as nvarchar(4) = null,
@month_to as nvarchar(2) = null,
@year_to as nvarchar(4) = null


AS

declare @from_date varchar(10)
declare @to_date varchar(10)
declare @sqlstr varchar(5000)

set @sqlstr = ' SELECT     
    Person.PersonID, 
    Person.FirstName, 
    Person.LastName, 
FROM    Person '

--Attemtping to create a value like 201108 (year + month)
set @from_date = Convert(VarChar(10), @year_from) + Replace(Str(@month_from, 2), ' ', '0')  
set @to_date = Convert(VarChar(10), @year_to) + Replace(Str(@month_to, 2), ' ', '0') 

set @sqlstr = @sqlstr +  ' WHERE '
set @sqlstr = @sqlstr + Convert(VarChar(10), Person.DOBYear) + Replace(Str(Person.DOBMonth, 2), ' ', '0') 
set @sqlstr = @sqlstr + ' BETWEEN '   + @from_date + ' and ' + @to_date


exec(@sqlstr)

Ответы [ 2 ]

2 голосов
/ 27 августа 2011

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

set @sqlstr = @sqlstr + Convert(VarChar(10), Person.DOBYear) + Replace(Str(Person.DOBMonth, 2), ' ', '0')

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

set @sqlstr = @sqlstr + ' Convert(VarChar(10), Person.DOBYear) + Replace(Str(Person.DOBMonth, 2), '' '', ''0'') '

Должен сделать трюк за вас ..

1 голос
/ 28 августа 2011

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

ALTER PROCEDURE dbo.get_persons_by_search_criteria
    @month_from VARCHAR(2) = NULL,
    @year_from  VARCHAR(4) = NULL,
    @month_to   VARCHAR(2) = NULL,
    @year_to    VARCHAR(4) = NULL
AS
BEGIN 
   SET NOCOUNT ON;

   SELECT
       PersonID, DOBYear, DOBMonth
   FROM
       dbo.Person
   WHERE 
       DOBYear + RIGHT('0' + DOBMonth, 2) + '01'
       BETWEEN @year_from + RIGHT('0' + @month_from, 2) + '01'
           AND @year_to   + RIGHT('0' + @month_to,   2) + '01'
   ORDER BY 
       PersonID, DOBYear, DOBMonth;
END
GO

Разве это не легче для глаз, легче следить и легче поддерживать?

Описание:

  • всегда используйте префикс схемы при создании, изменении или ссылке на объекты.

  • не используйте Unicode (NCHAR / NVARCHAR), когда вам не нужно поддерживать данные Unicode (например, числа никогда не должны содержать умлауты). Выбор правильного типа данных может быть не так важен в данном конкретном случае, но может иметь решающее значение в других.

  • оберните тело процедуры в BEGIN / END - это предотвратит неосознанный выбор другого нежелательного кода из окна запроса. И всегда используйте SET NOCOUNT ON в начале вашей процедуры. Я обращаюсь к этим и другим вопросам в моем « контрольном списке передовых практик хранимых процедур ».

  • , чтобы избежать изменений в поведении, вы всегда должны включать предложение ORDER BY. Если сегодня он заказывает по имени, а завтра начинает заказывать по фамилии, кто-то собирается пожаловаться. См. Второй раздел этого поста .

  • научиться писать SQL без динамического SQL, когда это возможно. Если вы собираетесь продолжать использовать динамический SQL, по крайней мере, пожалуйста, попробуйте использовать sp_executesql вместо EXEC () . Я объяснил причины в другом недавнем вопросе: SQL Server использует EXEC / sp_executesql или просто SQL в хранимой процедуре?

Еще лучше было бы просто сохранить дату своего рождения в качестве ДАТЫ. Зачем хранить год и месяц как отдельные строки? Должна быть какая-то причина, по которой вы делаете это, но я не могу представить, что это такое. Все, что он делает, - делает этот вид сопоставления строк менее эффективным, чем если бы вы на самом деле использовали даты, уменьшает вашу способность выполнять любые операции с датами над значениями и очень затрудняет проверку переданных значений. Прямо сейчас ваши вещи будет задыхаться позже, чем должно быть, если кто-то позвонит по следующему номеру:

EXEC get_persons_by_search_criteria 
    @month_from = '97',
    @year_from  = 'Audi',
    @month_to   = 'TT',
    @year_to    = 'Oy!!';

Что они могли бы сделать, потому что вы вообще не выполняете проверку. С переменными DATE, по крайней мере, возвращаемое сообщение об ошибке имело бы смысл. Прямо сейчас с любой из наших версий они просто получат пустой набор результатов.

...