规范化 SQL 表 - 将 1 行转换为 6 行 [关闭]
Posted
技术标签:
【中文标题】规范化 SQL 表 - 将 1 行转换为 6 行 [关闭]【英文标题】:Normalize a SQL table - convert 1 row to 6 rows [closed] 【发布时间】:2020-10-19 12:47:36 【问题描述】:我有一个表格,其中填充了来自需要标准化的制造系统的数据。此暂存表有一个关键字段 - LOTCODE - 加上 6 个 PARTSTATUS 字段,以及 PART1、PART2 等的状态代码 (INT)。
我想每隔一小时查询临时表,并为找到的每一行将 6 行插入存档表,该存档表将包含关键字段 LOTCODE 和 PARTLOCATION 以及第三个字段 PARTSTATUS。将数据插入存档表后,临时表中的行将被删除。
有没有办法只用查询来做到这一点,还是我需要逐行遍历暂存表,在存档表中插入 6 行,然后删除原始行?
数据库是 MS SQL 2016。制造系统每小时将向临时表添加大约 1440 行。
暂存表示例行:
Lot, Part1Status, Part2Status, Part3Status, Part4Status, Part5Status, Part6Status
ABCDE, 1010, 1010, -50, 1010, 990, 1010
存档表示例数据
Lot, PartLocation, Stats
ABCDE, 1, 1010
ABCDE, 2, 1010
ABCDE, 3, -50
ABCDE, 4, 1010
ABCDE, 5, 990
ABCDE, 6, 1010
【问题讨论】:
请提供样本数据和期望的结果。这听起来像是一些非常简单的insert
操作。
此操作称为“反透视”。有很多方法可以做到——UNPIVOT
子句、CROSS APPLY
、...
@Jpoole 。 . .为什么要删除临时表中的行?这似乎是不必要的开销。
在归档表中标准化后,没有理由保留未标准化的数据。将有数百万行也会浪费空间。
【参考方案1】:
这是一个TRY/CATCH
脚本,它在显式事务中执行INSERT
和DELETE
语句,其中XACT_ABORT
已设置为ON
,可确保在发生异常时完全回滚两个DML 语句被抛出。像这样的
set nocount on;
set xact_abort on;
begin transaction
begin try
declare @lc table(LOTCODE int unique not null);
insert ArchiveTable(Lot, PartLocation, [Stats])
output inserted.LOTCODE into @lc
select LOTCODE, v.(
from StagingTable st
cross apply (values (1, st.Part1Status),
(2, st.Part2Status),
(3, st.Part3Status),
(4, st.Part4Status),
(5, st.Part5Status),
(6, st.Part6Status)) v(PARTLOCATION, [STATS]);
delete st
from StagingTable st
join @lc lc on st.LOTCODE=lc.LOTCODE;
commit transaction;
end try
begin catch
/* throw / raiserror / logging */
rollback transaction;
end catch
【讨论】:
使用 Cross Apply 与 UnPivot 有什么优势吗? CROSS APPLY 的优势在于它更像是跨 SQL 的标准实现,对我来说它比 UNPIVOT 更直观和可读。就像堆砖一样 问题 - 我可以在触发器后使用插入而不是每小时从暂存表批量转换到存档表吗?将数据插入存档表,然后删除新的暂存记录。对临时表进行插入的系统会看到错误,还是“认为”插入成功? 是的,您可以使用触发器。根据其编码方式,它不会干扰现有流程以上是关于规范化 SQL 表 - 将 1 行转换为 6 行 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章