为什么此存储过程适用于一个查询但不适用于另一个查询?

时间:2017-04-28 14:38:52

标签: sql sql-server stored-procedures reporting-services

我修改了一个存储过程,我发现发送了一个值列表作为参数是SSRS。用户只需用逗号“2444,2445,2446,...”分隔一个接一个地输入值。使用我的一个查询,存储过程完全按预期工作,但是当我更改它使用的查询而不是存储过程的逻辑时它不再有效...似乎很奇怪,因为存储过程的逻辑无关查询本身。

这是工作存储过程

GO
/****** Object:  StoredProcedure [dbo].[MULTI_VALUED_USER_INPUT_PARAMETER]    Script Date: 4/28/2017 10:22:55 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*CREATING A STORED PROCEDURE, WHICH HAS ONE INPUT PARAMETER*/
ALTER PROCEDURE [dbo].[MULTI_VALUED_USER_INPUT_PARAMETER](@DIESECTION VARCHAR(MAX))
AS
BEGIN
  /*CHECKING IF TABLE EXISTS IN THE DATABASE*/
  IF OBJECT_ID('TEMP', 'U') IS NOT NULL 
    /*IF TABLE EXISTS THEN DROPPING AND RECREATING TABLE*/
    DROP TABLE TEMP

  CREATE TABLE TEMP (DIESECTION VARCHAR(MAX))

  /*INSERTING EACH COMMA SEPERATED VALUE INTO TEMP TABLE*/
  WHILE CHARINDEX(',',@DIESECTION)<>0
  BEGIN
    INSERT INTO TEMP VALUES((SELECT LEFT(@DIESECTION, CHARINDEX(',',@DIESECTION)-1)))
    SET @DIESECTION=(SELECT RIGHT(@DIESECTION,LEN(@DIESECTION)-CHARINDEX(',',@DIESECTION)))
  END

  /*MODIFY QUERY TO FIT YOUR NEEDS!*/
  SELECT DISTINCT TOP 100000 p.id AS DIE_SECTION,SUM(r.CALC_QTY) AS GROSS_KG, COUNT(WO.BASE_ID) AS NUMBER_OF_TIMES_ORDERED, MAX(WO.CREATE_DATE) AS RECENT_ORDER_DATE,
    CASE 
        WHEN ISNUMERIC(P.USER_3) = 1 
        THEN Convert(varchar(50), CONVERT(decimal(14,3), P.USER_3))
    END AS KG_M

  FROM [DAJCOR].[dbo].[WORK_ORDER] wo JOIN REQUIREMENT R ON R.WORKORDER_BASE_ID = wo.BASE_ID JOIN PART P ON P.ID = WO.DRAWING_ID  
  WHERE P.USER_3 IS NOT NULL 
  AND r.PART_ID = WO.DRAWING_ID 
  AND WO.BASE_ID <> WO.PART_ID
  AND P.ID IN(SELECT DIESECTION FROM TEMP)
  AND (WO.CREATE_DATE BETWEEN convert(datetime, '2009-01-01') AND GETDATE())
  GROUP BY P.ID, P.USER_3 ORDER BY COUNT(WO.BASE_ID)

  /*DROPPING THE TEMP TABLE*/
  DROP TABLE TEMP
END

第二个使用完全相同的存储过程和稍微复杂的查询。但是存储过程应该只影响WHERE子句的第一个参数。

GO

/****** Object:  StoredProcedure [dbo].[MULTI_VALUED_USER_INPUT_PARAMETER]    Script Date: 4/28/2017 9:49:02 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON

GO
/*CREATING A STORED PROCEDURE, WHICH HAS ONE INPUT PARAMETER*/
ALTER PROCEDURE [dbo].[MULTI_VALUED_USER_INPUT_PARAMETER_NET_KG](@DIESECTION VARCHAR(MAX))
AS
BEGIN

  /*CHECKING IF TABLE EXISTS IN THE DATABASE*/
  IF OBJECT_ID('TEMP', 'U') IS NOT NULL 
    /*IF TABLE EXISTS THEN DROPPING AND RECREATING TABLE*/
    DROP TABLE TEMP

  CREATE TABLE TEMP (DIESECTION VARCHAR(MAX))

  /*INSERTING EACH COMMA SEPERATED VALUE INTO TEMP TABLE*/
  WHILE CHARINDEX(',',@DIESECTION)<>0
  BEGIN
    INSERT INTO TEMP VALUES((SELECT LEFT(@DIESECTION, CHARINDEX(',',@DIESECTION)-1)))
    SET @DIESECTION=(SELECT RIGHT(@DIESECTION,LEN(@DIESECTION)-CHARINDEX(',',@DIESECTION)))
  END

  /*MODIFY QUERY TO FIT YOUR NEEDS!*/
 SELECT DISTINCT LT.WORKORDER_BASE_ID,WO.DRAWING_ID,P.WEIGHT AS SHIPPING_WEIGHT,
    CASE
    WHEN R.SUBORD_WO_SUB_ID >= 0
    THEN P.WEIGHT/R.QTY_PER
    ELSE P.WEIGHT
    END AS NET_WEIGHT
