执行存储过程和查询之间的区别(因类型而导致算术溢出)

Pov*_*vas 5 sql stored-procedures sql-server-2012

问题是:为什么在执行查询和存储过程时数据类型如何转换/解释会有区别?

我有一个存储过程,它给了我:

Msg 8115, Level 16, State 2, Procedure sp****ChargePackagingTest, Line 9
Arithmetic overflow error converting expression to data type nvarchar.
Run Code Online (Sandbox Code Playgroud)

问题是它只在作为存储过程执行时发生:

exec [sp****ChargePackagingTest] '2016-10-14', '2016-10-25'
Run Code Online (Sandbox Code Playgroud)

但是,如果我执行相同的查询(在存储过程外部复制并使用相同的参数声明并使用SQL管理工作室),我不会遇到问题.

最重要的是,我知道问题的确切位置:CONVERT(nvarchar(2),JobPDF.Pages/2)

存储过程说问题在第9行,但实际上并非如此.如果我将它更改为nvarchar(3),它甚至可以作为存储过程执行.

但是,JobPdf.Pages是可以为null的int类型:值只有24,48,72(我已经检查过).此外,它仅在有足够数据时崩溃,即,它不是特定于日期范围,而是特定于日期范围的长度.

存储过程代码:

ALTER PROCEDURE [dbo].[sp****ChargePackagingTest]
@dateFrom DateTime, @dateTo DateTime

AS
BEGIN

SELECT costPerOrder****.[Product Name], costPerOrder****.[Pack Price], SUM([Pack Count]) as [Pack Count], SUM(costPerOrder****.[Packaging Cost]) as [Packaging Cost]
FROM
(
    -- Raw data aggregated by order
    SELECT [Product Name], [Pack Price]
    , CEILING(SUM(Quantity) * 1.0 / [Pack Items]) as [Pack Count] -- 1.0 converts it to decimal and uses decimal division
    , CEILING(SUM(Quantity) * 1.0 / [Pack Items])  * [Pack Price] as [Packaging Cost]
    FROM

        (
        -- Raw Polaroid data (basically we creating LookUp_Product and joining with orders)
        select JobDetail.OrderId, ProductName + ' ' + CONVERT(nvarchar(2), JobPDF.Pages / 2) as [Product Name]

        , job.Quantity
        , CASE

        when LookUp_Product.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A' AND JobPDF.Pages = 24 THEN 0.063 -- **** 12 pages
        when LookUp_Product.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A' AND JobPDF.Pages = 48 THEN 0.063 -- **** 24 pages
        when LookUp_Product.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A' AND JobPDF.Pages = 72 THEN 0.089 -- **** 36 pages
        ELSE NULL 
        END as [Pack Price]

        ,CASE

        when LookUp_Product.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A' AND JobPDF.Pages = 24 THEN 2 -- **** 12 pages
        when LookUp_Product.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A' AND JobPDF.Pages = 48 THEN 2 -- **** 24 pages
        when LookUp_Product.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A' AND JobPDF.Pages = 72 THEN 3 -- **** 36 pages
        ELSE NULL
        END as [Pack Items]

        FROM Job WITH (NOLOCK)
        inner join LookUp_Product WITH (NOLOCK) on LookUp_Product.ProductID = job.ProductID

        inner join JobEvent WITH (NOLOCK)  on JobEvent.JobID = job.JobID
        inner join JobDetail WITH (NOLOCK)  on JobDetail.JobID = job.JobID
        inner join Orders WITH (NOLOCK)  on Orders.OrderId = JobDetail.OrderID
        inner join JobPDF WITH (NOLOCK)  on JobPDF.JobID = job.JobID
        where 1=1

        AND LookUp_Product.ClientID = 'AC7EDBCD-39DF-45CE-8D96-A26EB17D1E2D' 
        AND Job.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A'
        AND JobDetail.CurrentEventID = 999999
        AND JobEvent.EventID = 999999
        AND JobEvent.DateDone >= @dateFrom
        AND JobEvent.DateDone < @dateTo
        AND PackPrice is not null AND PackPrice <> 0.0000
        ) as Raw****Data

    GROUP BY Raw****Data.OrderID, [Product Name], [Pack Price], [Pack Items]) costPerOrder****

GROUP BY [Product Name], [Pack Price]
ORDER BY [Product Name]

END
Run Code Online (Sandbox Code Playgroud)

查询执行示例:

declare @dateFrom DateTime = '2016-10-14'
declare @dateTo DateTime = '2016-10-25'

