How to split cell content and extract information into a new column in an SQL select statement?

和自甴很熟 提交于 2019-12-13 01:41:36

问题


I have a table where one of the columns are storing key/value pairs separated by semicolons, like this:

KEY1:VALUE1;KEY2:VALUE2;KEY3:VALUE3

I would like to construct a view where I have additional columns where the value will be extracted from the field above. My question is how to extract VALUE1, VALUE2 and VALUE3 in a SELECT query.

There will not be more than three key-value pairs in this field.


回答1:


I've already answered an incredibly similar question today, so look at the answer:

SQL comma delimted column => to rows then sum totals?

but try this:

I prefer the number table approach to split a string in TSQL

For this method to work, you need to do this one time table setup:

SELECT TOP 10000 IDENTITY(int,1,1) AS Number
    INTO Numbers
    FROM sys.objects s1
    CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)

Once the Numbers table is set up, create this split function:

CREATE FUNCTION [dbo].[FN_ListToTable]
(
     @SplitOn  char(1)      --REQUIRED, the character to split the @List string on
    ,@List     varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN 
(

    ----------------
    --SINGLE QUERY-- --this will not return empty rows
    ----------------
    SELECT
        ListValue
        FROM (SELECT
                  LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue
                  FROM (
                           SELECT @SplitOn + @List + @SplitOn AS List2
                       ) AS dt
                      INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
                  WHERE SUBSTRING(List2, number, 1) = @SplitOn
             ) dt2
        WHERE ListValue IS NOT NULL AND ListValue!=''

);
GO 

You can now easily split a CSV string into a table and join on it:

select * from dbo.FN_ListToTable(',','1,2,3,,,4,5,6777,,,')

OUTPUT:

ListValue
-----------------------
1
2
3
4
5
6777

(6 row(s) affected)

Your can now use a CROSS APPLY to split every row in your table like:

DECLARE @YourTable table (RowID int, RowValue varchar(200))
INSERT INTO @YourTable VALUES (1,'KEY11:VALUE11;KEY12:VALUE12;KEY13:VALUE13')
INSERT INTO @YourTable VALUES (2,'KEY21:VALUE21;KEY22:VALUE22;KEY23:VALUE23')
INSERT INTO @YourTable VALUES (3,'KEY31:VALUE31;KEY32:VALUE32;KEY33:VALUE33')


SELECT
    o.RowID,RIGHT(st.ListValue,LEN(st.ListValue)-CHARINDEX(':',st.ListValue)) AS RowValue
    FROM @YourTable  o
        CROSS APPLY  dbo.FN_ListToTable(';',o.RowValue) AS st

OUTPUT:

RowID       
----------- -------
1           VALUE11
1           VALUE12
1           VALUE13
2           VALUE21
2           VALUE22
2           VALUE23
3           VALUE31
3           VALUE32
3           VALUE33

(9 row(s) affected)



回答2:


Writing a scalar function, which receives the string containing the key/value pairs, and the index of the value to get (or the key of the value to get) as its arguments, and returns the appropriate value, would make your problem easily solvable.

You could also write this scalar function in .Net, which would perform a lot better than writing it in TSQL, as you wouldn't have to access any tables or database objects from that function.



来源:https://stackoverflow.com/questions/2342431/how-to-split-cell-content-and-extract-information-into-a-new-column-in-an-sql-se

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!