简体   繁体   English

SQL 服务器存储过程参数语法错误

[英]SQL Server stored procedure parameters syntax error

I have the following query:我有以下查询:

DECLARE @periodEnd datetime = '2021-12-09 02:41:42.000'
DECLARE @ID VARCHAR(50) = '35915D4B-E210-48C0-ADD5-C68AAEB62C36'

EXEC('SELECT COUNT(*) AS count FROM pageloads nolock WHERE domainId = ''' + @ID+ ''' AND paid = 1 AND source IN (2) AND clickedOn BETWEEN DATEADD(MONTH, -3,' + @periodEnd + ') AND ' + @periodEnd)

but I get an error:但我收到一个错误:

Incorrect syntax near '9'. '9' 附近的语法不正确。

There is no need for dynamic SQL here.这里不需要动态 SQL。 The actual code you have won't generate that error either;您拥有的实际代码也不会产生该错误; it would likely generate this error instead:它可能会产生此错误:

Msg 241, Level 16, State 1, Line 4消息 241,第 16 级,State 1,第 4 行
Conversion failed when converting date and/or time from character string从字符串转换日期和/或时间时转换失败

This is because you add (as in addition) the value 'select...MONTH, -3,' to the datetime value 2021-12-09T02:41:42.000 ;这是因为您向datetime时间值2021-12-09T02:41:42.000添加(另外)值'select...MONTH, -3,' obviously the former is not a valid datetime and the conversion fails.显然前者不是有效的datetime时间并且转换失败。

Use a parametrised non-dynamic statement, and you'll get no errors.使用参数化的非动态语句,你不会得到任何错误。

DECLARE @periodEnd datetime = '2021-12-09T02:41:42.000'; -- Use an unambiguous datetime format
DECLARE @ID uniqueidentifier = '35915D4B-E210-48C0-ADD5-C68AAEB62C36'; --This is clearly a GUID, so use the right data type.
SELECT COUNT(*) AS count
FROM dbo.pageloads pl --nolock is an odd alias. I've gone for a better one.
WHERE domainId = @ID
  AND paid = 1
  AND source IN (2) --Why IN when you only supply one value?
  AND clickedOn BETWEEN DATEADD(MONTH, -3, @periodEnd) AND @periodEnd;

Also note that the BETWEEN may not be doing what you expect.另请注意, BETWEEN可能没有按照您的预期进行。 For the above, this would resolve to effectively the following:对于上述情况,这将有效地解决以下问题:

  AND clickedOn >= '2021-09-09T02:41:42.000'
  AND clickedOn <= '2021-12-09T02:41:42.000'

Most times I see people use such logic with BETWEEN that want exclusive of time, and >= and < logic;大多数时候,我看到人们将这种逻辑与想要排除时间的BETWEEN以及>=<逻辑一起使用; though I am not going to guess that is what you want here.虽然我不会猜测这就是你想要的。

You are simply missing a few single quotes around your date variables.您只是在日期变量周围缺少一些单引号。 Since you are building your query in dynamic SQL, your dates are passed into the dynamic query as date literals, so therefore they need single quotes around them.由于您在动态 SQL 中构建查询,因此您的日期作为日期文字传递到动态查询中,因此它们需要单引号。

To represent a single quote in your dynamic SQL, you actually need 3 single quotes, as you already have around your @ID variable.要在动态 SQL 中表示单引号,您实际上需要 3 个单引号,正如您在 @ID 变量周围已有的那样。 At the end, you need 4 single quotes to both add the single quote into the dynamic and also to terminate the EXEC string.最后,您需要 4 个单引号将单引号添加到动态中并终止 EXEC 字符串。

So it would look like this:所以它看起来像这样:

DECLARE @periodEnd datetime = '2021-12-09 02:41:42.000'
DECLARE @ID VARCHAR(50) = '35915D4B-E210-48C0-ADD5-C68AAEB62C36'

EXEC('SELECT COUNT(*) AS count FROM pageloads nolock WHERE domainId = ''' + @ID+ ''' AND paid = 1 AND source IN (2) AND clickedOn BETWEEN DATEADD(MONTH, -3,''' + @periodEnd + ''') AND ''' + @periodEnd + '''')

Any time I pass variables into Dynamic SQL I always end up with code littered with single quotes like this.每当我将变量传递给动态 SQL 时,我总是会得到像这样的单引号乱七八糟的代码。

It looks like you are trying to use the WITH(NOLOCK) table hint to speed up the process and to prevent any performance impact while you're running this count, which is a good idea.看起来您正在尝试使用 WITH(NOLOCK) 表提示来加快进程并防止在运行此计数时对性能产生任何影响,这是一个好主意。 You will get a lot of pushback on this website about using WITH(NOLOCK), but not from me.你会在这个网站上收到很多关于使用 WITH(NOLOCK) 的反对意见,但不是来自我。 It's a very useful feature for this type of query, where you want a quick number and don't want to grind your logging process to a halt while you get it.对于这种类型的查询,这是一个非常有用的功能,您需要一个快速的数字,并且不想在获得它时将您的日志记录过程停止。

The correct syntax to use WITH(NOLOCK) would be:使用 WITH(NOLOCK) 的正确语法是:

DECLARE @periodEnd datetime = '2021-12-09 02:41:42.000'
DECLARE @ID VARCHAR(50) = '35915D4B-E210-48C0-ADD5-C68AAEB62C36'

EXEC('SELECT COUNT(*) AS count FROM pageloads pl WITH(NOLOCK) WHERE domainId = ''' + @ID+ ''' AND paid = 1 AND source IN (2) AND clickedOn BETWEEN DATEADD(MONTH, -3,''' + @periodEnd + ''') AND ''' + @periodEnd + '''')

Previously you were using "nolock" as a table alias, which is not a great idea.以前您使用“nolock”作为表别名,这不是一个好主意。 I changed the table alias to "pl".我将表别名更改为“pl”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM