2016-11-28 73 views
0

我需要将一个列表传递给我的SQL Server存储过程。我已生成的列表中,这是一个逗号分隔的使用数字的列表:我想将一个评估列表传递给我的SQL Server存储过程

<cfquery name="House" datasource="#application.datasource#"> 
    SELECT cGLsubaccount 
    FROM HOUSE 
    WHERE Right(cGLsubaccount,3) IN 
     (
      <cfloop index="i" list="#consulsub#"> 
       <cfoutput>#right(Trim(i) , 3)#,</cfoutput> 
      </cfloop> 
      00000000 
     ) 
</cfquery> 

<cfset GLsubacct = Valuelist(House.cGLsubaccount,",")> 

现在,我将它传递到使用cfprocparam与cfsqltype为varchar(1000)的存储过程。 (我在google上读到这是将列表传递给存储过程的方式)。

<cfprocparam type="IN" value="#GLsubacct#" DBVARNAME="@GLsubacct" cfsqltype="cf_sql_varchar"> 

在存储过程中,我这样做:

ALTER PROCEDURE [rw].[sp_EFT_NoticeXLS2] (
     @Scope varchar(50) 
     , @AcctPeriod char(6) 
     , @CompanyID nchar(10) 
     , @GLsubacct varchar(1000) = NULL 
) 
AS...... 

,并在存储过程中的SQL语句如下:

CREATE TABLE #Houses (
    iHouse_ID  int, 
    cName   varchar(50), 
    cNumber   varchar(10), 
    cPhoneNumber1 varchar(25), 
    cAddressLine1 varchar(50), 
    cCity   varchar(30), 
    cStateCode  varchar(2), 
    cZipCode  varchar(10), 
    iUnitsAvailable int, 
    iRegOpsNumber int, 
    cOpsName  varchar(50), 
    iRegionID  int, 
    cRegionName  varchar(50) 
) 

INSERT INTO #Houses (
    iHouse_ID, 
    cName, 
    cNumber, 
    cPhoneNumber1, 
    cAddressLine1, 
    cCity, 
    CStateCode, 
    cZipCode, 
    iUnitsAvailable, 
    iRegOpsNumber, 
    cOpsName, 
    iRegionID, 
    cRegionName) 
SELECT 
    h2.iHouse_ID, 
    h.cName, 
    h.cNumber, 
    h.cPhoneNumber1, 
    h.cAddressLine1, 
    h.cCity, 
    h.CStateCode, 
    h.cZipCode, 
    h.iUnitsAvailable, 
    r.RegOpsNumber, 
    r.opsname, 
    r.iRegion_ID, 
    r.regionname 
FROM rw.fn_GetScopeHouses (@Scope, @dtReport, NULL, NULL, 0) h2 
     JOIN House h on h.iHouse_ID = h2.iHouse_ID 
      AND h.cCompanyID = @CompanyID 
      AND (@GLsubacct IS NULL OR h.iHouse_ID IN ('+ @GLsubacct +')) 
JOIN rw.vw_Reg_Ops r on r.opsareaID = h.iOpsArea_ID 

的问题是,我得到一个错误。错误信息是...

Error Executing Database Query. 
[Macromedia][SQLServer JDBC Driver][SQLServer]Conversion failed when converting the varchar value '+ @GLsubacct +' to data type int. 

The error occurred in E:\inetpub\wwwroot\intranet\TIPS4\Admin\EFTprocesspullfile.cfm: line 46 

44 :   <cfprocparam type="IN" value="#CompanyID#" DBVARNAME="@CompanyID" cfsqltype="cf_sql_varchar"><!--- TPecku added variable to be passed to the stored Proc ---> 
45 :   <cfif CompanyID EQ 0000> 
46 :   <cfprocparam type="IN" value="#GLsubacct#" DBVARNAME="@GLsubacct" cfsqltype="cf_sql_varchar"> 
47 :   </cfif> 
48 : </cfstoredproc> 

错误在存储过程中,因为那是我的'+ @GLsubacct +'。 关于我在做什么的任何想法都是错误的? (对不起,很长一段时间,我想尽可能详细地描述我在做什么

+2

查看表值参数(TVP),这可能是您想要使用而不是传递字符串。 https://msdn.microsoft.com/en-us/library/bb510489.aspx – rjdevereux

+0

谢谢rjdevereux,我看着你的链接,但我仍然困惑于如何前进。 – Tetteh

+1

那么,你有几个选择。一种是使用字符串解析功能。以下是一些你可以做到的方法:https://sqlperformance.com/2012/07/t-sql-queries/split-strings。一种是将表传递给存储过程。要做到这一点,你需要创建一个类型(如上面的链接),然后使用它作为你的过程的'READONLY'参数。无论您选择什么选项,您都希望更改您的过程以加入表格(分割值表或您使用的tvp)。 – ZLK

回答

0

为了使这个工作接近你现有的代码,你必须创建查询字符串(替换插入语句)并执行它

我创建了一些虚拟/测试变量来查看查询是如何使用PRINT语句查找的。 “DECLARE @execQuery varchar(MAX)”到最后替换你的插入语句。

像这样的逻辑应该用你可以使用的数据填充临时表#Houses。

-- test variables 
DECLARE @Scope varchar(50), @AcctPeriod char(6), @CompanyID nchar(10), @GLsubacct varchar(1000), @dtReport VARCHAR(20); 
SET @Scope = 'scope'; 
SET @AcctPeriod = 'fall'; 
SET @CompanyID = N'coID'; 
SET @dtReport = 'dtRpt' 
SET @GLsubacct = '123,234,345,456' 

-- copy code below this line 
DECLARE @execQuery varchar(MAX) 

SET @execQuery = 'insert into #Houses (
iHouse_ID, 
cName, 
cNumber, 
cPhoneNumber1, 
cAddressLine1, 
cCity, 
CStateCode, 
cZipCode, 
iUnitsAvailable, 
iRegOpsNumber, 
cOpsName, 
iRegionID, 
cRegionName 
) 
select 
h2.iHouse_ID, 
h.cName, 
h.cNumber, 
h.cPhoneNumber1, 
h.cAddressLine1, 
h.cCity, 
h.CStateCode, 
h.cZipCode, 
h.iUnitsAvailable, 
r.RegOpsNumber, 
r.opsname, 
r.iRegion_ID, 
r.regionname 
FROM rw.fn_GetScopeHouses ('''+ @Scope +''', '''+ @dtReport +''', NULL, NULL, 0) h2 
JOIN House h on h.iHouse_ID = h2.iHouse_ID 
AND h.cCompanyID = N'''+ @CompanyID +'''' 
IF (@GLsubacct IS NOT NULL) 
BEGIN 
    SET @execQuery = @execQuery + ' AND (h.iHouse_ID IN ('+ @GLsubacct +'))' 
