用于解析键值字符串的SQL

时间:2013-05-22 21:01:18

标签: sql sql-server sql-server-2008 tsql pivot

我有一个逗号分隔的字符串,如下所示:

key1=value1,key2=value2,key3=value3,key1=value1.1,key2=value2.1,key3=value3.1

我想把它解析成一个看起来像这样的表:

Key1       Key2       Key3
==============================
value1     value2     value3
value1.1   value2.1   value3.1

我可以将字符串拆分为行:

ID      Data
================
1       key1=value1
2       key2=value2
3       key3=value3
...

但是我被困在那里似乎无法找到办法完成剩下的工作。任何帮助表示赞赏。

4 个答案:

答案 0 :(得分:0)

如果您能够将数据转换为每行格式的一个键/值对,那么大部分工作都已完成。让我称之为结果t。这样的事情可能会让你完全接受:

select max(case when LEFT(data, 4) = 'key1' then SUBSTRING(data, 6, len(data)) end) as key1,
       MAX(case when LEFT(data, 4) = 'key2' then SUBSTRING(data, 6, len(data)) end) as key2,
       MAX(case when LEFT(data, 4) = 'key2' then SUBSTRING(data, 6, len(data)) end) as key3
from t
group by (id - 1)/3

这假定id按顺序分配,如示例所示。

答案 1 :(得分:0)

这是一个更通用的版本,不依赖于顺序ID。但是,不清楚的是,最终结果中的value1value2如何相互关联而不是value1value2.1。在这个解决方案中,我任意对每个给定密钥的出现进行排序。

With SplitKeyValuePairs As
    (
    Select Id
        , Left([Data], CharIndex('=', [Data]) - 1) As KeyName
        , Substring([Data], CharIndex('=', [Data]) + 1, Len([Data])) As Value
        , Row_Number() Over ( Partition By Left([Data], CharIndex('=', [Data]) - 1) Order By Id ) As RowNum
    From SplitDelimitedString
    )
Select Max ( Case When KeyName = 'Key1' Then Value End ) As [Key1]
    , Max ( Case When KeyName = 'Key2' Then Value End ) As [Key2]
    , Max ( Case When KeyName = 'Key3' Then Value End ) As [Key3]
From SplitKeyValuePairs
Group By RowNum

SQL Fiddle version

答案 2 :(得分:0)

这也应该有效:

SELECT *
FROM
   (
      SELECT
         Grp = ID / 3,
         KeyName = Left(Data, CharIndex('=', Data) - 1),
         Value = Substring(Data, CharIndex('=', Data) + 1, 8000)
      FROM
         SplitString
   ) S
   PIVOT (Max(Value) FOR KeyName IN (Key1, Key2, Key3)) P

答案 3 :(得分:0)

我知道这篇文章确实很老,但是请留在这里,以防万一有人觉得这对他们的特定解析要求有用或合适。

-- =============================================
-- Author:	Peter Gumpal
-- Create date: October 23, 2018
-- Description:	This function was developed to transform a key-value pair delimited string into a table.
--usage as follows:
-- Select * from dbo.KVParser('LP=pH FM=(begin)[odor](add)[odor](end) US=pgumpal')
-- this will return 3 records containing keys: LP, FM and US. Between "=" are values so  if the string
-- used is a CSV, the comma character will not be omitted. 
-- Key limitation: Fixed to two characters, update code as required.
-- Note: Code not optimal, suggestions/mods are always welcome. - Peter :)
-- =============================================
CREATE FUNCTION [dbo].[KVParser] 
(
@pKVString varchar(500)
)
RETURNS  @kvtemp table ([key] varchar(2), [val] varchar(300))
AS
Begin
Declare @str varchar(500)

set @str = @pKVString -- 'LP=pH FM=(begin)[odor](add)[odor](end) US=pgumpal'
Declare @curKey varchar(2)
Declare @curChar varchar(1)
Declare @concatStr varchar(300)
Declare @ctrI int
Set @ctrI = 0
While (len(@str) > @ctrI)
Begin
	Set @curChar = SUBSTRING(@str,@ctrI,1)
	If (@curChar = '=')
		Begin
			Set @curKey = SUBSTRING(@str, @ctrI - 2 ,2) --get the key
				--begin, get value from its right side
				Set @ctrI = @ctrI + 1
				Set @curChar = SUBSTRING(@str,@ctrI,1)
				Set @concatStr = ''
				--loop into the value
				While (@curChar <> '='AND len(@str)  >= @ctrI)
					Begin
						Set @curChar = SUBSTRING(@str,@ctrI,1)
						Set @concatStr = isnull(@concatStr,'') + ISNULL(@curChar,'')
						Set @ctrI = @ctrI + 1
					End
			    --end, get value from its right side

			Insert into @kvtemp([key],[val])
				Select @curKey, LEFT(@concatStr, IIF(RIGHT(@concatStr,1)= '=', len(@concatStr)-3,len(@concatStr)))
				--above IIF was added to trim the closing key and = / line needs improvement. 
			Set @ctrI = @ctrI - 3 --decrement counter to 3 to back read the key for the closing =
		End
	Set @ctrI = @ctrI + 1
End
Return
End