【问题标题】:How do I diagnose and fix "Error formatting query, probably invalid parameters, incorrect syntax" error?如何诊断和修复“格式查询错误,可能参数无效,语法不正确”错误?
【发布时间】:2021-11-20 13:09:55
【问题描述】:

我正在整理一个存储过程,它将一些查询结果作为 CSV 附件发送到电子邮件中。我正在测试程序并收到此错误:

Msg 22050, Level 16, State 1, Line 2 格式查询错误,可能 无效参数 Msg 14661,级别 16,状态 1,程序 sp_send_dbmail,第 517 行 [Batch Start Line 2] 查询执行失败: 消息 102,级别 15,状态 1,服务器 NRWOGMSQL6ST\SQLSTD2012,第 27 行 'tbl' 附近的语法不正确。

我知道在 CSV 中产生结果的查询有效,因为我已经在 SP 之外对其进行了测试。我相信所有的引用都是正确的,因为我打印了查询并仔细检查了转义引号。我尝试使用@query_result_no_padding = 1,但它在附加的 CSV 中给了我同样的错误。我也知道 SP 的电子邮件部分有效,因为我一直在使用测试查询来测试事物(请参阅以“SELECT TOP 100”开头的注释掉查询)。

我相信错误是指 tblAPDTracker 表。我尝试注释掉这一行,但下一个错误与“Well”表相同。我不能注释掉井表,因为它是我使用的第一张表。有什么方法可以获取有关问题所在以及如何解决问题的更多信息?

