我有一个嵌套循环,用于检查表descript
中tmp13
列的所有名称和日期,并将它们作为单独的行存储在其他表(tmp14
)中。问题是while循环执行了很长时间。我不知道如何使其运行更快。我已经尝试了上一篇文章中的一些建议,但是我并不是很成功。任何人都可以提出一些建议来解决这个可怕的问题。
这是我的代码,检查descript
列中的名称和日期。 Descript
是一个文本列,可以有多个名称和日期。我想将这些名称和日期存储在单独的行中。
DECLARE @Id INT
DECLARE @count INT
DECLARE @product_num INT
DECLARE @REQUESTED VARCHAR(50)
DECLARE @FirstDate VARCHAR(255)
DECLARE @RequestedBy VARCHAR(255)
DECLARE @name NVARCHAR(256)
DECLARE @date NVARCHAR(256)
DECLARE @desc NVARCHAR(256)
DECLARE @dateposition INT
DECLARE @nameposition INT
DECLARE @nameend INT
SELECT @count = MAX(id)
FROM #TMP13
SET @id = 1;
WHILE (@id <= @count)
BEGIN
SELECT @desc = descript FROM #TMP13 WHERE Id = @Id
SELECT @product_num = p_Num FROM #TMP13 WHERE Id = @Id
SELECT @REQUESTED = REQUESTED FROM #TMP13 WHERE Id = @Id
SELECT @FirstDate = DATE1 FROM #TMP13 WHERE Id = @Id
SELECT @RequestedBy = BY1 FROM #TMP13 WHERE Id = @Id
while (patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9][0-9]%',@desc) > 0)
begin
set @dateposition = patindex('%[0-9][0-9]/[0-9][0-9]/[0-9][0-9][0-9]%',@desc)
set @date = SUBSTRING(@desc,@dateposition,10)
set @nameposition = CHARINDEX('-', @desc)+2
set @nameend = CHARINDEX(' ', @desc, @nameposition)+1
set @name = SUBSTRING(@desc,@nameposition,@nameend-@nameposition)
insert into #TMP14
values (@Id,@product_num,@REQUESTED, @FirstDate ,@RequestedBY, @date, @name)
set @desc = SUBSTRING(@desc,@nameend,1024)
end
set @id = @id + 1;
end
select * from #tmp14;
---样本表
CREATE TABLE #Tmp13(
p_Num INTEGER NOT NULL PRIMARY KEY
REQUESTED varchar(50),
DATE1 VARCHAR(50),
BY1 VARCHAR(50),
DESCRIPT TEXT
);
INSERT INTO #tmp13 (p_Num, REQUESTED, DATE1, BY1, DESCRIPT)
VALUES (100, 'John', '5/30/2017', 'James', '05/30/2017 12:25am Eastern Standard Time - Mjames reported changes in the pages 05/30/2017 10:35AM JRachael agreed to work on the report and report to James 05/30/2017 10:00 AM James reports errors in page.',NULL);
INSERT INTO #tmp13(WO_NUM, Opendate, ClosedDate, Note)
VALUES (200, 'John', '6/1/2017', 'Rachael', '06/1/2017 3:20PM Eastern Standard Time - Rsubramaniam reported phone is not functional 06/1/2017 4:00PM Service took the phone and replaced it with new one');
输出:
Id product_num REQUESTED FirstDate RequestedBY date name date Name
1 100 John 5/30/2017 james 5/30/2017 mjames 5/30/2017 jRachael
答案 0 :(得分:0)
这是一个选项。如果它遵循一致的格式,则仅查看解析列中的多个日期和名称。您需要进行调整以适合您的解决方案。还有...
这仅适用于以下情况:
- 日期和名称以一致且可重复的格式存储在DESCRIPT字段中,例如:“ dd / mm / yyyy时区-名称文本dd / mm / yyyy 时区-名称文字dd / mm / yyyy时区-名称文字“
我不确定这会给您带来什么样的效果,并且如果该字段中日期和名称的存储格式发生变化,它将无法正常工作。这就是了解格式是否一致和可重复的重要性。
在示例中,我们基本上是将阶段分为单个单词,然后进行过滤以获取所需内容。根据SQL Server的版本,我提供了两个不同的选项来实现拆分。
没有太多示例数据,但是根据您的评论和答复,我正在做一些假设,您可能需要根据您的特定需求进行调整。
这是一个例子:
DECLARE @tmp13 TABLE
(
[p_Num] INTEGER NOT NULL
, [DESCRIPT] NVARCHAR(MAX)
PRIMARY KEY([p_Num])
);
DECLARE @tmp13Parse TABLE
(
[Id] INT
, [Position] BIGINT
, [Value] NVARCHAR(500)
unique clustered ([Id], [Position])
);
--insert test data
INSERT INTO @tmp13 (
[p_Num]
, [DESCRIPT]
)
VALUES ( 100
, '05/30/2017 12:25am Eastern Standard Time - Mjames reported changes in the pages 05/30/2017 10:35AM Eastern Standard Time - JRachael agreed to work on the report and report to James 05/30/2017 10:00AM Eastern Standard Time - James reports errors in page.' )
, ( 200
, '05/29/2017 12:25am Central Stanard Time - TSmith reported changes in the pages 05/29/2017 10:35AM Central Stanard Time - JRachael agreed to work on the report and report to James 05/29/2017 10:00AM Central Stanard Time - GregNoName reports errors in page.' )
, ( 300
, '05/28/2017 12:25am Eastern Standard Time - Mjames reported changes in the pages 05/28/2017 10:35AM Eastern Standard Time - JName agreed to work on the report and report to James 05/28/2017 10:00AM Eastern Standard Time - James reports errors in page.' )
, ( 400
, '05/27/2017 12:25am Central Stanard Time - Mjames reported changes in the pages 05/27/2017 10:35AM Central Stanard Time - JRachael agreed to work on the report and report to James 05/27/2017 10:00AM Eastern Standard Time - AnotherName reports errors in page.' )
, ( 500
, '05/26/2017 12:25am Eastern Standard Time - MJohnson reported changes in the pages 05/26/2017 10:35AM Eastern Standard Time - FTestname agreed to work on the report and report to James 05/26/2017 10:00AM Eastern Standard Time - James reports errors in page.' )
, ( 600
, '05/25/2017 12:25am Eastern Standard Time - Mjames reported changes in the pages 05/25/2017 10:35AM Eastern Standard Time - JRachael agreed to work on the report and report to James 05/25/2017 10:00AM Eastern Standard Time - James reports errors in page.' )
, ( 700
, '05/24/2017 12:25am Eastern Standard Time - TTaylor reported changes in the pages 05/24/2017 10:35AM Eastern Standard Time - JRachael agreed to work on the report and report to James 05/24/2017 10:00AM Eastern Standard Time - TMoreTestNames reports errors in page.' );
--Basically what we are doing is loading a table with each individual word making sure we keep which Id it was associated with.
--along with the Position of where it was in the phrase.
--Two options below depending on SQL Version.
--SQL Version 2016+, we'll use SPLIT_STRING, code is a little more easier
INSERT INTO @tmp13Parse (
[Id]
, [Position]
, [Value]
)
SELECT [a].[p_Num]
, [b].[Position]
, [b].[Value]
FROM @tmp13 [a]
CROSS APPLY (
SELECT [Value]
, ROW_NUMBER() OVER ( ORDER BY (
SELECT 1
)
) AS [Position]
FROM STRING_SPLIT([a].[DESCRIPT], ' ') --this will handle returning a table based on how you split it, in this case a space.
) AS [b];
--Prior to SQL Version 2016 back to 2012, use this option which is using a XML to split the data.
INSERT INTO @tmp13Parse (
[Id]
, [Position]
, [Value]
)
SELECT [a].[p_Num]
, [ss].[Position]
, [ss].[Value]
FROM @tmp13 [a]
CROSS APPLY (
SELECT ROW_NUMBER() OVER ( ORDER BY (SELECT 1)) AS [Position]
, [y].[i].[value]('(./text())[1]', 'nvarchar(max)') AS [Value]
FROM (
SELECT [x] = CONVERT(XML, '<i>'+ REPLACE([a].[DESCRIPT], ' ', '</i><i>')+ '</i>').[query]('.')
) AS [a]
CROSS APPLY [x].[nodes]('i') AS [y]([i])
) AS [ss];
--After we have split the data we'll now go after the specific values
SELECT [a].[Id]
, [a].[Value] AS [Date]
, [ccc].[Value] AS [Name]
FROM @tmp13Parse [a]
--First cross apply - what is the position of '-' after my date field. add 1 since the next value should be the name I'm after.
CROSS APPLY (
SELECT MIN([aa].[Position]) + 1 AS [nameAnchorPosition]
FROM @tmp13Parse [aa]
WHERE [aa].[Id] = [a].[Id]
AND [aa].[Value] = '-'
AND [aa].[Position] > [a].[Position]
) AS [bb]
--Second cross apply - Now, based on where I identified '-' to be, plus 1, give me that value.
CROSS APPLY (
SELECT [cc].[Value]
FROM @tmp13Parse [cc]
WHERE [cc].[Id] = [a].[Id]
AND [cc].[Position] = [bb].[nameAnchorPosition]
) AS [ccc]
WHERE TRY_CONVERT(DATE, [a].[Value]) > '1900-01-01'; --will return all those values that are a date as starting point, long with their position.
我使用记录和解析的两个选项对记录为54000的一台服务器进行了快速测试,并且都在4-10秒内给出了结果。您的里程可能会有所不同。