Skip to Content
Technical Articles

Split string into multiple rows using SQL in SAP HANA

Introduction

In this post I would like to describe options for splitting concatenated string into multiple rows using SQL in SAP HANA. Depending on which version of HANA system you are working you can choose the one which is valid.

Creating custom function (when SAP HANA system version is 2.0 SP02 or lower)

If your HANA system is of version 2.0 SP2 or older, then there is no in-built function for splitting strings, that’s why you will need to create custom function.

Scenario 1.

You have the comma separated string ‘A1,A2,A3,A4,A5,A6’ which you want to display as multiple rows. Below there is a code for table function splitting comma separated string into multiple lines. 

FUNCTION "_SYS_BIC"."TMP::TF_SPLIT_STRING" ( INPUT_STRING VARCHAR(5000) ) 
	RETURNS TABLE
	(
		"OUTPUT_SPLIT" VARCHAR(5000)
	)
	LANGUAGE SQLSCRIPT
	SQL SECURITY INVOKER AS
BEGIN

	DECLARE COUNTER INT := 1;
	SPLIT_VALUES = SELECT SUBSTR_BEFORE(:INPUT_STRING,',') SINGLE_VAL FROM DUMMY;	
	SELECT SUBSTR_AFTER(:INPUT_STRING,',') || ',' INTO INPUT_STRING FROM DUMMY;
	
	WHILE( LENGTH(:INPUT_STRING) > 0 )	
	DO
	
	   SPLIT_VALUES =	
	   
	   				SELECT SUBSTR_BEFORE(:INPUT_STRING,',') SINGLE_VAL FROM DUMMY				   
					   UNION 	   
					SELECT SINGLE_VAL FROM :SPLIT_VALUES;
	
	   SELECT SUBSTR_AFTER(:INPUT_STRING,',') INTO INPUT_STRING FROM DUMMY;
	   	
	END WHILE;
	
	RETURN
	
	SELECT SINGLE_VAL AS "OUTPUT_SPLIT" FROM :SPLIT_VALUES; 

END

*If your string is separated by different delimiter simply replace ',' with other symbol.

Now let’s query the function for the string which we need to split:

DO
BEGIN

	DECLARE TEST_STRING VARCHAR(50) := 'A,B,C,D,E,F,G,H';
	
	SELECT "OUTPUT_SPLIT" FROM "_SYS_BIC"."TMP::TF_SPLIT_STRING" (:TEST_STRING); 

END

Result:

Using SQLSCRIPT built-in Library (recommended when SAP HANA version is 2.0 SP03 or higher)

Version 2.0 SP03 of SAP HANA offers new enhancement of SQLScript library – SQLSCRIPT_STRING. Functions within this library enables easy way of splitting string into multiple rows. Additionally developer has more flexibility to define splitting rules.

Scenario 1

You have the comma separated string

'A1,A2,A3,A4,A5,A6'

which you want to display as multiple rows.

Use following code:

I. Explicitly declare usage of SQLSCRIPT_STRING library. Assign alias for the library (in this example name of the alias is “LIBRARY”, but you can assign any other name)

II. Explicitly declare output table

III. Use SPLIT_TO_TABLE function. Combine it with the alias assigned in point I. As input for SPLIT_TO_TABLE function use string which you want to split, and after comma define delimiter (in this example comma is delimiter). At the end you need to assign output of that function to the table variable defined in point II.

IV. Query the table variable

After running following the query string will be splitted into multiple rows:

DO
BEGIN

	USING SQLSCRIPT_STRING AS LIBRARY;
	
	DECLARE TEST_OUTPUT TABLE(RESULT NVARCHAR(5000));
	
	DECLARE TEST_STRING VARCHAR(50) := 'A,B,C,D,E,F,G,H';

	TEST_OUTPUT = LIBRARY:SPLIT_TO_TABLE(:TEST_STRING,',');
	
	SELECT * FROM :TEST_OUTPUT;

END

Result:

Scenario 2

There is a string which combines first and last name, phone and the address:

'Sarah Blake, 98 921 29 30, 270 Sycamore Street Brookfield, WI 53045, US' 

You want to split this string into three values: full name, phone, address.

Use following code:

DO
BEGIN

	USING SQLSCRIPT_STRING AS LIBRARY;
	
	DECLARE TEST_OUTPUT TABLE(RESULT NVARCHAR(5000));
	
	DECLARE TEST_STRING VARCHAR(100) := 'Sarah Blake, 98 921 29 30, 270 Sycamore Street Brookfield, WI 53045, US';

	TEST_OUTPUT = LIBRARY:SPLIT_TO_TABLE(:TEST_STRING,',',2);
	
	SELECT * FROM :TEST_OUTPUT;

END

Result:

Here I used third optional parameter (MAXSPLIT) which is available for SPLIT_TO_TABLE and assigned value of 2. This way I will limit the split to only first two comma occurrences (subsequent commas will not be considered).

Besides defining delimiter for split, you can also specify maximum number of splits. Function takes first n-number of delimiter occurences, and remaining part is being displayed in the last row. As you can see in the string from the example there are 4 commas, so if this parameter would not be specified, then in output there would be 5 rows.

Scenario 3

There is a string which combines number, date and time. It’s separated by #, DATE, TIME string:

'10000000123#20190101DATE115737TIME'

You want to split this string into three strings: number, date, time.

Use following code:

DO
BEGIN

	USING SQLSCRIPT_STRING AS LIBRARY;
	
	DECLARE TEST_OUTPUT TABLE(RESULT NVARCHAR(5000));
	
	DECLARE TEST_STRING VARCHAR(50) := '10000000123#20190101DATE115737TIME';

	TEST_OUTPUT = LIBRARY:SPLIT_REGEXPR_TO_TABLE(:TEST_STRING, '\#|[A-Z]*[A-Z]') ;
	
	SELECT * FROM :TEST_OUTPUT WHERE "RESULT" != '';

END

Output:

Here I used function SPLIT_REGEXPR_TO_TABLE. It can be combined with regular expressions, which gives user even more options for defining logic for splitting strings. Regular expression from the example splits string after each occurencs of # symbol or uppercase alphabet string.

Summary

SAP HANA SPS 02 introduced built-in libraries giving SQL developers new functions. In SPS 03 new librarary SQLSCRIPT_STRING has been added which contains multiple functions for manipulating with strings. If you want to find out more about SQLSCRIPT_STRING library, check SQLScript reference by SAP.

If your system is running on older version of SAP HANA, as workaround you can develop custom function as described in the post.

In my next post you can check how to Split table column value into multiple rows using SQL in SAP HANA

Thanks for reading!

