Как передать массив значений с плавающей запятой в хранимую процедуру SQL Server?

#sql-server #sql-server-2005 #stored-procedures

#sql-сервер #sql-server-2005 #хранимые процедуры

Вопрос:

Мне нужно записать массив из 36 плавающих значений в базу данных SQL Server 2005. Существует ли рекомендуемый ответ, который объясняет, как это сделать?

Я не могу записать его в виде строки, потому что нам может потребоваться запрашивать отдельные значения по миллионам строк, и я не хочу разбирать каждую строку, чтобы прочитать ее значение.

Я также хотел бы избежать передачи 36 параметров в хранимую процедуру.

Итак, что рекомендует обычная мудрость StackOverflow?

Комментарии:

1. Обновитесь до SQL Server 2008 и используйте табличные параметры

Ответ №1:

В 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, поэтому мой синтаксис может быть немного неточным, но в основном он должен быть правильным.

Ответ №2:

В 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. Я как раз собирался опубликовать тот же ответ 🙂

Ответ №3:

Если бы это было 360 или 3600, я бы сказал XML или строку, но 36, вероятно, все еще достаточно мало, чтобы учитывать параметры.

Основная причина, по которой я говорю это, заключается в том, что когда вы переходите к тексту вместо строго типизированных параметров, вам приходится беспокоиться о последовательном форматировании. Форматирование чисел может быть сложным, поскольку в некоторых странах для разделителей тысяч используются запятые, а в других — десятичные разделители. Если ваш код клиентского доступа выполняется с другими региональными настройками, чем ожидалось от хранимой процедуры, вы можете обнаружить, что это приводит к сбою вашего приложения.

Ответ №4:

Я бы рекомендовал передать значения float в качестве параметра XML, но сохранить его в базе данных в 36 отдельных столбцах. (Я предполагаю здесь, что значения float отличаются по смыслу друг от друга и что вы захотите извлечь их по отдельности.)

Как вы сказали, вы не хотите разархивировать каждую строку для чтения ее значения, поэтому вам понадобится 36 столбцов. (Это тоже хорошая практика). Но вы можете передать значения с плавающей точкой в виде фрагмента XML, который вы можете разобрать различными способами, чтобы получить отдельные значения.

Комментарии:

1. Почему 36 одинаковых столбцов являются хорошей практикой? Звучит как кандидат на нормализацию. Я бы выбрал отдельную таблицу со столбцом index и value.

2. Обработка XML в SQL Server может быть очень ресурсоемкой. Обычно этого лучше избегать, если только вам не нужно его использовать.

Ответ №5:

Используйте это для передачи массива с помощью «create type table». простой пример для пользователя

 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