【问题标题】:Split multiple values with header included into columns拆分多个值,并将标题包含在列中
【发布时间】:2018-07-20 14:53:10
【问题描述】:

我有一列包含由“,”分隔的多个值,还包括由“:”分隔的标题。 该列如下所示:

{"Id":"c7d45d60-cf90-490d-be4c-f04c9349da03","RecordType":20,"CreationTime":"2018-06-12T21:48:30","Operation":"DownloadReport","OrganizationId":"dabd5d90-87c2-44c9-93cd-783e03236e40","UserType":0,"UserKey":"10033FFF85612C0C","Workload":"PowerBI","UserId":"xxxxxx@grundfos.com","ClientIP":"xxx.3.xx.111","UserAgent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/66.0.3359.181 Safari\/537.36","Activity":"DownloadReport","ItemName":"My Salesresponsibility Final 12-06-2018","WorkSpaceName":"My Sales Dashboard testing environment","DatasetName":"My Salesresponsibility Final 12-06-2018","ReportName":"My Salesresponsibility Final 12-06-2018","CapacityId":"65CB790D-16C8-4DA6-BFA2-89854100423E","CapacityName":"Hope","WorkspaceId":"34812eed-830a-43b2-ae18-6c5c1c0c92a1","ObjectId":"My Salesresponsibility Final 12-06-2018","DatasetId":"b6184b73-fea2-4244-83ca-328e89c536af","ReportId":"36e6b6c5-ceeb-4d02-9d54-fb820634e839","IsSuccess":true,"DatapoolRefreshScheduleType":"None"}

有没有办法将这些值及其标题拆分为单独的列? 因此第一列将命名为“Id”并包含值“c7d45d60-cf90-490d-be4c-f04c9349da03”等等。 我已经尝试遵循这个类似问题的最受好评的解决方案,但它似乎不起作用: How to split a comma-separated value to columns

所以我想从这里开始:

这样的:

我尝试过使用这段代码,但确实效果不佳:

SELECT [AuditData]
      ,Substring(AuditData, 1,Charindex(',', AuditData)-1) as Id
      ,Substring(AuditData, Charindex(',', AuditData)+1, LEN(AuditData)) as  RecordType
      ,Substring(AuditData, Charindex(',', AuditData)+2, LEN(AuditData)) as  CreationTime
  FROM [dbo].[Log]

【问题讨论】:

  • 包含您一直在尝试但似乎不起作用的代码?
  • 我不认为我可以使用 JSON 函数? Microsoft SQL Azure (RTM) - 2018 年 6 月 8 日 12.0.2000.8 18:18:54 版权所有 (C) 2018 Microsoft Corporation
  • JSOn 函数在 Azure 中可用。您是否尝试过以下@shnugo 答案?
  • 是的,它似乎有效。我只需要弄清楚如何在作为列中的键和作为这些列中的值的值中进行透视。

标签: tsql


【解决方案1】:

这并不奇怪,只是 JSON。 Starting with version 2016 you can use FROM OPENJSON() 喜欢这里:

DECLARE @v VARCHAR(MAX)='{"Id":"c7d45d60-cf90-490d-be4c-f04c9349da03","RecordType":20,"CreationTime":"2018-06-12T21:48:30","Operation":"DownloadReport","OrganizationId":"dabd5d90-87c2-44c9-93cd-783e03236e40","UserType":0,"UserKey":"10033FFF85612C0C","Workload":"PowerBI","UserId":"xxxxxx@grundfos.com","ClientIP":"xxx.3.xx.111","UserAgent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/66.0.3359.181 Safari\/537.36","Activity":"DownloadReport","ItemName":"My Salesresponsibility Final 12-06-2018","WorkSpaceName":"My Sales Dashboard testing environment","DatasetName":"My Salesresponsibility Final 12-06-2018","ReportName":"My Salesresponsibility Final 12-06-2018","CapacityId":"65CB790D-16C8-4DA6-BFA2-89854100423E","CapacityName":"Hope","WorkspaceId":"34812eed-830a-43b2-ae18-6c5c1c0c92a1","ObjectId":"My Salesresponsibility Final 12-06-2018","DatasetId":"b6184b73-fea2-4244-83ca-328e89c536af","ReportId":"36e6b6c5-ceeb-4d02-9d54-fb820634e839","IsSuccess":true,"DatapoolRefreshScheduleType":"None"}';
SELECT *
FROM OPENJSON(@v);

结果

key            value                                 type
Id             c7d45d60-cf90-490d-be4c-f04c9349da03  1
RecordType     20                                    2
CreationTime   2018-06-12T21:48:30                   1
[... more rows ...]

UPDATE 将此作为 PIVOT 列表

有两种方法:

DECLARE @v VARCHAR(MAX)='{"Id":"c7d45d60-cf90-490d-be4c-f04c9349da03","RecordType":20,"CreationTime":"2018-06-12T21:48:30","Operation":"DownloadReport","OrganizationId":"dabd5d90-87c2-44c9-93cd-783e03236e40","UserType":0,"UserKey":"10033FFF85612C0C","Workload":"PowerBI","UserId":"xxxxxx@grundfos.com","ClientIP":"xxx.3.xx.111","UserAgent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/66.0.3359.181 Safari\/537.36","Activity":"DownloadReport","ItemName":"My Salesresponsibility Final 12-06-2018","WorkSpaceName":"My Sales Dashboard testing environment","DatasetName":"My Salesresponsibility Final 12-06-2018","ReportName":"My Salesresponsibility Final 12-06-2018","CapacityId":"65CB790D-16C8-4DA6-BFA2-89854100423E","CapacityName":"Hope","WorkspaceId":"34812eed-830a-43b2-ae18-6c5c1c0c92a1","ObjectId":"My Salesresponsibility Final 12-06-2018","DatasetId":"b6184b73-fea2-4244-83ca-328e89c536af","ReportId":"36e6b6c5-ceeb-4d02-9d54-fb820634e839","IsSuccess":true,"DatapoolRefreshScheduleType":"None"}';

--枢轴

SELECT p.*
FROM
(
    SELECT [value],[key]
    FROM OPENJSON(@v)
) t
PIVOT
(
    MAX(t.[value]) FOR t.[key] in(Id,RecordType,CreationTime)
) p;

--JSON_VALUE

SELECT JSON_VALUE(@v,'$.Id') AS Id
      ,JSON_VALUE(@v,'$.RecordType') AS RecordType
      ,JSON_VALUE(@v,'$.CreationTime') AS CreationTime

试试看……

更新 2:从表中获取

这很简单。

DECLARE @tbl TABLE(ID INT IDENTITY, yourJSON NVARCHAR(MAX));
INSERT INTO @tbl VALUES('{"Id":"blah1","RecordType":10]}')
                      ,('{"Id":"blah2","RecordType":20]}')
                      ,('{"Id":"blah3","RecordType":30]}');
SELECT t.ID 
      ,JSON_VALUE(t.yourJSON,'$.Id') AS JsonId
      ,JSON_VALUE(t.yourJSON,'$.RecordType') AS RecordType
FROM @tbl t;

提示

对于您的下一个问题:请不要粘贴图片。尝试添加一个简化的独立运行示例 (so called MCVE),就像我在上面所做的那样。否则,人们必须为您输入此内容。

【讨论】:

  • 这个解决方案看起来不错而且简单,但是我如何获取单独列中的值而不是键列中的行值?
  • @user2776167 如果你事先知道所有的键,你可以使用简单的pivot。
  • 我愿意,而且它们不应该随着时间的推移而改变。我将研究将键和值旋转到列中。关于如何做到这一点的任何提示? @Shnugo
  • 这也很完美!非常感谢您编写如此清晰的代码!
  • 现在我只需要弄清楚如何为表中的每一行而不是一个变量。
【解决方案2】:

如果你修复了上面cmets中提到的数据,那么使用Jeff Moden's splitter function你可以使用这种方法

最好使用永远不会出现在数据集中的分隔符

;WITH CteSpace AS(
    SELECT *
    FROM dbo.DelimitedSplit8K(REPLACE(REPLACE(REPLACE(@j,'"', ''),'{', ''), '}', '') , ',')
)
SELECT
    [Id]    = LEFT(Item, CHARINDEX(':', Item) - 1),
    [Value] = SUBSTRING(Item, CHARINDEX(':', Item) +1, LEN(Item) - CHARINDEX(':', Item))
FROM CteSpace

提供此输出

Id                          Value
Id                          c7d45d60-cf90-490d-be4c-f04c9349da03
RecordType                  20
CreationTime                2018-06-12T21-48-30
Operation                   DownloadReport
OrganizationId              dabd5d90-87c2-44c9-93cd-783e03236e40
UserType                    0
UserKey                     10033FFF85612C0C
Workload                    PowerBI
UserId                      xxxxxx@grundfos.com
ClientIP                    xxx.3.xx.111
UserAgent                   Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML- like Gecko) Chrome\/66.0.3359.181 Safari\/537.36
Activity                    DownloadReport
ItemName                    My Salesresponsibility Final 12-06-2018
WorkSpaceName               My Sales Dashboard testing environment
DatasetName                 My Salesresponsibility Final 12-06-2018
ReportName                  My Salesresponsibility Final 12-06-2018
CapacityId                  65CB790D-16C8-4DA6-BFA2-89854100423E
CapacityName                Hope
WorkspaceId                 34812eed-830a-43b2-ae18-6c5c1c0c92a1
ObjectId                    My Salesresponsibility Final 12-06-2018
DatasetId                   b6184b73-fea2-4244-83ca-328e89c536af
ReportId                    36e6b6c5-ceeb-4d02-9d54-fb820634e839
IsSuccess                   true
DatapoolRefreshScheduleType None