SELECT costPerOrder****.[Product Name], costPerOrder****.[Pack Price], SUM([Pack Count]) as [Pack Count], SUM(costPerOrder****.[Packaging Cost]) as [Packaging Cost]
FROM
(
    -- Raw data aggregated by order
    SELECT [Product Name], [Pack Price]
    , CEILING(SUM(Quantity) * 1.0 / [Pack Items]) as [Pack Count] -- 1.0 converts it to decimal and uses decimal division
    , CEILING(SUM(Quantity) * 1.0 / [Pack Items])  * [Pack Price] as [Packaging Cost]
    FROM

        (
        -- Raw **** data (basically we creating LookUp_Product and joining with orders)
        select JobDetail.OrderId, ProductName + ' ' + CONVERT(nvarchar(2), JobPDF.Pages / 2) as [Product Name]

        , job.Quantity
        , CASE

        when LookUp_Product.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A' AND JobPDF.Pages = 24 THEN 0.063 -- **** 12 pages
        when LookUp_Product.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A' AND JobPDF.Pages = 48 THEN 0.063 -- **** 24 pages
        when LookUp_Product.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A' AND JobPDF.Pages = 72 THEN 0.089 -- **** 36 pages
        ELSE NULL 
        END as [Pack Price]

        ,CASE

        when LookUp_Product.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A' AND JobPDF.Pages = 24 THEN 2 -- **** 12 pages
        when LookUp_Product.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A' AND JobPDF.Pages = 48 THEN 2 -- **** 24 pages
        when LookUp_Product.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A' AND JobPDF.Pages = 72 THEN 3 -- ****36 pages
        ELSE NULL
        END as [Pack Items]

        FROM Job WITH (NOLOCK)
        inner join LookUp_Product WITH (NOLOCK) on LookUp_Product.ProductID = job.ProductID

        inner join JobEvent WITH (NOLOCK)  on JobEvent.JobID = job.JobID
        inner join JobDetail WITH (NOLOCK)  on JobDetail.JobID = job.JobID
        inner join Orders WITH (NOLOCK)  on Orders.OrderId = JobDetail.OrderID
        inner join JobPDF WITH (NOLOCK)  on JobPDF.JobID = job.JobID
        where 1=1

        AND LookUp_Product.ClientID = 'AC7EDBCD-39DF-45CE-8D96-A26EB17D1E2D' 
        AND Job.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A'
        AND JobDetail.CurrentEventID = 999999
        AND JobEvent.EventID = 999999
        AND JobEvent.DateDone >= @dateFrom
        AND JobEvent.DateDone < @dateTo
        AND PackPrice is not null AND PackPrice <> 0.0000
        ) as Raw****dData

    GROUP BY Raw****Data.OrderID, [Product Name], [Pack Price], [Pack Items]) costPerOrder****

GROUP BY [Product Name], [Pack Price]
ORDER BY [Product Name]
Run Code Online (Sandbox Code Playgroud)

iam*_*ave 0

我认为您的数据比您发现的要多。您是否distinct整个 JobPDF.Pages专栏进行了测试,而不仅仅是“代表性”样本?

由于您的查询适用于某些日期范围,而不适用于其他日期范围,因此我建议采用不适用的范围并查看distinct返回的值,arithmetic overflow因为您的查询只能在除法之后返回超过 2 个字符。

下面的脚本说明了这一点,因为即使存在会导致失败的数据convert,如果查询首先没有返回该数据,那么一切似乎都可以正常运行:

declare @a table (a int);
insert into @a values(7155),(72);

-- This query will run
select CONVERT(nvarchar(2), a / 2)
from @a
where a < 100;

-- This query will not
select CONVERT(nvarchar(2), a / 2)
from @a;
Run Code Online (Sandbox Code Playgroud)

很简单,我不明白为什么会有除上述之外的任何问题。您能否运行以下命令并将输出添加到您的问题中?如果日期与产生错误的范围不相关,请将这些日期替换为以下内容:

select distinct JobPDF.Pages

FROM Job WITH (NOLOCK)
inner join LookUp_Product WITH (NOLOCK) on LookUp_Product.ProductID = job.ProductID

inner join JobEvent WITH (NOLOCK)  on JobEvent.JobID = job.JobID
inner join JobDetail WITH (NOLOCK)  on JobDetail.JobID = job.JobID
inner join Orders WITH (NOLOCK)  on Orders.OrderId = JobDetail.OrderID
inner join JobPDF WITH (NOLOCK)  on JobPDF.JobID = job.JobID
where 1=1

AND LookUp_Product.ClientID = 'AC7EDBCD-39DF-45CE-8D96-A26EB17D1E2D' 
AND Job.ProductID = 'AA5DF53B-4B58-4298-AFA3-EE856610689A'
AND JobDetail.CurrentEventID = 999999
AND JobEvent.EventID = 999999
AND JobEvent.DateDone >= '20161014'
AND JobEvent.DateDone < '20161025'
AND PackPrice is not null AND PackPrice <> 0.0000
Run Code Online (Sandbox Code Playgroud)