字符串解析 VARCHAR 列
String Parsing VARCHAR Column
我正在使用一个数据库,在这个数据库中,phone 调用用户与客户端的位置被保存到单个 VARCHAR(MAX) 列中。但是,出于详细报告目的 (SSRS),嵌入 VARCHAR 列中的所有各种属性都需要转换为单独的列。为完成此解析,我在存储过程中使用游标,该过程调用处理所需子字符串提取的 UDF。
当查询的行数比较少的时候(不超过几百行),查询的性能还是不错的。但是,当查询大量行(几千行)时,性能很糟糕,查询经常会超时。所以,我正在寻找一种比我现有的方法扩展性更好的方法。
VARCHAR 列包含完整的 HTML 标记。我删除了不相关的内容以说明我感兴趣的数据是如何存储的:
<table>
<tr>
<td class="key">Dial Result:</td><td id="DialResult" class="value">No Answer</td></tr>
<tr><td class="key">Client Name:</td><td id="ClientName" class="value">SMITH, BOB</td></tr>
<tr><td class="key">Number Dialed:</td><td id="NumberDialed" class="value">5555555555 [Day]</td></tr>
<tr><td class="key">Dial Count:</td><td id="DialCount" class="value">1</td></tr><tr><td class="key">Contact Made:</td><td id="ContactMade" class="value">No</td></tr>
<tr><td class="key">Campaign Called On:</td><td id="CampaignCalledOn" class="value">TEST CAMPAIGN</td></tr>
<tr><td class="key">Call Outcome:</td><td id="CallOutcome" class="value">No answer</td></tr>
<tr><td class="key">Email Sent:</td><td id="EmailSent" class="value">No</td></tr>
<tr><td class="key">Do Not Call Requested:</td><td id="DoNotCallRequested" class="value">No</td></tr>
<tr><td class="key">Product Purchased:</td><td id="ProductPurchased" class="value">No</td></tr>
<tr><td class="key">Order Number:</td><td id="OrderNumber" class="value">N/A</td></tr><tr><td class="key">Order Dollar Value:</td><td id="PurchaseAmount" class="value">0.00</td></tr>
<tr><td class="key">Purchased SKUs:</td><td id="PurchasedSKUs" class="value">N/A</td></tr>
</table>
目前,我有一个存储过程,它使用游标遍历 "live" 数据库 table 中的行。过程光标如下所示:
OPEN MainNoteCursor;
FETCH NEXT FROM MainNoteCursor INTO @SequenceNumber,@ClientId,@ContactNumber,@UserDisplayName,@CreatorId,@DateCol,@NoteText
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN TRY
DECLARE @NoteDate date = null
DECLARE @DialResult varchar(255) = null
DECLARE @ClientName varchar(255) = null
DECLARE @NumberDialed varchar(255) = null
DECLARE @DialCount int = null
DECLARE @ContactMade varchar(3) = null
DECLARE @CampaignCalledOn varchar(255) = null
DECLARE @CallOutcome varchar(255) = null
DECLARE @EmailSent varchar(3) = null
DECLARE @DoNotCallRequested varchar(3) = null
DECLARE @ProductPurchased varchar(3) = null
DECLARE @OrderNumber varchar(255) = null
DECLARE @PurchaseAmount money = null
DECLARE @PurchasedSKUs varchar(255) = null
SET @NoteDate = CONVERT(date, @DateCol)
SET @DialResult = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="DialResult" class="value">'',''</td>'',1)
SET @ClientName = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="ClientName" class="value">'',''</td>'',1)
SET @NumberDialed = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="NumberDialed" class="value">'',''</td>'',1)
SET @DialCount = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="DialCount" class="value">'',''</td>'',1)
SET @ContactMade = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="ContactMade" class="value">'',''</td>'',1)
SET @CampaignCalledOn = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="CampaignCalledOn" class="value">'',''</td>'',1)
SET @CallOutcome = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="CallOutcome" class="value">'',''</td>'',1)
SET @EmailSent = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="EmailSent" class="value">'',''</td>'',1)
SET @DoNotCallRequested = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="DoNotCallRequested" class="value">'',''</td>'',1)
SET @ProductPurchased = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="ProductPurchased" class="value">'',''</td>'',1)
SET @OrderNumber = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="OrderNumber" class="value">'',''</td>'',1)
SET @PurchaseAmount = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="PurchaseAmount" class="value">'',''</td>'',1)
SET @PurchasedSKUs = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="PurchasedSKUs" class="value">'',''</td>'',1)
INSERT INTO @Return
([SequenceNumber],[ClientId],[ContactNumber],[UserDisplayName],[CreatorId],
[DateCol],[NoteDate],[NoteText],[DialResult],[ClientName],[NumberDialed],[DialCount],
[ContactMade],[CampaignCalledOn],[CallOutcome],[EmailSent],[DoNotCallRequested],
[ProductPurchased],[OrderNumber],[PurchaseAmount],[PurchasedSKUs])
VALUES
(@SequenceNumber,@ClientId,@ContactNumber,@UserDisplayName,@CreatorId,
@DateCol,@NoteDate,@NoteText,@DialResult,@ClientName,@NumberDialed,@DialCount,
@ContactMade,@CampaignCalledOn,@CallOutcome,@EmailSent,@DoNotCallRequested,
@ProductPurchased,@OrderNumber,@PurchaseAmount,@PurchasedSKUs)
END TRY
BEGIN CATCH
--Nothing to do.
END CATCH
FETCH NEXT FROM MainNoteCursor INTO @SequenceNumber,@ClientId,@ContactNumber,@UserDisplayName,@CreatorId,@DateCol,@NoteText
END
CLOSE MainNoteCursor;
DEALLOCATE MainNoteCursor;
SELECT * FROM @Return
所以,你可以看到光标每次都在解析完整的笔记正文,提取两个字符串分隔符之间的值,将值插入到table,然后返回table .
在 SSMS 中执行时,我得到如下所示的结果:
FN_PARSE_TEXT 中的代码使用 CHARINDEX()、LEN()、SUBSTRING() 等来读取 "Start string" 和 "end string" 之间的文本。我不会 post 完整的功能,因为有很多不相关的内务处理代码,但可以提炼为:
--********************************************************************************
-- CHARINDEX returns the position of the fist character in @StartKey, but we need to
-- start reading after the *last* character in @StartKey. Re-adjust the position
-- at which we''ll start reading the string.
--********************************************************************************
SET @StartKeyIndex = @StartKeyIndex + @StartKeyLength
SET @ReadLength = @EndKeyIndex - @StartKeyIndex
--********************************************************************************
-- Start / End positions have been determined, so now read out the calculated number
-- of characters and return to the calling code.
--********************************************************************************
SET @ReturnValue = LTRIM(RTRIM(SUBSTRING(@noteText, @StartKeyIndex, @ReadLength)))
因此,在了解所有这些背景信息之后(如果需要,我可以提供更多详细信息),我正在寻找更好的方法。
我考虑过创建一个夜间批处理过程,在下班时间进行所有解析,然后将数据转储到扁平化 table 中。然后我会报告扁平化的数据,而不是试图实时解析细节。当然,这打开了它自己的蠕虫罐头,理想情况下我想继续点击实时数据。根据用户在 运行 查询时提供的日期范围,可能会返回超过 10,000 行。
我想到的另一种选择是使用 CLR 方法来处理循环和解析 - 但我在这方面没有太多经验,而且我不确定这是否比我现在在做什么。
我读过一些文章(例如,https://sqlperformance.com/2012/07/t-sql-queries/split-strings),讨论诸如 CTE 之类的事情,但我在这方面的经验并不多,所以我不确定如何实现这一飞跃。我读过的大多数 "string parsing" 文章都针对定界符相同的场景——比如解析逗号分隔的字符串。但是因为我有 "rolling" 个分隔符,所以我不确定如何处理它。
无论如何,如果您仍然和我在一起,我们将不胜感激。
如果您可以修改数据库,我会尽我所能避免在查询时进行此解析。特别是如果这是一个用户经常执行的查询,例如 CRM 应用程序。
我要么将所有这些经常选择的列添加到我的 table,要么为它们创建一个单独的 table,可以链接到这个 [=26] 的主键=].
然后,理想情况下,我会在插入时填充这些列。最好让 INSERT 通过存储过程,但如有必要,可以在 table.
上放置一个插入触发器
如果我不能在 INSERT 时执行此操作,那么我会 运行 执行解析并尽可能频繁地填充列的作业 requires/allows。
对于大多数 CRM 应用程序,SELECT 性能比 INSERT 性能更重要,因为它影响多行,而 INSERTS 通常一次发生一个。因此,如果可能的话,我会尝试将性能负担转移到那里。
免责声明:我从未使用过 Xedni 在其评论中提到的 XML 函数。所以我不能说我的建议和他的建议之间的性能差异是什么。
只是为了提供一个具体示例,说明如何使用 XML 执行此操作,以下是我的操作方法。我这里只有一份示例文档,但如果您有多个,同样适用。您只需为每个主键返回多行。
;with src (Id, NoteText) as
(
select 1, cast('<table>
<tr>
<td class="key">Dial Result:</td><td id="DialResult" class="value">No Answer</td></tr>
<tr><td class="key">Client Name:</td><td id="ClientName" class="value">SMITH, BOB</td></tr>
<tr><td class="key">Number Dialed:</td><td id="NumberDialed" class="value">5555555555 [Day]</td></tr>
<tr><td class="key">Dial Count:</td><td id="DialCount" class="value">1</td></tr><tr><td class="key">Contact Made:</td><td id="ContactMade" class="value">No</td></tr>
<tr><td class="key">Campaign Called On:</td><td id="CampaignCalledOn" class="value">TEST CAMPAIGN</td></tr>
<tr><td class="key">Call Outcome:</td><td id="CallOutcome" class="value">No answer</td></tr>
<tr><td class="key">Email Sent:</td><td id="EmailSent" class="value">No</td></tr>
<tr><td class="key">Do Not Call Requested:</td><td id="DoNotCallRequested" class="value">No</td></tr>
<tr><td class="key">Product Purchased:</td><td id="ProductPurchased" class="value">No</td></tr>
<tr><td class="key">Order Number:</td><td id="OrderNumber" class="value">N/A</td></tr><tr><td class="key">Order Dollar Value:</td><td id="PurchaseAmount" class="value">0.00</td></tr>
<tr><td class="key">Purchased SKUs:</td><td id="PurchasedSKUs" class="value">N/A</td></tr>
</table>' as xml)
)
select
a.*,
t.c.value('td[1]', 'varchar(max)')
from src a
cross apply a.NoteText.nodes('table/tr') as t(c)
XML 在 SQL 中分解的文档可能会有点乱七八糟,主要是因为 SQL 正在实现独立于 SQL 和 Microsoft 的 xquery。也就是说,对于做基本的事情,通常 MSDN 文档可以让你很好地开始。
这里有几篇好文章
您可以使用 XML 转换您的值,然后在转换结果后
DECLARE @xml xml = '<table>
<tr>
<td class="key">Dial Result:</td><td id="DialResult" class="value">No Answer</td></tr>
<tr><td class="key">Client Name:</td><td id="ClientName" class="value">SMITH, BOB</td></tr>
<tr><td class="key">Number Dialed:</td><td id="NumberDialed" class="value">5555555555 [Day]</td></tr>
<tr><td class="key">Dial Count:</td><td id="DialCount" class="value">1</td></tr><tr><td class="key">Contact Made:</td><td id="ContactMade" class="value">No</td></tr>
<tr><td class="key">Campaign Called On:</td><td id="CampaignCalledOn" class="value">TEST CAMPAIGN</td></tr>
<tr><td class="key">Call Outcome:</td><td id="CallOutcome" class="value">No answer</td></tr>
<tr><td class="key">Email Sent:</td><td id="EmailSent" class="value">No</td></tr>
<tr><td class="key">Do Not Call Requested:</td><td id="DoNotCallRequested" class="value">No</td></tr>
<tr><td class="key">Product Purchased:</td><td id="ProductPurchased" class="value">No</td></tr>
<tr><td class="key">Order Number:</td><td id="OrderNumber" class="value">N/A</td></tr><tr><td class="key">Order Dollar Value:</td><td id="PurchaseAmount" class="value">0.00</td></tr>
<tr><td class="key">Purchased SKUs:</td><td id="PurchasedSKUs" class="value">N/A</td></tr>
</table>'
Select
Tbl.Col.value('@id','varchar(max)') Id
,Tbl.Col.value('.','varchar(max)') Value
FRom
@xml.nodes('/table/tr/td[@class="value"]') Tbl(Col)
SELECT
DialResult
,ClientName
,NumberDialed
,DialCount
,ContactMade
,CampaignCalledOn
,CallOutcome
,EmailSent
,DoNotCallRequested
,ProductPurchased
,OrderNumber
,PurchaseAmount
,PurchasedSKUs
FROM
(
Select
Tbl.Col.value('@id','varchar(max)') Id
,Tbl.Col.value('.','varchar(max)') Value
FRom
@xml.nodes('/table/tr/td[@class="value"]') Tbl(Col) ) T Pivot
(Max(Value) FOR Id In(DialResult
,ClientName
,NumberDialed
,DialCount
,ContactMade
,CampaignCalledOn
,CallOutcome
,EmailSent
,DoNotCallRequested
,ProductPurchased
,OrderNumber
,PurchaseAmount
,PurchasedSKUs)) p;
第一个结果 select
Id Value
-------------------------------------------------- --------------------------------------------------
DialResult No Answer
ClientName SMITH, BOB
NumberDialed 5555555555 [Day]
DialCount 1
ContactMade No
CampaignCalledOn TEST CAMPAIGN
CallOutcome No answer
EmailSent No
DoNotCallRequested No
ProductPurchased No
OrderNumber N/A
PurchaseAmount 0.00
PurchasedSKUs N/A
第二个结果 select
DialResult ClientName NumberDialed DialCount ContactMade CampaignCalledOn CallOutcome EmailSent DoNotCallRequested ProductPurchased OrderNumber PurchaseAmount PurchasedSKUs
-------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- --------------------------------------------------
No Answer SMITH, BOB 5555555555 [Day] 1 No TEST CAMPAIGN No answer No No No N/A 0.00 N/A
(1 row(s) affected)
我正在使用一个数据库,在这个数据库中,phone 调用用户与客户端的位置被保存到单个 VARCHAR(MAX) 列中。但是,出于详细报告目的 (SSRS),嵌入 VARCHAR 列中的所有各种属性都需要转换为单独的列。为完成此解析,我在存储过程中使用游标,该过程调用处理所需子字符串提取的 UDF。
当查询的行数比较少的时候(不超过几百行),查询的性能还是不错的。但是,当查询大量行(几千行)时,性能很糟糕,查询经常会超时。所以,我正在寻找一种比我现有的方法扩展性更好的方法。
VARCHAR 列包含完整的 HTML 标记。我删除了不相关的内容以说明我感兴趣的数据是如何存储的:
<table>
<tr>
<td class="key">Dial Result:</td><td id="DialResult" class="value">No Answer</td></tr>
<tr><td class="key">Client Name:</td><td id="ClientName" class="value">SMITH, BOB</td></tr>
<tr><td class="key">Number Dialed:</td><td id="NumberDialed" class="value">5555555555 [Day]</td></tr>
<tr><td class="key">Dial Count:</td><td id="DialCount" class="value">1</td></tr><tr><td class="key">Contact Made:</td><td id="ContactMade" class="value">No</td></tr>
<tr><td class="key">Campaign Called On:</td><td id="CampaignCalledOn" class="value">TEST CAMPAIGN</td></tr>
<tr><td class="key">Call Outcome:</td><td id="CallOutcome" class="value">No answer</td></tr>
<tr><td class="key">Email Sent:</td><td id="EmailSent" class="value">No</td></tr>
<tr><td class="key">Do Not Call Requested:</td><td id="DoNotCallRequested" class="value">No</td></tr>
<tr><td class="key">Product Purchased:</td><td id="ProductPurchased" class="value">No</td></tr>
<tr><td class="key">Order Number:</td><td id="OrderNumber" class="value">N/A</td></tr><tr><td class="key">Order Dollar Value:</td><td id="PurchaseAmount" class="value">0.00</td></tr>
<tr><td class="key">Purchased SKUs:</td><td id="PurchasedSKUs" class="value">N/A</td></tr>
</table>
目前,我有一个存储过程,它使用游标遍历 "live" 数据库 table 中的行。过程光标如下所示:
OPEN MainNoteCursor;
FETCH NEXT FROM MainNoteCursor INTO @SequenceNumber,@ClientId,@ContactNumber,@UserDisplayName,@CreatorId,@DateCol,@NoteText
WHILE (@@FETCH_STATUS <> -1)
BEGIN
IF (@@FETCH_STATUS <> -2)
BEGIN TRY
DECLARE @NoteDate date = null
DECLARE @DialResult varchar(255) = null
DECLARE @ClientName varchar(255) = null
DECLARE @NumberDialed varchar(255) = null
DECLARE @DialCount int = null
DECLARE @ContactMade varchar(3) = null
DECLARE @CampaignCalledOn varchar(255) = null
DECLARE @CallOutcome varchar(255) = null
DECLARE @EmailSent varchar(3) = null
DECLARE @DoNotCallRequested varchar(3) = null
DECLARE @ProductPurchased varchar(3) = null
DECLARE @OrderNumber varchar(255) = null
DECLARE @PurchaseAmount money = null
DECLARE @PurchasedSKUs varchar(255) = null
SET @NoteDate = CONVERT(date, @DateCol)
SET @DialResult = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="DialResult" class="value">'',''</td>'',1)
SET @ClientName = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="ClientName" class="value">'',''</td>'',1)
SET @NumberDialed = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="NumberDialed" class="value">'',''</td>'',1)
SET @DialCount = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="DialCount" class="value">'',''</td>'',1)
SET @ContactMade = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="ContactMade" class="value">'',''</td>'',1)
SET @CampaignCalledOn = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="CampaignCalledOn" class="value">'',''</td>'',1)
SET @CallOutcome = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="CallOutcome" class="value">'',''</td>'',1)
SET @EmailSent = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="EmailSent" class="value">'',''</td>'',1)
SET @DoNotCallRequested = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="DoNotCallRequested" class="value">'',''</td>'',1)
SET @ProductPurchased = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="ProductPurchased" class="value">'',''</td>'',1)
SET @OrderNumber = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="OrderNumber" class="value">'',''</td>'',1)
SET @PurchaseAmount = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="PurchaseAmount" class="value">'',''</td>'',1)
SET @PurchasedSKUs = [dbo].[FN_PARSE_TEXT] (@NoteText,''<TD id="PurchasedSKUs" class="value">'',''</td>'',1)
INSERT INTO @Return
([SequenceNumber],[ClientId],[ContactNumber],[UserDisplayName],[CreatorId],
[DateCol],[NoteDate],[NoteText],[DialResult],[ClientName],[NumberDialed],[DialCount],
[ContactMade],[CampaignCalledOn],[CallOutcome],[EmailSent],[DoNotCallRequested],
[ProductPurchased],[OrderNumber],[PurchaseAmount],[PurchasedSKUs])
VALUES
(@SequenceNumber,@ClientId,@ContactNumber,@UserDisplayName,@CreatorId,
@DateCol,@NoteDate,@NoteText,@DialResult,@ClientName,@NumberDialed,@DialCount,
@ContactMade,@CampaignCalledOn,@CallOutcome,@EmailSent,@DoNotCallRequested,
@ProductPurchased,@OrderNumber,@PurchaseAmount,@PurchasedSKUs)
END TRY
BEGIN CATCH
--Nothing to do.
END CATCH
FETCH NEXT FROM MainNoteCursor INTO @SequenceNumber,@ClientId,@ContactNumber,@UserDisplayName,@CreatorId,@DateCol,@NoteText
END
CLOSE MainNoteCursor;
DEALLOCATE MainNoteCursor;
SELECT * FROM @Return
所以,你可以看到光标每次都在解析完整的笔记正文,提取两个字符串分隔符之间的值,将值插入到table,然后返回table .
在 SSMS 中执行时,我得到如下所示的结果:
FN_PARSE_TEXT 中的代码使用 CHARINDEX()、LEN()、SUBSTRING() 等来读取 "Start string" 和 "end string" 之间的文本。我不会 post 完整的功能,因为有很多不相关的内务处理代码,但可以提炼为:
--********************************************************************************
-- CHARINDEX returns the position of the fist character in @StartKey, but we need to
-- start reading after the *last* character in @StartKey. Re-adjust the position
-- at which we''ll start reading the string.
--********************************************************************************
SET @StartKeyIndex = @StartKeyIndex + @StartKeyLength
SET @ReadLength = @EndKeyIndex - @StartKeyIndex
--********************************************************************************
-- Start / End positions have been determined, so now read out the calculated number
-- of characters and return to the calling code.
--********************************************************************************
SET @ReturnValue = LTRIM(RTRIM(SUBSTRING(@noteText, @StartKeyIndex, @ReadLength)))
因此,在了解所有这些背景信息之后(如果需要,我可以提供更多详细信息),我正在寻找更好的方法。
我考虑过创建一个夜间批处理过程,在下班时间进行所有解析,然后将数据转储到扁平化 table 中。然后我会报告扁平化的数据,而不是试图实时解析细节。当然,这打开了它自己的蠕虫罐头,理想情况下我想继续点击实时数据。根据用户在 运行 查询时提供的日期范围,可能会返回超过 10,000 行。
我想到的另一种选择是使用 CLR 方法来处理循环和解析 - 但我在这方面没有太多经验,而且我不确定这是否比我现在在做什么。
我读过一些文章(例如,https://sqlperformance.com/2012/07/t-sql-queries/split-strings),讨论诸如 CTE 之类的事情,但我在这方面的经验并不多,所以我不确定如何实现这一飞跃。我读过的大多数 "string parsing" 文章都针对定界符相同的场景——比如解析逗号分隔的字符串。但是因为我有 "rolling" 个分隔符,所以我不确定如何处理它。
无论如何,如果您仍然和我在一起,我们将不胜感激。
如果您可以修改数据库,我会尽我所能避免在查询时进行此解析。特别是如果这是一个用户经常执行的查询,例如 CRM 应用程序。
我要么将所有这些经常选择的列添加到我的 table,要么为它们创建一个单独的 table,可以链接到这个 [=26] 的主键=].
然后,理想情况下,我会在插入时填充这些列。最好让 INSERT 通过存储过程,但如有必要,可以在 table.
上放置一个插入触发器如果我不能在 INSERT 时执行此操作,那么我会 运行 执行解析并尽可能频繁地填充列的作业 requires/allows。
对于大多数 CRM 应用程序,SELECT 性能比 INSERT 性能更重要,因为它影响多行,而 INSERTS 通常一次发生一个。因此,如果可能的话,我会尝试将性能负担转移到那里。
免责声明:我从未使用过 Xedni 在其评论中提到的 XML 函数。所以我不能说我的建议和他的建议之间的性能差异是什么。
只是为了提供一个具体示例,说明如何使用 XML 执行此操作,以下是我的操作方法。我这里只有一份示例文档,但如果您有多个,同样适用。您只需为每个主键返回多行。
;with src (Id, NoteText) as
(
select 1, cast('<table>
<tr>
<td class="key">Dial Result:</td><td id="DialResult" class="value">No Answer</td></tr>
<tr><td class="key">Client Name:</td><td id="ClientName" class="value">SMITH, BOB</td></tr>
<tr><td class="key">Number Dialed:</td><td id="NumberDialed" class="value">5555555555 [Day]</td></tr>
<tr><td class="key">Dial Count:</td><td id="DialCount" class="value">1</td></tr><tr><td class="key">Contact Made:</td><td id="ContactMade" class="value">No</td></tr>
<tr><td class="key">Campaign Called On:</td><td id="CampaignCalledOn" class="value">TEST CAMPAIGN</td></tr>
<tr><td class="key">Call Outcome:</td><td id="CallOutcome" class="value">No answer</td></tr>
<tr><td class="key">Email Sent:</td><td id="EmailSent" class="value">No</td></tr>
<tr><td class="key">Do Not Call Requested:</td><td id="DoNotCallRequested" class="value">No</td></tr>
<tr><td class="key">Product Purchased:</td><td id="ProductPurchased" class="value">No</td></tr>
<tr><td class="key">Order Number:</td><td id="OrderNumber" class="value">N/A</td></tr><tr><td class="key">Order Dollar Value:</td><td id="PurchaseAmount" class="value">0.00</td></tr>
<tr><td class="key">Purchased SKUs:</td><td id="PurchasedSKUs" class="value">N/A</td></tr>
</table>' as xml)
)
select
a.*,
t.c.value('td[1]', 'varchar(max)')
from src a
cross apply a.NoteText.nodes('table/tr') as t(c)
XML 在 SQL 中分解的文档可能会有点乱七八糟,主要是因为 SQL 正在实现独立于 SQL 和 Microsoft 的 xquery。也就是说,对于做基本的事情,通常 MSDN 文档可以让你很好地开始。
这里有几篇好文章
您可以使用 XML 转换您的值,然后在转换结果后
DECLARE @xml xml = '<table>
<tr>
<td class="key">Dial Result:</td><td id="DialResult" class="value">No Answer</td></tr>
<tr><td class="key">Client Name:</td><td id="ClientName" class="value">SMITH, BOB</td></tr>
<tr><td class="key">Number Dialed:</td><td id="NumberDialed" class="value">5555555555 [Day]</td></tr>
<tr><td class="key">Dial Count:</td><td id="DialCount" class="value">1</td></tr><tr><td class="key">Contact Made:</td><td id="ContactMade" class="value">No</td></tr>
<tr><td class="key">Campaign Called On:</td><td id="CampaignCalledOn" class="value">TEST CAMPAIGN</td></tr>
<tr><td class="key">Call Outcome:</td><td id="CallOutcome" class="value">No answer</td></tr>
<tr><td class="key">Email Sent:</td><td id="EmailSent" class="value">No</td></tr>
<tr><td class="key">Do Not Call Requested:</td><td id="DoNotCallRequested" class="value">No</td></tr>
<tr><td class="key">Product Purchased:</td><td id="ProductPurchased" class="value">No</td></tr>
<tr><td class="key">Order Number:</td><td id="OrderNumber" class="value">N/A</td></tr><tr><td class="key">Order Dollar Value:</td><td id="PurchaseAmount" class="value">0.00</td></tr>
<tr><td class="key">Purchased SKUs:</td><td id="PurchasedSKUs" class="value">N/A</td></tr>
</table>'
Select
Tbl.Col.value('@id','varchar(max)') Id
,Tbl.Col.value('.','varchar(max)') Value
FRom
@xml.nodes('/table/tr/td[@class="value"]') Tbl(Col)
SELECT
DialResult
,ClientName
,NumberDialed
,DialCount
,ContactMade
,CampaignCalledOn
,CallOutcome
,EmailSent
,DoNotCallRequested
,ProductPurchased
,OrderNumber
,PurchaseAmount
,PurchasedSKUs
FROM
(
Select
Tbl.Col.value('@id','varchar(max)') Id
,Tbl.Col.value('.','varchar(max)') Value
FRom
@xml.nodes('/table/tr/td[@class="value"]') Tbl(Col) ) T Pivot
(Max(Value) FOR Id In(DialResult
,ClientName
,NumberDialed
,DialCount
,ContactMade
,CampaignCalledOn
,CallOutcome
,EmailSent
,DoNotCallRequested
,ProductPurchased
,OrderNumber
,PurchaseAmount
,PurchasedSKUs)) p;
第一个结果 select
Id Value
-------------------------------------------------- --------------------------------------------------
DialResult No Answer
ClientName SMITH, BOB
NumberDialed 5555555555 [Day]
DialCount 1
ContactMade No
CampaignCalledOn TEST CAMPAIGN
CallOutcome No answer
EmailSent No
DoNotCallRequested No
ProductPurchased No
OrderNumber N/A
PurchaseAmount 0.00
PurchasedSKUs N/A
第二个结果 select
DialResult ClientName NumberDialed DialCount ContactMade CampaignCalledOn CallOutcome EmailSent DoNotCallRequested ProductPurchased OrderNumber PurchaseAmount PurchasedSKUs
-------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- --------------------------------------------------
No Answer SMITH, BOB 5555555555 [Day] 1 No TEST CAMPAIGN No answer No No No N/A 0.00 N/A
(1 row(s) affected)