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

标签 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 值不会出现,因为它后面没有逗号。

最佳答案

代码中的问题很可能与此循环有关: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 |
+------------+------+

分割字符串引用:


由于这是为了报告,并且您正在执行可能填充也可能不填充参数的操作,因此您可能会发现这些文章也很有帮助:

综合查询引用:

关于sql - 为什么此存储过程适用于一个查询而不适用于另一查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43682832/

相关文章:

java - 如何用Java创建MySQL表?

mysql - 如何在 BigQuery SQL 中将一组用户分组为 10 人组?

c# - 是否可以从 ASP.net 中的 SQL/MySQL 数据库导入表单的按钮位置?

sql-server - Visual Studio 中的 Alter procedure 语句给出 'This statement is not recognized in this context message'

sql - Postgres 中的递归 SQL 查询

php - 组合两个查询时出现问题

sql-server - Sql Server中的大事务,有什么问题吗?

SQL 查询——如何找到最低的 2 个数字

sql - 一般来说,存储过程是否比现代 RDBMS 上的内联语句更有效?

java - 数据库 : map to another data model