【讨论】:

  • 任何字符串拆分方法都必须处理这样一个事实,即出现在 qoutes 之间的分隔符不是分隔符。如果有最微小的机会,其中一个值在内容中包含逗号(例如 ObjectId="My Salesresponsibility, Final 12-06-2018"),那么这种方法将失败......这可能会通过任何测试,但会中断生产...
  • 这是真的,但如果 OP 没有 SQL 2016 那么他们就不能使用 OPENJSON ,这不会留下很多其他选择
  • True... 您必须遍历字符并注意打开和关闭引号,以便用另一个必须在拆分后重新设置的字符替换嵌入的分隔符。可能,但很重......
【解决方案3】:

如果你没有 SQL 2016 并且想使用 JSON 字符串,那么你可以使用Phil Factor's ParseJSON function

然后,正如@Shnugo 所说,无需担心数据集中出现分隔符并破坏代码

DECLARE @j NVARCHAR(MAX) = '{"Id":"c7d45d60-cf90-490d-be4c-f04c9349da03","RecordType":20,"CreationTime":"2018-06-12T21-48-30","Operation":"DownloadReport","OrganizationId":"dabd5d90-87c2-44c9-93cd-783e03236e40","UserType":0,"UserKey":"10033FFF85612C0C","Workload":"PowerBI","UserId":"xxxxxx@grundfos.com","ClientIP":"xxx.3.xx.111","UserAgent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML- like Gecko) Chrome\/66.0.3359.181 Safari\/537.36","Activity":"DownloadReport","ItemName":"My Salesresponsibility Final 12-06-2018","WorkSpaceName":"My Sales Dashboard testing environment","DatasetName":"My Salesresponsibility Final 12-06-2018","ReportName":"My Salesresponsibility Final 12-06-2018","CapacityId":"65CB790D-16C8-4DA6-BFA2-89854100423E","CapacityName":"Hope","WorkspaceId":"34812eed-830a-43b2-ae18-6c5c1c0c92a1","ObjectId":"My Salesresponsibility Final 12-06-2018","DatasetId":"b6184b73-fea2-4244-83ca-328e89c536af","ReportId":"36e6b6c5-ceeb-4d02-9d54-fb820634e839","IsSuccess":true,"DatapoolRefreshScheduleType":"None"}'


SELECT name, stringvalue
FROM dbo.parseJSON(@j)

输出

name            stringvalue
Id              c7d45d60-cf90-490d-be4c-f04c9349da03
RecordType      20
CreationTime    2018-06-12T21-48-30
Operation       DownloadReport
OrganizationId  dabd5d90-87c2-44c9-93cd-783e03236e40
UserType        0
UserKey         10033FFF85612C0C

【讨论】:

    【解决方案4】:

    以一种非常迂回的方式,我得到了我需要的答案。我通过以下方式从列中创建了一个包含 JSON 的新视图:

    SELECT
            JSON_VALUE(AuditData,'$.Id') AS Id
            ,JSON_VALUE(AuditData,'$.RecordType') AS RecordType
            ,JSON_VALUE(AuditData,'$.CreationTime') AS CreationTime
            ,JSON_VALUE(AuditData,'$.Operation') AS Operation
            ,JSON_VALUE(AuditData,'$.OrganizationId') AS OrganizationId
            ,JSON_VALUE(AuditData,'$.UserType') AS UserType
            ,JSON_VALUE(AuditData,'$.UserKey') AS UserKey
            ,JSON_VALUE(AuditData,'$.Workload') AS Workload
            ,JSON_VALUE(AuditData,'$.UserId') AS UserId
            ,JSON_VALUE(AuditData,'$.ClientIP') AS ClientIP
            ,JSON_VALUE(AuditData,'$.UserAgent') AS UserAgent
            ,JSON_VALUE(AuditData,'$.Activity') AS Activity
            ,JSON_VALUE(AuditData,'$.ItemName') AS ItemName
            ,JSON_VALUE(AuditData,'$.WorkSpaceName') AS WorkSpaceName
            ,JSON_VALUE(AuditData,'$.DatasetName') AS DatasetName
            ,JSON_VALUE(AuditData,'$.ReportName') AS ReportName
            ,JSON_VALUE(AuditData,'$.CapacityId') AS CapacityId
            ,JSON_VALUE(AuditData,'$.CapacityName') AS CapacityName
            ,JSON_VALUE(AuditData,'$.WorkspaceId') AS WorkspaceId
            ,JSON_VALUE(AuditData,'$.ObjectId') AS ObjectId
            ,JSON_VALUE(AuditData,'$.DatasetId') AS DatasetId
            ,JSON_VALUE(AuditData,'$.ReportId') AS ReportId
            ,JSON_VALUE(AuditData,'$.IsSuccess') AS IsSuccess
            ,JSON_VALUE(AuditData,'$.DatapoolRefreshScheduleType') AS DatapoolRefreshScheduleType
    
    FROM [dbo].[Audit_Log];
    

    非常感谢 @Shnugo 帮助像我这样的新手使用 Stackoverflow。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多