9 Comments
You must be Logged on to comment or reply to a post.
  • Good explanation how to split a string.  My situation though is I have a table with a column, whose values are a comma separated list.  How to leverage this SPLIT function on a table column and generate a separate row per split value?

     

    Header_1 | Header_2

    A | 1,2,3

    B | 4,5

     

    Convert to

    Header_1 | Header_2

    A | 1

    A | 2

    A | 3

    B | 4

    B | 5

    • Hi Beecher,

      Sorry for late reply. I’ve just published a new post which describes your scenario (link added at the end of this post).

  • Hi Konrad

     

    First I would like to thank you for sharing the possibilities of “SQLSCRIPT_STRING” library .

     

    I tried to use it for one of my use cases , but I came across insufficient privileges error . I tried to find the authorizations required for Using libraries in procedure  , but could not find documentation related to that . Could you help me with authorizations required to use libraries in procedures.

    Thanks

  • Hi Konrad,

    Firstly, thanks a lot for showing us how to use SQLSCRIPT_STRING, it was a very helpful document.

    I have a requirement where I have an input string as shown below, where data is been consumed with column and its respective data using Tilda and Pipe delimiters. Can you please guide how split the data using the new functionality.

    Input String:

    ~COLUMN_1~2F-8S~COLUMN_2~SEC-WATER~COLUMN_3~2SF-S-S10~COLUMN_4~10~COLUMN_5~20.44~COLUMN_6~7358.40~COLUMN_7~TRUE~|

    ~COLUMN_1~2F-8S~COLUMN_2~SEC- WATER ~COLUMN_3~2SF-S-M-10~COLUMN_4~10~COLUMN_5~55.91~COLUMN_6~20127.60~COLUMN_7~ TRUE ~|

    ~COLUMN_1~2F-8S~COLUMN_2~SEC- WATER ~COLUMN_3~2SF-S-P-10~COLUMN_4~10~COLUMN_5~10.84~COLUMN_6~3902.40~COLUMN_7~ TRUE ~|

     

    Need to show the data as below

    COLUMN_1 COLUMN_2 COLUMN_3 COLUMN_4 COLUMN_5 COLUMN_6 COLUMN_7
    2F-8S SEC- WATER 2SF-S-S10 10 20.44 7,358.40 TRUE
    2F-8S SEC- WATER 2SF-S-M-10 10 55.91 20,127.60 TRUE
    2F-8S SEC- WATER 2SF-S-P-10 10 10.84 3,902.40 TRUE

     

    Note: I am using 2.0 SPS 3

    • Hi Santhosh,

      You can use SPLIT_REGEXPR function. Here is an example (it includes first two strings which you provided):

      DO
      BEGIN
      
      	USING SQLSCRIPT_STRING AS LIB;
      	
      	DECLARE COL1 VARCHAR(150);
      	DECLARE COL2 VARCHAR(150);
      	DECLARE COL3 VARCHAR(150);
      	DECLARE COL4 VARCHAR(150);
      	DECLARE COL5 VARCHAR(150);
      	DECLARE COL6 VARCHAR(150);
      	DECLARE COL7 VARCHAR(150);
      	DECLARE COL8 VARCHAR(150);
      	DECLARE COL9 VARCHAR(150);
      	DECLARE COL10 VARCHAR(150);
      	DECLARE COL11 VARCHAR(150);
      	DECLARE COL12 VARCHAR(150);
      	DECLARE COL13 VARCHAR(150);
      	DECLARE COL14 VARCHAR(150);
      	DECLARE COL15 VARCHAR(150);
      	DECLARE COL16 VARCHAR(150);
      	
      	DECLARE STRING VARCHAR(200) := '~COLUMN_1~2F-8S~COLUMN_2~SEC-WATER~COLUMN_3~2SF-S-S10~COLUMN_4~10~COLUMN_5~20.44~COLUMN_6~7358.40~COLUMN_7~TRUE~|';
      	
      	DECLARE STRING2 VARCHAR(200) := '~COLUMN_1~2F-8S~COLUMN_2~SEC-WATER~COLUMN_3~2SF-S-M-10~COLUMN_4~10~COLUMN_5~55.91~COLUMN_6~20127.60~COLUMN_7~TRUE~|';
      	
      	(COL1,COL2,COL3,COL4,COL5,COL6,COL7,COL8,COL9,COL10,COL11,COL12,COL13,COL14,COL15,COL16) :=  LIB:SPLIT_REGEXPR(:STRING,'\~',15);
      		
      	RES1 = SELECT COL3 AS COLUMN_1,COL5 AS COLUMN_2,COL7 AS COLUMN_3,COL9 AS COLUMN_4,COL11 AS COLUMN_5,COL13 COLUMN_6, COL15 AS COLUMN_7 FROM DUMMY;
      
      	(COL1,COL2,COL3,COL4,COL5,COL6,COL7,COL8,COL9,COL10,COL11,COL12,COL13,COL14,COL15,COL16) :=  LIB:SPLIT_REGEXPR(:STRING2,'\~',15);
      
      	RES2 = SELECT COL3 AS COLUMN_1,COL5 AS COLUMN_2,COL7 AS COLUMN_3,COL9 AS COLUMN_4,COL11 AS COLUMN_5,COL13 COLUMN_6, COL15 AS COLUMN_7 FROM DUMMY;
      
      
      	SELECT * FROM :RES1
      	UNION
      	SELECT * FROM :RES2;
      	
      END

      In future if you have specific question, raise it through SAP community rather than in comments 🙂