USE [UTRBDMSNET]
GO
/****** Object:  StoredProcedure [dbo].[TestProcedure] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[HiebingTestProcedure] 

AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @message VARCHAR(1000);
    DECLARE @subject VARCHAR(100);
    DECLARE @query VARCHAR(1000);
    DECLARE @tab char(1) = CHAR(9);
    DECLARE @query_attachment_filename VARCHAR(520);
    DECLARE @CRLF char(2);

    SELECT @CRLF = CHAR(13)+CHAR(10)
    SELECT @subject = 'Well Information Report'
    SELECT @message = N'Dear Zeke, '
                      +@CRLF+ ''
                      +@CRLF+ N'Please refer to the attached spread sheet for the results of last month''s information report.'
                      +@CRLF+ ''
                      +@CRLF+ 'Thanks,'
                      +@CRLF+ 'Matt';

    --SELECT @query = 
    --   'SET NOCOUNT ON;
    --    SELECT TOP 100 WellID, Operator, WellStatus, ModifyUser
    --    FROM UTRBDMSNET.dbo.Well';

    SELECT @query =
    '
        SET NOCOUNT ON;
        DECLARE @SearchYear AS VARCHAR(4) = 2020
        DECLARE @SearchMonth AS VARCHAR(2) = 7

        SELECT
            API14,
            [Entity Number],
            [First Prod Date],
            [Spacing Rule],
            TPI AS ''Top Producing Interval Location'',
            BH AS ''Bottom Hole Location'',
            [Well History Comments],
            [Well History Modify Date] AS ''Last Modified Date''
        FROM
        (
        SELECT
            dbo.BuildAPI14(Well.WellID, Construct.SideTrack, Construct.Completion) AS ''API14'',
            CAST(ConstructDate.EventDate AS DATE) AS ''First Prod Date'',
            Loc.LocType AS ''Location Type'',
            CONCAT(''Township '',LocExt.Township,LocExt.TownshipDir,'' '',''Range '',LocExt.Range,LocExt.RangeDir,'' Section '',LocExt.Sec,'' '',RefCounty.CountyName,'' County'') AS ''Location'',
            tblAPDTracker.SpacingRule AS ''Spacing Rule'',
            Lease.Number AS ''Entity Number'',
            WellHistory.WHComments AS ''Well History Comments'',
            WellHistory.ModifyDate AS ''Well History Modify Date''
        FROM UTRBDMSNET.dbo.Well
            LEFT JOIN UTRBDMSNET.dbo.tblAPDTracker ON LEFT(tblAPDTracker.APINO,10) = Well.WellID
            LEFT JOIN UTRBDMSNET.dbo.Construct ON Construct.WellKey = Well.PKey
            LEFT JOIN UTRBDMSNET.dbo.ConstructReservoir ON ConstructReservoir.ConstructKey = Construct.PKey
            LEFT JOIN UTRBDMSNET.dbo.Lease ON Lease.Pkey = ConstructReservoir.LeaseKey
            LEFT JOIN UTRBDMSNET.dbo.WellHistory ON WellHistory.WellKey = Construct.WellKey
            LEFT JOIN UTRBDMSNET.dbo.ConstructDate ON ConstructDate.ConstructKey = Construct.PKey AND ConstructDate.Event = ''FirstProduction''
            LEFT JOIN UTRBDMSNET.dbo.Loc ON loc.ConstructKey = Construct.PKey AND Loc.LocType IN (''BH'',''TPI'')
            LEFT JOIN UTRBDMSNET.dbo.LocExt ON LocExt.LocKey = Loc.PKey
            LEFT JOIN UTRBDMSNET.dbo.RefCounty ON RefCounty.PKey = LocExt.County
        WHERE
                WellHistory.WorkType = ''ENTITY''
            AND WellHistory.ModifyUser = ''UTAH\rachelmedina''
            AND YEAR(WellHistory.ModifyDate) = @SearchYear
            AND MONTH(WellHistory.ModifyDate) = @SearchMonth
        GROUP BY
            Well.WellID,
            Construct.SideTrack,
            Construct.Completion,
            ConstructDate.EventDate,
            Loc.LocType,
            LocExt.Township,
            LocExt.TownshipDir,
            LocExt.Range,
            LocExt.RangeDir,
            LocExt.Sec,
            RefCounty.CountyName,
            tblAPDTracker.SpacingRule,
            Lease.Number,
            WellHistory.WHComments,
            WellHistory.ModifyDate
        ) AS BasicQuery
        PIVOT
        (
        MIN(BasicQuery.Location) FOR [Location Type] IN ([TPI], [BH])
        ) AS PivotedQuery
        ORDER BY
            API14,
            [Well History Modify Date];
    '
    
    SELECT @query_attachment_filename = 'TestingEmailAttachment.csv';

    EXEC msdb.dbo.sp_send_dbmail
        @profile_name = 'OilGasEmail',
        @from_address = 'mhiebing@utah.gov',
        @recipients = 'mhiebing@utah.gov ',
        @body = @message,
        @query = @query,
        @query_attachment_filename = @query_attachment_filename,
        @attach_query_result_as_file = 1,
        @query_result_header = 1,
        @query_result_width = 32767,
        @query_result_separator = @tab,
        @append_query_error = 0
        --@query_result_no_padding = 1;
END

下面是我希望在电子邮件 CSV 中看到的几行结果。

API14 Entity Number First Prod Date Spacing Rule Top Producing Interval Location Bottom Hole Location Well History Comments Last Modified Date
43013534820000 100260 2019-01-09 139-134 Township 3S Range 1W Section 22 DUCHESNE County Township 3S Range 1W Section 15 DUCHESNE County Moved to CTB entity 100401 2020-07-15 17:27:00
43013534820000 100401 2019-01-09 139-134 Township 3S Range 1W Section 22 DUCHESNE County Township 3S Range 1W Section 15 DUCHESNE County Moved to CTB entity 100401 2020-07-15 17:27:00
43013534860000 100246 2019-01-09 139-134 Township 3S Range 1W Section 22 DUCHESNE County Township 3S Range 1W Section 15 DUCHESNE County Moved to CTB entity 100401. 2020-07-15 17:28:00

【问题讨论】:

  • DECLARE "@"SearchYear AS VARCHAR(4) = 2020 DECLARE "@"SearchMonth AS VARCHAR(2) = 7 为什么要在字符串类型的变量中使用数字?
  • 如果省略 3 部分命名,而只使用 2 部分命名,然后使用 @execute_query_database 参数定义需要在其中运行查询的数据库,会发生什么情况?
  • @SQLpro 最后,我希望这个 SP 在本月 1 日运行。我将用动态数字替换这两个变量,这些数字将调用当前年份的上个月。我尝试删除它们并将数字直接放入查询中,但没有任何区别。
  • 那是 1 部分命名,@Hiebs915 ... 始终符合架构条件
  • @Hiebs915 这意味着始终为模式绑定对象指定模式名称。因此,请使用dbo.tblAPDTracker 而不仅仅是tblAPDTracker。您的查询已经这样做了,Larnu 只是指您询问您是否应该只使用 tblAPDTracker 而不是 dbo.tblAPDTracker 当您误解使用 2 部分命名(即 dbo.tblAPDTracker)而不是 3 部分命名的原始建议时,其中包括数据库名称(例如UTRBDMSNET.dbo.Lease)。 Larnu 建议删除第一部分——数据库名称——然后通过@execute_query_database 参数传递数据库名称。

标签: sql-server tsql dynamic-sql truncation dbmail


【解决方案1】:

问题非常简单,以至于被忽略了:由于@query 变量未声明为足够大以容纳查询而导致字符串截断。

@query 更改为VARCHAR(4000) 即可,尽管NVARCHAR(MAX) 是最佳/理想的选择。

我开始将截断视为错误原因的原因是由于错误消息:

| 'tbl' 附近的语法不正确。

表面上看起来是表别名,但我搜索并发现字符串tbl 只用作表名的前缀。当您收到一条仅包含部分文本的错误消息时,通常表明优化器没有看到查询的其余部分(或者错误消息太长而被切断,但显然不是这种情况在这里)。

附加说明

另外,与我使用NVARCHAR 而不是VARCHAR 的建议有关,看看代码中的至少一些字符串文字如何以N 为前缀(使它们NVARCHAR 文字):您应该将所有变量声明为 NVARCHAR,因为如果使用了不属于与当前数据库的默认排序规则关联的代码页的任何字符(“当前”为此存储过程所在的位置)。同样,CHAR 变量应该是 NCHAR

那么,所有的字符串文字都应该以N 为前缀,而不仅仅是其中的一部分。

最后,列名别名(即AS 之后的名称)应该使用方括号而不是单引号。例如:

Loc.LocType AS [Location Type]

代替:

Loc.LocType AS ''Location Type''

【讨论】:

  • 哇,这成功了!谢谢!昨天我在查找此内容时很接近,甚至查找了 VARCHAR 和 NVARCHAR 之间的差异,但从未想过要更改字符数……我尝试了 VARCHAR(4000)NVARCHAR(MAX),两者都有效。我将使用NVARCHAR(MAX)
  • @Hiebs915 欢迎您。是的,我希望通过分享提示我的原因可以帮助其他人更快地识别这些问题,而不是浪费时间进行微小的修改和重新测试。另外,请参阅我刚刚添加到此答案末尾的附加说明。
  • 我看到了您的补充说明,再次感谢。我将所有VARCHARs 更改为NVARCHAR。关于方括号的重要提示也是如此。在其他帖子中,单引号通常是问题,所以我花了很多时间检查它们。在这种情况下,方括号更容易使用。
  • @Hiebs915 而且,使用动态 SQL 时方括号不仅更容易,我相信使用单引号是一种已弃用的语法(这将在未来 50 年内有效,但仍然有明确的偏好一个原因)。
  • @Hiebs915 是的,但更好的弃用信息来源直接来自 Microsoft。只需转到此处:docs.microsoft.com/en-us/sql/database-engine/… 并查找“列别名”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-25
  • 2019-12-02
  • 1970-01-01
相关资源
最近更新 更多