我正在使用SQl服务器,并且已经在工作了一段时间用于工作但遇到了很多问题。
我开始用表“Logs”
| ChangeID | UserID | LogDate | Status | Fields
| 123 | 001 | 7-12-12 | Open | (raw data)
| 456 | 001 | 7-9-14 | Complete | (raw data)
| 789 | 002 | 5-8-15 | Open | (raw data)
“Fields”列包含JSON格式的表单中的数据。基本上,它包含字段名称,前值和后值。 对于Fields中的每一行,我都能够解析JSON以获得临时表#fieldTable。因此,例如,“字段”列中的一行原始数据将生成下表:
|Field |Before |After
|User |ZZZ |YYY
|requestDue |7-2-13 |7-5-14
|Assigned |No |Yes
Field可以有任意数量的值,并且事先不知道字段的名称。 我需要的是有一个final表,它将所有使用字段值生成的临时表组合为新列,如下所示:
| ChangeID | UserID | LogDate | Status | Fields | UserBefore | UserAfter | requestDueBefore | requestDueAfter | … |
其中,如果相同的字段名称出现在JSON的两个不同的行中(以及因此格式化数据的表),则不会添加新列,而是仅更新数据。因此,例如,如果具有ChangeID 123的行具有原始数据
[{“field":"reqId", “before”: “000”,"after":"111"},{"field":"affected",”before”:no,"after":"yes"},{"field":"application",”before”:xxx,"after":"yyy"}]
并且ChangeID 789将其Fields字段中的原始数据作为
[{“field":"attachments", “before”: “null”,"after":"zzzzzzz"},{"field":"affected",”before”:no,"after":"yes}]
,那么因为来自ChangeID123的“受影响”字段应该导致列受影响,然后受影响到最终表,当从Change789再次看到此字段时,将不会添加新列。
如果某个特定行的某些列没有数据,则它应该为null。
我想这样做的方法是首先尝试在生成临时表时动态调整它们,以便我得到以前的结果
|User |requestDue |Assigned
|ZZZ |7-2-13 |No
和另一个后结果
|User |requestDue |Assigned
|YYY |7-5-14 |Yes
使用以下代码:
declare @cols as nvarchar(max),
@query as nvarchar(max)
select @cols = stuff((select ',' + QUOTENAME(field)
from #fieldTable
group by field--, id
--order by id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = N'SELECT ' + @cols + N' from
(
select before, field
from #fieldTable
) x
pivot
(
max(before)
for field in (' + @cols + N')
) p '
exec sp_executesql @query;
(对于带有after值的结果,再次使用不同的变量再次相同)
我认为可能有某种方法可以动态地将动态列名称与“之前”或“之后”连接起来,然后以某种方式将这些列添加到过程范围之外的最终表中。但是,我不确定如何,而且我也不确定这是否是解决问题的最佳方法。我尝试使用别名,但我认为您需要知道列名称才能使其工作,同样需要更改表以添加更多列。
此外,我已经看到,对于许多类似的问题,人们被建议使用openrowset,我无法使用。
答案 0 :(得分:0)
这个答案在评论中更好,因为它没有直接解决你的问题 - 但是,我还没有直接评论的声誉。
对于您所描述的内容,您可能会考虑SQLXML数据字段。 SQLXML允许您存储任意模式的文档,SQL-Server本身支持对它的查询。
这将允许避免我认为您已经发现在尝试基于未知的模型动态创建模式时相当复杂。
希望有所帮助。