我修改了一个存储过程,我发现发送了一个值列表作为参数是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值不会,因为它后面没有逗号。
答案 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 |
+------------+------+
拆分字符串参考:
string_split()
in SQL Server 2016 : Follow-Up #1 - Aaron Bertrand <小时/>
由于这是用于报告,而您正在处理可能填充或不填充参数的内容,您可能会发现这些文章也很有用:
Catch-all查询参考: