如何将一个浮点数组传递给SQL Server存储过程?

问题描述:

我需要将一个由36个浮点数组成的数组写入SQL Server 2005数据库。是否有最佳实践答案解释如何做到这一点?如何将一个浮点数组传递给SQL Server存储过程?

我不能把它写成字符串,因为我们可能需要查询数百万行的单个值,而且我不想为了读取它的值而去解构每一行。

我也想避免将36个参数传递给存储过程。

那么,*的传统智慧推荐什么?

+1

升级到SQL Server 2008,并使用[表值参数(http://msdn.microsoft.com/en-us/library/bb675163.aspx) – 2011-05-10 20:28:56

在SQL Server 2008中,也有因为这个原因表值参数。然而,在2005年,你只有选择是(1)字符串加入/拆分或(2)xml。

我想通过传递XML,然后插入到表变量。这里有一个例子:

declare @floatsXml nvarchar(max); 
set @floatsXml = '<nums><num val="2.123" /><num val="2.123" /></nums>'; 

declare @floats table (value float); 

insert into @floats 
select tbl.c.value('@val', 'float') 
from @floatsXml.nodes('/nums/num') as tbl(c); 

select * 
from @floats; 

我没有当前的SQL Server安装,所以我的语法可能稍有偏差,但它应该是基本上是正确的。

我建议将浮点数作为XML参数传递,但将其存储在数据库中的36个单独列中。 (我假设这里的花车彼此的意义是不同的,并且你会想单独将它们拉出来。)

正如你所说的,你不需要去构造每一行阅读它的价值,所以你需要36列。 (这也是很好的做法)。但是您可以将浮点数作为XML片段传递,您可以通过各种方式分离浮点数以获取各个值。

+1

如何为36列,其都是一样的好习惯吗?听起来像正常化的候选人。我会去索引和价值列单独的表。 – 2011-05-10 19:00:17

+0

在SQL Server中,XML处理可能非常耗费CPU资源。除非你绝对必须使用它,否则通常最好避免。 – 2011-05-10 19:04:22

对于SQL Server 2008,可以使用表值参数。由于这是SQL 2005,因此我使用逗号分隔的列表,然后使用转换为相应数据类型并返回表的分割函数。

这是分割功能我用:

IF OBJECT_ID('dbo.Nums') IS NOT NULL 
    DROP TABLE dbo.Nums ; 
GO 

CREATE TABLE [dbo].[Nums] 
    (
    [n] int NOT NULL, 
    PRIMARY KEY CLUSTERED ([n] ASC) 
    WITH (PAD_INDEX = OFF, FILLFACTOR = 100, IGNORE_DUP_KEY = OFF, 
      STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, 
      ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) 
ON 
    [PRIMARY] ; 
GO 

DECLARE @max AS INT, 
    @rc AS INT ; 
SET @max = 1000000 ; 
SET @rc = 1 ; 

INSERT INTO dbo.Nums (n) 
VALUES (1) ; 
WHILE @rc * 2 <= @max 
    BEGIN 
    INSERT INTO dbo.Nums (n) 
      SELECT n + @rc 
      FROM dbo.Nums ; 
    SET @rc = @rc * 2 ; 
    END 

INSERT INTO dbo.Nums (n) 
     SELECT n + @rc 
     FROM dbo.Nums 
     WHERE n + @rc <= @max ; 
GO 

CREATE FUNCTION [dbo].[fn_split] 
(@arr nvarchar(4000), @sep nchar(1)) 
RETURNS table 
AS 
RETURN 
    SELECT (n - 1) - LEN(REPLACE(LEFT(@arr, n-1), @sep, N'')) + 1 AS pos, 
       SUBSTRING(@arr, n, CHARINDEX(@sep, @arr + @sep, n) - n) AS element 
    FROM  dbo.Nums 
    WHERE  n <= LEN(@arr) + 1 
       AND SUBSTRING(@sep + @arr, n, 1) = @sep; 
GO 
+1

我刚刚发布相同的答案:) – 2011-05-10 18:54:58

如果是360或3600,我会说XML或一个字符串,但36可能仍然足够小,以考虑参数。

我这样说的主要原因是因为当你转到文本而不是强类型参数时,你必须考虑一致的格式。数字格式化可以用一些国家的数千个分隔符和其他数字中的小数点分隔符使用逗号来挑剔。如果您的客户端访问代码运行的区域设置不同于存储过程预期的区域设置,则可能会发现它破坏了您的应用程序。

使用它可以使用“创建类型表”传递数组。简单的例子为用户

CREATE TYPE unit_list AS TABLE (
    ItemUnitId int, 
    Amount float, 
    IsPrimaryUnit bit 
); 

GO 
CREATE TYPE specification_list AS TABLE (
    ItemSpecificationMasterId int, 
    ItemSpecificationMasterValue varchar(255) 
); 

GO 
declare @units unit_list; 
insert into @units (ItemUnitId, Amount, IsPrimaryUnit) 
    values(12,10.50, false), 120,100.50, false), (1200,500.50, true); 

declare @spec specification_list; 
    insert into @spec (ItemSpecificationMasterId,temSpecificationMasterValue) 
    values (12,'test'), (124,'testing value'); 

exec sp_add_item "mytests", false, @units, @spec 


//Procedure definition 
CREATE PROCEDURE sp_add_item 
( 
    @Name nvarchar(50), 
    @IsProduct bit=false, 
    @UnitsArray unit_list READONLY, 
    @SpecificationsArray specification_list READONLY 
) 
AS 


BEGIN 
    SET NOCOUNT OFF  

    print @Name; 
    print @IsProduct;  
    select * from @UnitsArray; 
    select * from @SpecificationsArray; 
END