我们目前正在建立一个门户网站,以便能够查看我们组织的SQL报告。目前,门户网站使用PHP脚本和MS SQLSRV驱动程序对我们众多的SQL数据库进行查询。本质上,门户通过调用我们创建的存储过程来返回所请求的数据。然后,网站解析数据并向用户显示他们请求的信息。这个过程适用于我们现有的所有报告,除了我目前正在努力工作的报告。
有问题的存储过程/报告使用用户定义的表类型最终在脚本末尾创建WHERE IN
类型子句,以便根据提供的帐号进行选择。
我很痛苦地意识到SQLSRV驱动程序不支持通过用户定义的表类型发送,因此我有一个工作函数,它接受CSV格式的输入字符串并返回包含数据的表。这部分工作,我可以传递一串帐号,它成功地将它们解析为单独的行。如果我远程调用它,我会得到预期的结果。如果我提供4个帐号,我的表格应该填满4行。
输入字符串的示例是:
A00000000001,A00000000002,A00000000003,A00000000004
如果我从MS SQL Server Management Studio手动运行它并为其提供相同的字符串,则此脚本/存储过程可以正常工作;给我一个按预期提供的每个帐号的行。我也可以从Mgmt Studio手动运行脚本,并将字符串硬编码到脚本中,我得到相同的结果,表明脚本可以正常工作。但问题是,当远程执行存储过程时,只返回最后一行,并且它始终是字符串/转换表中的最后一个帐号。更糟糕的是,如果我运行SQL Trace Profiler,我可以看到正在发出的请求,我可以看到它将我的帐号插入到我的表类型中,并且对于发送的每个帐户都这样做,但是当Trace Profiler显示实际存储过程,只返回一行...
我原本以为这个问题出现在我的PHP脚本中,但是看到跟踪探查器只捕获了一行,这让我觉得远程运行时存储过程会发生一些事情......
这是SQL的修剪版本,没有保存空间的所有字段:
USE [Livendb]
GO
/****** Object: StoredProcedure [dbo].[cejnsqip] Script Date: 05/25/2015 12:24:19 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[cejnsqip] @acctList varchar(MAX)
AS
--Split our comma separated list that was sent over so we can convert it to an array
DECLARE @acctNumList acctNum_list_tbltype
INSERT INTO @acctNumList(AccountNumber) SELECT Data FROM [dbo].[cejSplitCommaList](@acctList, ',') -- Call to function to split csv into table
SELECT
...
...
...
FROM AbstractData
WHERE AbstractData.AccountNumber IN(SELECT AccountNumber FROM @acctNumList)
答案 0 :(得分:-1)
本身不是答案,而是建议调查略有不同的路径......
当TVP不是一个选项(通常是由于驱动程序不支持它,如你的情况)时,我的回退是使用XML参数,然后使用XML函数来解析它。有时,这需要将XML参数作为字符串公开,然后将其CASTing为XML数据类型(同样,取决于驱动程序支持)。
这种方法具有以下好处:
- 如果您需要比简单的逗号分隔列表更复杂的内容(例如,如果您想要发送{Acct#,Checksum}对),则更容易扩展
- 在我的测试中,从XML(或XML片段)中提取有趣的东西,而不是使用自制的解析函数,从而减轻了CPU的负担。
- 能够使用模式"强类型" XML(或片段)
如果您的帐号#列表长度超过50个,那么您也可以考虑粉碎您用于传递列表的任何内容(无论是XML,还是如果您弄清楚,简单的字符串) list)到#temp表而不是表变量,键列上有索引。在某些情况下,这将有助于优化器选择更好的计划。