sql存储过程数组参数
① 如何给存储过程,传一个数组参数
方法一 分割
例:通过sql Server存储过程传送数组参数删除多条记录
eg. ID 值为'1,2,3' 以下存储过程就是删除表中id号为1,2,3的记录:
CREATE PROCEDURE DeleteNews
@ID nvarchar(500)
as
DECLARE @PointerPrev int
DECLARE @PointerCurr int
DECLARE @TId int
Set @PointerPrev=1
while (@PointerPrev < LEN(@ID))
Begin
Set @PointerCurr=CharIndex(',',@ID,@PointerPrev)
if(@PointerCurr>0)
Begin
set @TId=cast(SUBSTRING(@ID,@PointerPrev,@PointerCurr-@PointerPrev) as int)
Delete from News whereID=@TID
SET @PointerPrev = @PointerCurr+1
End
else
Break
End
--删除最后一个,因为最后一个后面没有逗号,所以在循环中跳出,需另外再删除
set @TId=cast(SUBSTRING(@ID,@PointerPrev,LEN(@ID)-@PointerPrev+1) as int)
Delete from News whereID=@TID
GO
这个方法麻烦不?于是又有另外一种方法——临时表
方法二 Table对象
传3个参数,都是数组形式还有时间类型用存储过程更新
@Oid = 1,2,3,4
@Did = 111,222,333,444
@DateArr = '2007-1-1,2007-1-2,2007-1-3,2007-1-4'
CREATE proc Test999
@Oid nvarchar(1000)--ID1
,@Did nvarchar(1000)--ID2
,@DateArr nvarchar(1000)--日期
AS
DECLARE @id1s varchar(8000), @id2s varchar(8000), @dates varchar(8000)
set @id1s=@Oid
set @id2s=@Did
set @dates = @DateArr
-- 调用函数实现处理
SELECT @id1s=@id1s, @id2s=@id2s,@dates = @dates
UPDATE A SET terminate_time = B.dt
FROM [Table] A,(
SELECT
id1 = CONVERT(int, Desk_id.value),
id2 = CONVERT(int, room_id.value),
dt = CONVERT(datetime, terminate_time.value)
FROM dbo.f_splitstr(@id1s) Desk_id, dbo.f_splitstr(@id2s) room_id, dbo.f_splitstr(@dates) terminate_time
WHERE Desk_id.id = room_id.id
AND Desk_id.id = terminate_time.id
) B
WHERE A.Desk_id = B.ID1 AND A.room_id = B.ID2
GO这个还用到一个函数f_splitstr
CREATE FUNCTION dbo.f_splitstr(
@str varchar(8000)
)RETURNS @r TABLE(id int IDENTITY(1, 1), value varchar(5000))
AS
BEGIN
DECLARE @pos int
SET @pos = CHARINDEX(',', @str)
WHILE @pos > 0
BEGIN
INSERT @r(value) VALUES(LEFT(@str, @pos - 1))
SELECT
@str = STUFF(@str, 1, @pos, ''),
@pos = CHARINDEX(',', @str)
IF @str > ''
INSERT @r(value) VALUES(@str)
RETURN
这个方法更加可怕~~~辗转网络,找到了一个还不错的方法,用OPENXML,这个SQL2000就支持了。
方法三 xml
应该用SQL2000 OpenXML更简单,效率更高,代码更可读:
CREATE Procere [dbo].[ProctListUpdateSpecialList]
(
@ProctId_Array NVARCHAR(2000),
@MoleId INT
)
AS
delete from ProctListSpecial whereMoleId=@MoleId
-- If empty, return
IF (@ProctId_Array IS NULL OR LEN(LTRIM(RTRIM(@ProctId_Array))) = 0)
RETURN
DECLARE @idoc int
EXEC sp_xml_preparedocument @idoc OUTPUT, @ProctId_Array
Insert into ProctListSpecial (MoleId,ProctId)
Select
@MoleId,C.[ProctId]
FROM
OPENXML(@idoc, '/Procts/Proct', 3)
with (ProctId int ) as C
where
C.[ProctId] is not null
EXEC sp_xml_removedocument @idoc
哇,看起来还是很复杂的说。有木有更好的办法呢?
既然是OPENXML,为啥不用XML呢?于是查到,SQL2005以上都支持XML。Good,找到一片天了。
利用SQL2005的XML/XQuery功能,可以很方便的解决传数组参数的问题。
declare @xml xml
set @xml = '<?xml version="1.0"?>
<ArrayOfInt>
<int>1</int>
<int>2</int>
<int>3</int>
</ArrayOfInt>'
select N.value( '(text())[1]','int' ) RoomId from @xml.nodes('/ArrayOfInt/int') V(N)
结果就是
注:上面的数据类型为XML
这样就可以给存储过程传一个集合了,一般是数组,比如主键的集合。然后可用通过主键集合来查询记录。
客户端可用使用序列化,把list转化成xml。不过在序列化过程中,遇到了一些小麻烦。
1. .net默认是utf-16,SQL只认识utf-8
2. 出现很讨厌的xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
可以用我这个类
public static class SerializeHelper
{
private static readonly XmlSerializerNamespaces Namespaces = new XmlSerializerNamespaces();
static SerializeHelper()
{
//去掉 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
Namespaces.Add(string.Empty, string.Empty);
}
public static string SerializeXml<T>(T obj)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (MemoryStream stream = new MemoryStream())
{
serializer.Serialize(stream, obj, Namespaces);
return Encoding.UTF8.GetString(stream.ToArray());
}
}
public static T DeserializeXml<T>(string obj)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (StringReader reader = new StringReader(obj))
{
return (T)serializer.Deserialize(reader);
}
}
}
SQL与XML,XQuery结合起来,功能会很强大的。
② sql存储过程处理数组参数
declare@strvarchar(500)
declare@insertvarchar(8000)
select@insert='insertintoyouTablevalues'
select@str='str1,1,1,1,1|str2,2,2,2,2|str3,3,3,3,5|str4,4,4,45,4'
select@str=@insert+'('''+@str+''')'
select@str=REPLACE(@str,',',''',''')
select@str=REPLACE(@str,'|',''')'+CHAR(13)+@insert+'(''')
print@str
--exec(@str)动态执行下生成的语句就好了
--print结果如下:
insertintoyouTablevalues('str1','1','1','1','1')
insertintoyouTablevalues('str2','2','2','2','2')
insertintoyouTablevalues('str3','3','3','3','5')
insertintoyouTablevalues('str4','4','4','45','4')
③ 如何给SQLSERVER存储过程传递数组参数
数组不能传递,变通的解决办法是有的
思路如下:
1、将数组转换为字符串格式(例如:a,b,c,d)
2、在数据库内创建字符串分割为行的表值函数
3、若是需要将一个二维数组传递的话,需要将每列数据都格式化为1的方式,然后再用2的方式转换为行,再将转换后的数据组合为一个表
4、你就可以直接进行插入、编辑、删除或查询操作了。
④ sqlserver2008存储过程的参数有数组类型吗
您好,没有数组类型的.所有的参数类型都是systypes表里面的.
⑤ 【SQL】存储过程中如何定义数组
存储过程里定义不了数组。如果是sqlserver,那么你可以用表变量,游标来实现你的功能。
如果是sqlserver2005以上的版本,可以做clr存储过程,那里面是可以用数组的。
⑥ 【SQL】存储过程中如何定义数组
存储过程
里定义不了数组。如果是
sqlserver
,那么你可以用表变量,游标来实现你的功能。
如果是
sqlserver2005
以上的版本,可以做clr存储过程,那里面是可以用数组的。
⑦ sql存储过程数组参数超难问题
--方法一,用字符串替换和拼接,构造成insert
into
表
select
的样子,然后执行
--方法二,用字符串拆分
declare
@a
varchar(800)='str1,0,0,0|str2,0,0,0|str3,0,0,0'
set
@a='insert
into
t
select
'''+@a
set
@a=replace(replace(@a,'|','''
union
all
select
'''),',',''',''')+''''
exec(@a)
/*
insert
into
t
select
'str1','0','0','0'
union
all
select
'str2','0','0','0'
union
all
select
'str3','0','0','0'
*/
⑧ 如何给存储过程,传一个数组参数
这个是我自己写的一个例子,你看看:在命令窗口执行以下语句,创建自定义类型NESTEDARRAY。;在存储过程中使用自定义类型NESTEDARRAY。PROCEDUREGET_ARR_RESULT(INPUTARRAYINNESTEDARRAY,AROUTNESTEDARRAY)ISBEGINAR:=NESTEDARRAY();FORIIN1..INPUTARRAY.COUNTLOOPAR.EXTEND;AR(I):=I||INPUTARRAY(I);ENDLOOP;ENDGET_ARR_RESULT;java代码:importjava.sql.Connection;importjava.sql.SQLException;importoracle.jdbc.OracleCallableStatement;importoracle.jdbc.OracleTypes;importoracle.sql.ARRAY;importoracle.sql.ArrayDescriptor;importoracle.sql.Datum;/***Java获取Oracle存储过程返回自定义类型*@authorluckystar**/{/***@paramargs*/publicstaticvoidmain(String[]args){Connectioncon=null;OracleCallableStatementocs=null;Stringsql="{calltest.GET_ARR_RESULT(?,?)}";try{con=DBUtil.dbUtil.getConnection();ocs=(OracleCallableStatement)con.prepareCall(sql);String[]params={“10001”,”10003”};ArrayDescriptorarrayDesc=ArrayDescriptor.createDescriptor("NESTEDARRAY",con);ARRAYinputArray=newARRAY(arrayDesc,con,params);ocs.setARRAY(1,inputArray);ocs.registerOutParameter(2,OracleTypes.ARRAY,"NESTEDARRAY");ocs.execute();ARRAYarray=ocs.getARRAY(2);Datum[]datum=array.getOracleArray();for(inti=0;i
⑨ sql 存储过程 传入两组数组参数
declare@nnvarchar(500)
declare@mnvarchar(500)
set@n='1,2,3,4,5'
set@m='a,b,c,d,e'
createtable#tb(nVARCHAR(500),mVARCHAR(500))
while(1=1)
begin
if(Charindex(',',@n)=0andCharindex(',',@m)=0)
begin
insertinto#tbvalues(@n,@m)
break
end
insertinto#tbvalues(Substring(@n,1,Charindex(',',@n)-1),Substring(@m,1,Charindex(',',@m)-1))
set@n=Right(@n,Len(@n)-Charindex(',',@n))
set@m=Right(@m,Len(@m)-Charindex(',',@m))
end
select*from#tb
droptable#tb
ps:要做好校验!