我在SQL Server中有一个动态的SQL查询。所以我构建它,将其设置为varible,然后我尝试根据日期格式化where子句。但是,当我尝试这样做时,我得到“多部分标识符'FIELD NAME'不能被绑定。我相信这是因为实际的表格在claus中是动态的,所以在编译之前它们是不可见的。有什么方法吗?
在这里,我试图说,给我所有在指定年份+月份之间的人员,例如,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)
答案 0 :(得分:2)
此行给出错误,因为在构建动态字符串时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 :(得分:1)
我意识到你已经修复了你的问题并接受了答案,但我想我还会指出其他一些潜在的改进(无论是你还是未来的任何读者)。
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
眼睛不容易,更容易遵循,更容易维护吗?
要点:
always use the schema prefix在创建,更改或引用对象时。
当您不需要支持Unicode数据时,不要使用Unicode(NCHAR
/ NVARCHAR
)(例如,数字永远不需要包含变音符号)。 Choosing the right data type在这个特定情况下可能不那么重要,但在其他情况下它可能至关重要。
将您的程序正文包裹在BEGIN
/ END
中 - 这可以防止您在不知不觉中从查询窗口中拾取其他不需要的代码。并始终在程序开始时使用SET NOCOUNT ON
。我在“stored procedure best practices checklist。”
为避免行为更改,您应始终包含ORDER BY
子句。如果今天它按名字命令,明天开始按姓氏排序,有人会抱怨。请参阅this post的第二部分。
尽可能学习在没有动态SQL的情况下编写SQL。如果您要继续使用动态SQL,请至少尝试使用sp_executesql
而不是EXEC()。我在最近的另一个问题中解释了原因:SQL Server use EXEC/sp_executesql or just plain sql in stored procedure?
更好的方法是首先将他们的出生日期存储为DATE。为什么要将年份和月份存储为单独的字符串?你必须有这样的理由,但我无法想象它是什么。所有这一切都使得这种字符串匹配效率低于实际使用日期时的效率,降低了对值执行任何类型的日期操作的能力,并且使得验证传入的值非常困难。现在你的东西如果有人打电话给以下人员,它会比以前更加窒息:
EXEC get_persons_by_search_criteria
@month_from = '97',
@year_from = 'Audi',
@month_to = 'TT',
@year_to = 'Oy!!';
他们可以做什么,因为你不进行任何验证。对于DATE变量,至少返回的错误消息是有意义的。现在,对于我们的任何一个版本,他们只会得到一个空的结果集。