【发布时间】:2021-02-09 20:56:14
【问题描述】:
我有一个类似于下面的数据集(还有更多列,但仅将这些列用于示例目的)。
| PersonId | LocationId | StartDate | AttendanceString |
|---|---|---|---|
| 123 | 987 | 2018-09-01 | XXXXZZZZ######PPLL |
| 234 | 678 | 2018-10-01 | PPPPLL######ZZZZXX |
我需要实现的是将 AttendanceString 列拆分为多行和多列。考勤字符串需要每 2 个字符分解一次,并分成 2 个不同的列,分别代表一个上午和下午的时段。一个例子会让这个更清楚,所以让我们使用第一条记录。期望的结果是:
| PersonId | LocationId | StartDate | MorningAttendanceString | AfternoonAttendanceString |
|---|---|---|---|---|
| 123 | 987 | 2018-09-01 | X | X |
| 123 | 987 | 2018-09-02 | X | X |
| 123 | 987 | 2018-09-03 | Z | Z |
| 123 | 987 | 2018-09-04 | Z | Z |
| 123 | 987 | 2018-09-05 | # | # |
对于每个字符串,我们需要迭代直到到达最后一个字符,将新记录添加到对应于不同日期的表中,并为早上/下午分别记录。
我能够使用本文末尾的代码实现所需的逻辑。但是,因为这可能涉及大约 90/100k 条记录,并且其中大部分需要分解为 365 条记录,所以我们谈论的是需要创建 33-35M 条记录。我正在使用带有一段时间循环的游标来获得这些结果,即使通常要避免使用游标,我也不认为这是这里的问题。这通常需要大约 30 分钟才能在 S6 标准层中的 Azure SQL 数据库上运行。
我是否缺少任何选项来提高效率?理想情况下,我想减少处理数据所需的时间。我不能真正使用 split_string,因为它需要一个特定的字符来破坏字符串。
DECLARE @LocationID as int;
DECLARE @AttendanceString as varchar(1000);
DECLARE @StartDate as date;
DECLARE @PersonId as int;
DECLARE @MorningValue as char(1);
DECLARE @AfternoonValue as char(1);
DECLARE @DayDate as date;
DECLARE @AttendanceCursor as cursor;
DECLARE @i as int;
SET @AttendanceCursor = CURSOR LOCAL FAST_FORWARD FOR
SELECT
PersonId,
LocationId,
StartDate,
AttendanceString
FROM
SourceTable
WHERE
StartDate >= '2019-08-01'
BEGIN
SET NOCOUNT ON
OPEN @AttendanceCursor
FETCH NEXT FROM @AttendanceCursor INTO @PersonId , @AttendanceString, @StartDate, @LocationId;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @i = 1;
SET @DayDate = @StartDate;
WHILE (@i < len(@AttendanceString))
BEGIN
SET @MorningValue = SUBSTRING(@AttendanceString,@i,1);
SET @AfternoonValue = SUBSTRING(@AttendanceString,@i+1,1);
BEGIN TRY
INSERT INTO FinalTable
SELECT @DayDate , @LocationId, @PersonId, @MorningValue @AfternoonValue
END TRY
BEGIN CATCH
...
END CATCH
SET @i = @i+2;
SET @DayDate = DATEADD(DD,1,@DayDate );
END
FETCH NEXT FROM @AttendanceCursor INTO @PersonId , @AttendanceString, @StartDate, @LocationId;
END
CLOSE @AttendanceCursor ;
DEALLOCATE @AttendanceCursor ;
【问题讨论】:
-
AttendanceString的长度是固定的还是可变的? -
游标解决方案刚刚在同一台服务器上完成了 1 小时 26 分钟。
SELECT ...INTO在我的服务器上在 2 秒内完成。这对我来说似乎是一个重大改进。 -
不固定,可以有不同的长度,一般在730个字符左右
标签: sql sql-server azure-sql-database