END 
SET @execQuery = @execQuery + 'JOIN rw.vw_Reg_Ops r on r.opsareaID = h.iOpsArea_ID' 

--PRINT @execQuery 

EXEC @execQuery 
+0

如果可能,请勿使用动态sql。除了其他问题,它很容易被SQL注入。使用JOIN的udf/table驱动方法会更好。 – Leigh

+0

与cfprocparam标签cfstoredproc调用不会像cfqueryparam一样工作吗? –

+0

如果它是一个常规的SQL语句,执行*没有* EXEC是。但是,上面构建了一个字面的sql字符串(没有任何绑定变量)并将其传递给EXEC。 (使用PreserveSingleQuotes的SQL等效项的排序)。所以@variables中的任何恶意sql都会被执行。如果您绝对必须使用动态sql,请使用[sp_executeSQL](https://msdn.microsoft.com/zh-cn/library/ms188001.aspx)而不是EXEC。尽管它不适用于所有情况(例如,使用IN子句)。在这种情况下,表格驱动的方法是更好的IMO。 – Leigh

0

我终于想出了如何使它工作。在我将这个列表传递给存储过程变量后,我无法直接在我的sql语句中使用这个变量,它不起作用,所以我做的是迭代变量的内容并将它们存储在一个临时表中。然后我在我的SQL语句中使用了临时表的内容。如果你看上面,你会看到我想要做的事情,但没有成功。我最终做的是......

declare @oneNumber int 
declare @POS int 
if @GLsubacct <> '' 
begin 
--Step through the comma delimted list of numbers and plug each one into a temp table 
create table #HouseList (HouseID int) 
select @POS = patindex('%,%',@GLsubacct) 
while @POS > 0 
begin 
select @oneNumber = cast(left(@GLsubacct,@POS - 1) as int) 
insert into #HouseList (HouseID) values (@oneNumber) 
select @GLsubacct = right(@GLsubacct,len(@GLsubacct) - @POS) 
select @POS = patindex('%,%',@GLsubacct) 
end 
--do the last one which doesn't have any comma 
select @oneNumber = cast(@GLsubacct as int) 
insert into #HouseList (HouseID) values (@oneNumber) 
end 

-- Create #House table 
CREATE TABLE #Houses (
iHouse_ID  int, 
cName   varchar(50), 
cNumber   varchar(10), 
cPhoneNumber1 varchar(25), 
cAddressLine1 varchar(50), 
cCity   varchar(30), 
cStateCode  varchar(2), 
cZipCode  varchar(10), 
iUnitsAvailable int, 
iRegOpsNumber int, 
cOpsName  varchar(50), 
iRegionID  int, 
cRegionName  varchar(50)) 

insert into #Houses (
iHouse_ID, 
cName, 
cNumber, 
cPhoneNumber1, 
cAddressLine1, 
cCity, 
CStateCode, 
cZipCode, 
iUnitsAvailable, 
iRegOpsNumber, 
cOpsName, 
iRegionID, 
cRegionName) 
select 
h2.iHouse_ID, 
h.cName, 
h.cNumber, 
h.cPhoneNumber1, 
h.cAddressLine1, 
h.cCity, 
h.CStateCode, 
h.cZipCode, 
h.iUnitsAvailable, 
r.RegOpsNumber, 
r.opsname, 
r.iRegion_ID, 
r.regionname 
from rw.fn_GetScopeHouses (@Scope, @dtReport, NULL, NULL, 0) h2 
JOIN House h on h.iHouse_ID = h2.iHouse_ID 
AND h.cGLsubaccount IN (select Houseid from #HouseList) 
JOIN rw.vw_Reg_Ops r on r.opsareaID = h.iOpsArea_ID 

它工作完美!

+0

您应该将“分割”逻辑放入UDF表中。那么你可以在任何列表中使用它,从任何过程 - 不只是这一个:)参见[链接ZLK张贴在评论](http://stackoverflow.com/questions/40852635/i-want-to-pass- a-valuelist-to-my-sql-server-stored-procedure#comment68926713_40852635)。 – Leigh

相关问题