Вопрос : Существует ли в SQL Server тип переменной array (массив)?
Ответ: В стандарте ANSI SQL 92 нет массивов, и в SQL Server их тоже нет.
А для чего в SQL могут понадобиться массивы? Вот основные поводы:
1. Передать заполненный массив в хранимую процедуру.
2. Работать с массивами так, как это принято в других языках программирования.
3. Хранить массивы в строках таблицы.
Рассмотрим разрешение всех этих проблем по очереди.
1. Передать заполненный массив в хранимую процедуру. Проблему передачи списка значений в хранимую процедуру каждый решает как может. Рассмотрим несколько вариантов ее решения. Каждый из этих вариантов имеет свою нишу для применения.
Вариант 1. В процедуру можно передать одну или несколько переменных типа varchar, содержащие значения, разделенные запятой, или имеющие равную длину для каждого значения. А затем занести эти значения во временную таблицу или использовать их как есть.
1) Перенос во временную таблицу:
use tempdb
GO
if OBJECT_ID('Test1') IS NOT NULL drop procedure Test1
GO
CREATE PROCEDURE Test1 @Param varchar(200)
AS
BEGIN
select *
from sysobjects
where type in (
-- перевод строки в таблицу параметров
-- в MSSQL 2000 удобнее создать пользовательскую функцию
select SUBSTRING(@Param, a.i,
CASE WHEN CHARINDEX(',', @Param, a.i)>0
THEN CHARINDEX(',', @Param, a.i)-(a.i)
ELSE 8000
END) AS Value
from (
-- таблица значений 1,2,3.... (лучше перевести в специальную таблицу)
select count(*) as i
from master..sysobjects a, master..sysobjects b
where a.id<b.id
group by a.id
) a
where (a.i=1 or SUBSTRING(@Param, a.i-1, 1)=',')
and a.i<=LEN(@Param)
)
END
GO
-- вызов процедуры
exec Test1 'S,V,P'
GO
2) Использование строки "как есть":
use tempdb
GO
if OBJECT_ID('Test1') IS NOT NULL drop procedure Test1
GO
CREATE PROCEDURE Test1 @Param varchar(200)
AS
BEGIN
select *
from sysobjects
where CHARINDEX(','+rtrim(type)+',', ','+@Param+',')>0
END
GO
-- вызов процедуры
exec Test1 'S,V,P'
GO
Вариант 2. Более широко используемым вариантом является передача в хранимую процедуру имени ранее заполненной временной таблицы.
use tempdb
GO
if OBJECT_ID('Test1') IS NOT NULL drop procedure Test1
GO
CREATE PROCEDURE Test1 @Param varchar(200)
AS
BEGIN
SET NOCOUNT ON
create table #Temp (Value varchar(2))
insert #Temp
exec ( 'select * from ' + @Param )
SET NOCOUNT OFF
select *
from sysobjects
where type in ( select Value from #Temp )
END
GO
-- вызов процедуры
create table #MyList (Item varchar(2))
insert #MyList values ('S')
insert #MyList values ('V')
insert #MyList values ('P')
GO
exec Test1 '#MyList'
GO
drop table #MyList
GO
2. Работать с массивами так, как это принято в других языках программирования. Такое желание возникает у новичков в SQL. Таблица - это тот же массив, только представленный в "плоском" виде. Вот так будет выглядеть работа с таблицей как с трехмерным массивом:
use tempdb
GO
CREATE TABLE Array1 (i int, j int, k int, Value decimal)
GO
DECLARE @i int, @j int, @k int
SET @i=0
WHILE @i<10
BEGIN
SET @j=0
WHILE @j<10
BEGIN
SET @k=0
WHILE @k<10
BEGIN
INSERT Array1 VALUES(@i, @j, @k, RAND()*10000)
SET @k=@k+1
END
SET @j=@j+1
END
SET @i=@i+1
END
GO
SELECT * FROM Array1
GO
DROP TABLE Array1
GO
Писать такой код нет никакой надобности. Средствами языка SQL можно делать гораздо более сложные операции над таблицами. И все эти операции производятся с потрясающей быстротой, потому что это является основой SQL.
Надеюсь, Вы поняли, что я хотел сказать. Если у Вас появилась потребность в массивах только для того, чтобы поработать с ними как в Pascal или C, то это означает, что Вы не прониклись духом реляционных баз данных.
3. Хранить массивы в строках таблицы.
1) У Вас появилась необходимость хранить для каждой записи массив одинаковой структуры.
Ничего кроме денормализации базы данных, усложнения кода и замедления обработки данных это не даст. Для таких массивов создается отдельная таблица с добавлением уникального кода строки главной таблицы.
Например, не надо хранить в таблице клиентов движение по ним. Движение выносится в отдельную таблицу.
2) У Вас появилась необходимость хранить для каждой записи массивы разной структуры.
Это равносильно хранению в таблице объектов. Для хранения таких массивов используйте возможности XML или пишите свой "парсер". Хранить их придется в виде varchar, text, varbinary или image в зависимости от предполагаемой величины массивов.
Надеюсь, Вы нашли эту информацию полезной. Вопросы, предложения и пожелания шлите на адрес sql@likor.ru С уважением, Сергей Кошкин.
Архив рассылки смотрите на сайте Рассылки http://sql.softmatics.ru/