我有一张表来跟踪变化。
CREATE TABLE ChangeTracker
(
ChangeId BIGINT NOT NULL identity(1, 1) PRIMARY KEY,
ChangeDate DATETIME NOT NULL DEFAULT getdate(),
Changes VARCHAR(max) NOT NULL DEFAULT ''
)
Changes
中的数据采用以下格式:
<span class="fieldname">AssignedTo</span>
<span class="oldvalue">user1</span>
<span class="newvalue">user2</span>
<br />
<span class="fieldname">Attachments</span>
<br />
<span class="fieldname">Status</span>
<span class="oldvalue">new</span>
<span class="newvalue">open</span>
<br />
<span class="fieldname">Priority</span>
<span class="oldvalue">low</span>
<span class="newvalue">high</span>
<br />
...
请注意,某些更改包含fieldname,oldvalue,newvalue对,而有些更改只有fieldname。此外,所有更改都以<br />
标记分隔。
因此,当我想要对特定的FieldName(比如Status)进行更改时,我可以使用以下查询来执行此操作:
SELECT * FROM
(
SELECT ChangeId,
ChangeDate,
TransDesc.value('(/root/span[@class="fieldname"]/text())[1]', 'varchar(255)') as FieldName,
TransDesc.value('(/root/span[@class="oldvalue"]/text())[1]', 'varchar(255)') AS OldValue,
TransDesc.value('(/root/span[@class="newvalue"]/text())[1]', 'varchar(255)') AS NewValue
FROM (
SELECT *, TransDesc = CAST('<root>' + SUBSTRING(ChangeA, 0, CHARINDEX('<br />', ChangeA)) + '</root>' AS XML)
FROM
(
SELECT *, ChangeA = SUBSTRING(Changes, CHARINDEX('<span class="fieldname">Status</span>', Changes), 4000)
FROM ChangeTracker
WHERE CHARINDEX('<span class="fieldname">Status</span>', Changes) > 0
) TTX
) TT
) x
这给了我以下结果:
ChangeId | ChangeDate | FieldName | OldValue | NewValue
————————————————————————————————————————————————————————————————————
1 | 2016-06-28 18:37:24.403 | Status | new | open
现在我想要一个获得所有更改的查询(创建一个视图)。所以输出看起来像这样:
ChangeId | ChangeDate | FieldName | OldValue | NewValue
————————————————————————————————————————————————————————————————————
1 | 2016-06-28 18:37:24.403 | AssignedTo | user1 | user2
1 | 2016-06-28 18:37:24.403 | Attachments | NULL | NULL
1 | 2016-06-28 18:37:24.403 | Status | new | open
1 | 2016-06-28 18:37:24.403 | Priority | low | high
答案 0 :(得分:2)
将<br />
作为分隔符非常好。这样你就可以得到你想要的东西。
;with tbl as (
select ChangeId,ChangeDate,
--build xml
cast('<root><rec>'+replace(Changes,'<br />','</rec><rec>')+'</rec></root>' as xml) x
from ChangeTracker
)
select ChangeId, ChangeDate,
t.v.value('span[@class="fieldname"][1]','varchar(50)') fieldname,
t.v.value('span[@class="oldvalue"][1]','varchar(50)') oldvalue,
t.v.value('span[@class="newvalue"][1]','varchar(50)') newvalue
from tbl cross apply tbl.x.nodes('root/rec') t(v) --convert to tabular form
where t.v.value('span[@class="fieldname"][1]','varchar(50)') is not null
答案 1 :(得分:2)
我们可以通过逗号分割方法来做。在这里,我们只需要将字符串拆分为“&lt; br /&gt;”。
例如: -
SELECT CAST(item AS XML)
FROM dbo.SplitString(@str, '<br />') AS [Changes]
WHERE LEN(item) > 0
<强>结果: - 强> Result
因此,最终的查询将是: -
INSERT INTO ChangeTracker
SELECT GETDATE()
,tb.xmldata.value('(/span[@class="fieldname"]/text())[1]', 'varchar(255)') AS fieldName
,tb.xmldata.value('(/span[@class="oldvalue"]/text())[1]', 'varchar(255)') AS oldValue
,tb.xmldata.value('(/span[@class="newvalue"]/text())[1]', 'varchar(255)') AS newValue
FROM(
SELECT CAST(Item AS XML) AS xmldata
FROM dbo.SplitString(@str, '<br />') AS [Changes]
WHERE LEN(item) > 0
) AS tb
最终结果: - Final Result
注意: - 您需要创建分割功能,请在下面找到.BEGIN
CREATE FUNCTION SplitString
(
@Input NVARCHAR(MAX),
@Character NVARCHAR(10)
)
RETURNS @Output TABLE (
Item NVARCHAR(1000)
)
AS
BEGIN
DECLARE @StartIndex INT, @EndIndex INT
SET @StartIndex = 1
IF SUBSTRING(@Input, LEN(@Input) - 1, LEN(@Input)) <> @Character
BEGIN
SET @Input = @Input + @Character
END
WHILE CHARINDEX(@Character, @Input) > 0
BEGIN
SET @EndIndex = CHARINDEX(@Character, @Input)
INSERT INTO @Output(Item)
SELECT SUBSTRING(@Input, @StartIndex, @EndIndex - 1)
SET @Input = SUBSTRING(@Input, @EndIndex + LEN(@Character), LEN(@Input))
END
RETURN
END