Often, when working with databases there is a need to pass a parameter with set of elements.
Function described here (TABLE-Value UDF) converts a string in the form "aaa;bbb;ccc" to tabular form.
Additionally could be removed empty items.
In case if list has non-unique items, the function returns the serial number for each items group (RANK).
- -- Drop Function if exists
- IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'dbo.tf_array2table'))
- DROP FUNCTION dbo.tf_array2table;
- GO
- /*=============================================
- Author:
- Yuri Abele
- Changes:
- 11.06.2013 - Yuri Abele - initial
- Description:
- Function to convert list of Values to Table
-
- Usage: Get all items
- SELECT item_index, item_value = IIF(item_value = '', '---', item_value), item_rank
- FROM dbo.tf_array2table(N';ddd;bbb;ccc;;;ccc;ddd;eee;', N';', 0);
- Usage: Get all non-empty items
- SELECT * FROM dbo.tf_array2table(N';ddd;bbb;ccc;;;ccc;ddd;eee;', N';', 1);
- Usage: Get all non-empty items and filter non-unique
- SELECT * FROM dbo.tf_array2table(N';ddd;bbb;ccc;;;ccc;ddd;eee;', N';', 1)
- WHERE item_rank=1;
- =============================================*/
- CREATE FUNCTION dbo.tf_array2table
- (
- @array NVARCHAR(MAX), -- List of delimited values
- @delim NCHAR(1), -- Delimiter
- @remove_empty BIT -- Flag to remove empty values
- )
- -- Container for Array Items
- RETURNS @data TABLE(
- item_index INT IDENTITY(1,1), -- 1-based index of item
- item_value NVARCHAR(MAX), -- item value
- item_rank INT -- item rank if items are not unique
- )
- AS BEGIN
- -- Container for XML
- DECLARE
- @xml_text NVARCHAR(MAX),
- @xml XML;
-
- IF @remove_empty = 1 BEGIN
- -- Remove empty inner items
- WHILE (CHARINDEX(@delim + @delim, @array, 0) > 0) BEGIN
- SET @array = REPLACE(@array, @delim + @delim, @delim);
- END;
- -- Remove empty left item
- IF(LEFT(@array, 1) = @delim) BEGIN
- SET @array = SUBSTRING(@array, 2, LEN(@array)-1)
- END;
- -- Remove empty right item
- IF(RIGHT(@array, 1) = @delim) BEGIN
- SET @array = SUBSTRING(@array, 1, LEN(@array)-1)
- END;
- END;
-
- -- Prepare XML-Text
- SET @xml_text = N'<L><I>' +
- REPLACE(@array, @delim, N'</I><I>') +
- N'</I></L>';
-
- -- Convert Array to XML
- SET @xml = CAST(@xml_text AS XML);
-
- DECLARE @temp_data TABLE(
- item_index INT IDENTITY(1,1),
- item_value NVARCHAR(MAX)
- )
- -- Extract Array Items to Table-Variable
- INSERT INTO @temp_data(item_value)
- SELECT
- item_value = item.value('.', 'NVARCHAR(MAX)')
- FROM
- @xml.nodes('//I') XMLDATA(item);
-
- -- Calculate Rank for each item (to find non-unique items)
- INSERT INTO @data(item_value, item_rank)
- SELECT
- item_value,
- item_rank=RANK() OVER(PARTITION BY item_value ORDER BY item_index, item_value)
- FROM
- @temp_data
- ORDER BY
- item_index;
-
- RETURN;
- END;
- GO
Usages:
- -- Get all items
- SELECT item_index, item_value = IIF(item_value = '', '---', item_value), item_rank
- FROM dbo.tf_array2table(N';ddd;bbb;ccc;;;ccc;ddd;eee;', N';', 0);
Result
item_index | item_value | item_rank |
1 | --- | 1 |
2 | ddd | 1 |
3 | bbb | 1 |
4 | ccc | 1 |
5 | --- | 2 |
6 | --- | 3 |
7 | ccc | 2 |
8 | ddd | 2 |
9 | eee | 1 |
10 | --- | 4 |
- -- Get all non-empty items
- SELECT * FROM dbo.tf_array2table(N';ddd;bbb;ccc;;;ccc;ddd;eee;', N';', 1);
Result
item_index | item_value | item_rank |
1 | ddd | 1 |
2 | bbb | 1 |
3 | ccc | 1 |
4 | ccc | 2 |
5 | ddd | 2 |
6 | eee | 1 |
- -- Get all non-empty items and filter non-unique
- SELECT * FROM dbo.tf_array2table(N';ddd;bbb;ccc;;;ccc;ddd;eee;', N';', 1)
- WHERE item_rank=1;
Result
item_index | item_value | item_rank |
1 | ddd | 1 |
2 | bbb | 1 |
3 | ccc | 1 |
6 | eee | 1 |