【问题标题】:SQL to Parse a Key-Value StringSQL 解析键值字符串
【发布时间】:2013-05-18 01:53:27
【问题描述】:

我有一个这样的逗号分隔字符串:

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
...

但我被困在那里,似乎无法找到解决其余部分的方法。任何帮助表示赞赏。

【问题讨论】:

  • 你是全部用SQL做,还是用代码做一些处理,然后上传到数据库?
  • 这个好像和this question差不多。然而,由于 TSQL 对于文本操作和解析来说是一种非常弱的语言,如果可能的话,我会用另一种语言来做。
  • @cost,是的,存储过程的输入是分隔字符串,输出是表格
  • 在您的最终结果中,是什么规定 value2 应与 value1 位于同一行,而不是与 value1.1 位于同一行?
  • 什么版本的 SQL Server?

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


【解决方案1】:

如果您能够将数据放入每行格式的一个键/值对中,那么大部分工作就完成了。让我称这个结果为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 是按顺序分配的,如您的示例所示。

【讨论】:

  • 这很棒。我想我错过的是 group by 条款。谢谢戈登!
【解决方案2】:

这是一个更通用的版本,不依赖于顺序 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

【讨论】:

    【解决方案3】:

    这也应该有效:

    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
    

    【讨论】:

      【解决方案4】:

      我知道这篇文章真的很老了,但把它留在这里以防万一有人发现它对他们的特定解析要求有用或适合。

      -- =============================================
      -- 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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-12
        • 2021-03-02
        • 2010-10-13
        • 1970-01-01
        • 1970-01-01
        • 2021-02-18
        • 1970-01-01
        • 2021-10-24
        相关资源
        最近更新 更多