,R.PART_ID,LT.GOOD_QTY,
LT.GOOD_QTY * CASE
    WHEN R.SUBORD_WO_SUB_ID >= 0
    THEN P.WEIGHT/R.QTY_PER
    ELSE P.WEIGHT
    END AS NET_KG,SUM(IT.QTY) AS GROSS_KG,LT.TRANSACTION_ID AS LT_TRANS,IT.TRANSACTION_DATE AS IT_DATE,LT.TRANSACTION_DATE AS LT_DATE
,LT.EMPLOYEE_ID,LT.RESOURCE_ID,LT.HOURS_WORKED,(LT.GOOD_QTY * CASE
    WHEN R.SUBORD_WO_SUB_ID >= 0
    THEN P.WEIGHT/R.QTY_PER
    ELSE P.WEIGHT
    END/LT.HOURS_WORKED) AS NET_KG_HR
FROM LABOR_TICKET LT JOIN INVENTORY_TRANS IT ON IT.WORKORDER_BASE_ID = LT.WORKORDER_BASE_ID LEFT JOIN WORK_ORDER WO ON WO.BASE_ID = LT.WORKORDER_BASE_ID LEFT JOIN PART P ON P.ID = WO.PART_ID
    LEFT JOIN REQUIREMENT R ON R.WORKORDER_BASE_ID = LT.WORKORDER_BASE_ID  AND R.WORKORDER_SUB_ID = WO.SUB_ID
WHERE WO.DRAWING_ID IN (SELECT DIESECTION FROM TEMP) AND LT.GOOD_QTY > 0 AND (LT.TRANSACTION_DATE BETWEEN '04-01-2017' AND '04-10-2017') AND IT.WAREHOUSE_ID <> 'COSTCODE' AND IT.PART_ID = WO.DRAWING_ID
    AND P.WEIGHT IS NOT NULL AND LT.RESOURCE_ID LIKE 'EP%' AND (R.PART_ID IN ('25023', '25024', '25025', '25026', '25027', '25028') OR R.PART_ID IS NULL) AND R.QTY_PER <> 0
GROUP BY LT.WORKORDER_BASE_ID,WO.DRAWING_ID,P.WEIGHT, 
    CASE
    WHEN R.SUBORD_WO_SUB_ID >= 0
    THEN P.WEIGHT/R.QTY_PER
    ELSE P.WEIGHT
    END,R.PART_ID,LT.GOOD_QTY, LT.GOOD_QTY * CASE
    WHEN R.SUBORD_WO_SUB_ID >= 0
    THEN P.WEIGHT/R.QTY_PER
    ELSE P.WEIGHT
    END,LT.TRANSACTION_DATE,IT.TRANSACTION_DATE,LT.TRANSACTION_ID,LT.EMPLOYEE_ID,LT.RESOURCE_ID,LT.HOURS_WORKED
ORDER BY WO.DRAWING_ID,LT.WORKORDER_BASE_ID

  /*DROPPING THE TEMP TABLE*/
  DROP TABLE TEMP
END

问题在于,当我尝试输入值例如“23703”时,没有任何内容出现,但如果我在末尾添加逗号“23703”,那么它可以工作。第一个示例正常用于第一个查询,但只有第二个示例适用于第二个查询。另一个例子是如果我有多个值“1,2,3”只会出现1和2,因为它们后跟逗号,但3值不会,因为它后面没有逗号。

1 个答案:

答案 0 :(得分:2)

代码中的问题很可能与此循环有关:WHILE CHARINDEX(',',@DIESECTION)<>0。由于没有逗号,它不会做任何事情。

然而,拆分分隔字符串的真正问题可以通过其他一些更快的解决方案来解决。

一个例子是Jeff Moden的表值函数:

create function [dbo].[delimitedsplit8K] (
      @pstring varchar(8000)
    , @pdelimiter char(1)
  )
returns table with schemabinding as
 return
  with e1(N) as (
    select 1 union all select 1 union all select 1 union all 
    select 1 union all select 1 union all select 1 union all 
    select 1 union all select 1 union all select 1 union all select 1
  )
  , e2(N) as (select 1 from e1 a, e1 b)
  , e4(N) as (select 1 from e2 a, e2 b)
  , ctetally(N) as (
    select top (isnull(datalength(@pstring),0)) 
      row_number() over (order by (select null)) from e4
  )
  , ctestart(N1) as (
    select 1 union all
    select t.N+1 from ctetally t where substring(@pstring,t.N,1) = @pdelimiter
  )
  , ctelen(N1,L1) as (
    select s.N1,
      isnull(nullif(charindex(@pdelimiter,@pstring,s.N1),0)-s.N1,8000)
    from ctestart s
  )
 select itemnumber = row_number() over(order by l.N1)
      , item       = substring(@pstring, l.N1, l.L1)
   from ctelen l
;
go

可以这样使用:

declare @diesection varchar(8000) = '1,2,3';
select s.ItemNumber, s.Item
from [dbo].[delimitedsplit8K](@diesection,',') s

rextester演示:http://rextester.com/XJSQUS89642

返回:

+------------+------+
| ItemNumber | Item |
+------------+------+
|          1 |    1 |
|          2 |    2 |
|          3 |    3 |
+------------+------+

拆分字符串参考:

 

<小时/>

由于这是用于报告,而您正在处理可能填充或不填充参数的内容,您可能会发现这些文章也很有用:

Catch-all查询参考: