我使用@SQL变量构建了一个相当大的语句,然后从语句末尾的变量运行查询。除了将日期插入其中一个参数外,此操作很好。
然后查询不返回数据,并返回一个错误:
从字符串转换日期和/或时间时,转换失败。
我目前拥有的SQL如下:
ALTER PROCEDURE [dbo].[GetVisitListFiltered]
@sitekey int,
@VisitNo int = NULL,
@DNS varchar(max) = NULL,
@SessionStarted varchar(15) = '01/01/1900',
@Page varchar(max) = NULL,
@SecondsOnSite int = NULL,
@SecondsOnSiteRange int = NULL,
@Pages int = NULL,
@Cost int = NULL,
@City varchar(max) = NULL,
@Country varchar(max) = NULL,
@Keywords varchar(max) = NULL,
@Referrer varchar(max) = NULL
AS
BEGIN
BEGIN TRY
SET @SecondsOnSiteRange =
CASE @SecondsOnSiteRange
WHEN 1 THEN '='
WHEN 2 THEN '>'
WHEN 3 THEN '<'
ELSE NULL
END
DECLARE @SQL NVARCHAR(MAX)
, @SQLParams NVARCHAR(MAX);
SET @SQL = N'
SELECT VKey,
VisitIP,
SiteKey,
Alert,
AlertNo,
VisitNo,
Invited,
Chatted,
Prospect,
Customer,
HackRaised,
Spider,
Cost,
Revenue,
Visits,
FirstDate,
TotalCost,
TotalRevenue,
OperatingSystem,
Browser,
SearchEngine,
Referrer,
Keywords,
ReferrerQuery,
Name,
Email,
Company,
Telephone,
Fax,
Street,
City,
Zip,
Country,
Web,
Organization,
CRMID,
Notes,
DNS,
Region,
FirstAlert,
FirstVisitReferrer,
ProspectTypes,
VisitDate,
SecondsOnSite,
Page
FROM dbo.VisitDetail
WHERE SiteKey = @p0';
IF NULLIF(@VisitNo, '') IS NOT NULL SET @SQL += N' AND VisitNo = @p1';
IF NULLIF(@DNS, '') IS NOT NULL SET @SQL += N' AND DNS = @p2';
IF NULLIF(@SessionStarted, '01/01/1900') IS NOT NULL SET @SQL += N' AND VisitDate between @p3 and @p3 23:59:59';
IF NULLIF(@Page, '') IS NOT NULL SET @SQL += N' AND Page = @p4';
IF NULLIF(@SecondsOnSite, '') IS NOT NULL AND NULLIF(@SecondsOnSiteRange, '') IS NOT NULL SET @SQL += N' AND SecondsOnSite' + '@p12' + '@p5';
IF NULLIF(@Pages, '') IS NOT NULL SET @SQL += N' AND PagesSeen = @p6';
IF NULLIF(@Cost, '') IS NOT NULL SET @SQL += N' AND Cost = @p7';
IF NULLIF(@City, '') IS NOT NULL SET @SQL += N' AND City = @p8';
IF NULLIF(@Country, '') IS NOT NULL SET @SQL += N' AND Country = @p9';
IF NULLIF(@Keywords, '') IS NOT NULL SET @SQL += N' AND Keywords = @p10';
IF NULLIF(@Referrer, '') IS NOT NULL SET @SQL += N' AND ReferrerQuery = @p11';
SET @SQLParams = N'
@p0 INT
, @p1 INT
, @p2 VARCHAR(MAX)
, @p3 VARCHAR(15)
, @p4 VARCHAR(MAX)
, @p5 INT
, @p6 INT
, @p7 INT
, @p8 VARCHAR(MAX)
, @p9 VARCHAR(MAX)
, @p10 VARCHAR(MAX)
, @p11 VARCHAR(MAX)
, @p12 VARCHAR(10)';
EXECUTE sp_executesql @SQL
, @SQLParams
, @p0 = @SiteKey
, @p1 = @VisitNo
, @p2 = @DNS
, @p3 = @SessionStarted
, @p4 = @Page
, @p5 = @SecondsOnSite
, @p6 = @Pages
, @p7 = @Cost
, @p8 = @City
, @p9 = @Country
, @p10 = @Keywords
, @p11 = @Referrer
, @p12 = @SecondsOnSiteRange;
END TRY
BEGIN CATCH
SELECT ERROR_MESSAGE();
END CATCH
END
我知道问题就在这方面:
IF NULLIF(@SessionStarted, '01/01/1900') IS NOT NULL
SET @SQL += N' AND VisitDate between @p3 and @p3 23:59:59';
但我不知道怎么解决--有人能建议我做错了什么吗?
发布于 2015-09-03 03:13:24
已经有人指出,当@SessionStarted
应该是一个日期时,它是一个VARCHAR
。并且您的最终SQL格式不正确,其有效性不亚于:
DECLARE @p3 DATE = GETDATE();
SELECT Test = @p3 '23:59:59';
这意味着:
Msg 102,15级,状态1,第3行 在“23:59:59”附近不正确的语法。
但我想强调另一点:
不使用像这样的
您正在尝试构造如下语句:
WHERE Date BETWEEN '2015-09-03' AND '2015-09-03 23:59:59'
但是,如果Date
是'2015-09-03 23:59:59.5‘-你真的想把这个排除在外吗?最佳做法是使用一个开放的范围:
WHERE Date >= '2015-09-03'
AND Date < '2015-09-04'
差不多一样,但涵盖了一整天,而不仅仅是大部分时间。所以你的确切陈述应该是:
IF NULLIF(@SessionStarted, '01/01/1900') IS NOT NULL
SET @SQL += N' AND VisitDate >= @p3 AND VisitDate < DATEADD(DAY, 1, @p3)';
亚伦·伯特兰( Aaron Bertrand )在这方面写了一篇伟大的文章,以供进一步阅读。
因此,总而言之,部分修复将是使用串联运算符+
。
DECLARE @p3 VARCHAR(50) = '03/09/2015';
SELECT Test = @p3 + ' 23:59:59';
更好的解决办法是转换为正确的数据类型:
DECLARE @p3 VARCHAR(50) = '03/09/2015';
SELECT Test = CONVERT(DATETIME, @p3 + ' 23:59:59');
更好的做法是使用区域性不变的日期格式,因此很清楚您指的是9月3日还是3月9日:
DECLARE @p3 VARCHAR(50) = '20150903';
SELECT Test = CONVERT(DATETIME, @p3 + ' 23:59:59');
更好的做法是首先使用正确的数据类型:
DECLARE @p3 DATETIME = '20150903';
SELECT Test = @p3 + '23:59:59';
更好的做法是,如上文所述,使用一个开放日期范围。
发布于 2015-09-03 02:57:01
您已经声明sessionstarted
是一个字符,而不是日期。我想这是你问题的根源。
将类型更改为日期。我还建议您对日期使用ISO标准YYYY DD格式,而不是使用特定于区域性的格式。
发布于 2015-09-03 02:58:04
你的问题在于这一点@p3 23:59:59';
您正在尝试将字符串值连接到日期。您需要做的是在@p3中添加一个日期(DATEADD),并将其用作另一个参数。
https://stackoverflow.com/questions/32373608
复制相似问题