1

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

Msg 22050, Level 16, State 1, Line 2 格式查询错误,可能参数无效 Msg 14661, Level 16, State 1, Procedure sp_send_dbmail, Line 517 [Batch Start Line 2] 查询执行失败:Msg 102, Level 15, State 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 实体编号 首次生产日期 间距规则 最高生产区间位置 底孔位置 井历史评论 最后修改日期
43013534820000 100260 2019-01-09 139-134 乡镇 3S 范围 1W 第 22 段 DUCHESNE 县 乡镇 3S 范围 1W 第 15 段 DUCHESNE 县 移至 CTB 实体 100401 2020-07-15 17:27:00
43013534820000 100401 2019-01-09 139-134 乡镇 3S 范围 1W 第 22 段 DUCHESNE 县 乡镇 3S 范围 1W 第 15 段 DUCHESNE 县 移至 CTB 实体 100401 2020-07-15 17:27:00
43013534860000 100246 2019-01-09 139-134 乡镇 3S 范围 1W 第 22 段 DUCHESNE 县 乡镇 3S 范围 1W 第 15 段 DUCHESNE 县 移至 CTB 实体 100401。 2020-07-15 17:28:00
4

1 回答 1

2

问题是如此简单以至于被忽略了:由于@query变量未声明为具有足够大的大小以容纳查询而导致的字符串截断。

改变@queryVARCHAR(4000),它会工作,虽然NVARCHAR(MAX)是最好的/理想的选择。

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

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

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

补充笔记

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

然后,所有字符串文字都应该以 为前缀N,而不仅仅是其中的一些。

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

Loc.LocType AS [Location Type]

代替:

Loc.LocType AS ''Location Type''
于 2021-09-28T14:22:55.207 回答