我需要在更新表时应用一些逻辑。
existing_items是目标表,received_items完全保存对existing_items或新项目的更新。
逻辑是 - 对于每个分组的received_items,应在existing_items中标识匹配的行。如果未找到匹配项,则应创建新行。
踢球者是行可以在多个条件上匹配。它们应始终匹配代码,line_no(如果给定),ref(如果给定)。 received_items行应该以processing_seq顺序处理,并且可能也按照给定的顺序检查匹配。
当所有已分组的received_items已与一个existing_item匹配时,任何余数都是新行。
假设:
create table #existing_items(id int identity(1,1), code varchar(10)
,qty numeric(10,2), line_no int, ref varchar(10))
create table #received_items(code varchar(10), qty numeric(10,2), line_no int
,ref varchar(10), processing_seq int)
insert into #existing_items (code, qty, line_no, ref)
values('ABC123',2.0, 1, NULL)
insert into #existing_items (code, qty, line_no, ref)
values('ABC123',3.0, 2, '1001')
insert into #received_items(code, qty, line_no, ref, processing_seq)
values ('ABC123', 4, NULL, NULL, 1)
insert into #received_items(code, qty, line_no, ref, processing_seq)
values ('ABC123', 3, NULL, NULL, 1)
insert into #received_items(code, qty, line_no, ref, processing_seq)
values ('ABC123', 4, NULL, 1002, 2)
insert into #received_items(code, qty, line_no, ref, processing_seq)
values ('ABC123', 4, 2, 1003, 3)
insert into #received_items(code, qty, line_no, ref, processing_seq)
values ('ABC123', 5, NULL, NULL, 4)
从#received_items中选择*
ABC123 4.00 NULL NULL 1
ABC123 3.00 NULL NULL 1
ABC123 4.00 NULL 1003 2
ABC123 4.00 2 1002 3
ABC123 5.00 NULL NULL 4
从#existing_items
中选择* 1 ABC123 2.00 1 NULL
2 ABC123 3.00 2 1001
结果应为:
1 ABC123 7.00 1 NULL
2 ABC123 4.00 2 1002
3 ABC123 4.00 3 1003
4 ABC123 5.00 4 NULL
解释:
id = 1的existing_items更新为7,因为received_items应该分组(code,line_no,ref,processing_seq)。该行仅在代码上匹配,因为没有提供line_no或ref。
使用id = 3创建新项目,因为找不到与ref 1003匹配的内容。
id = 2的existing_items会更新qty和ref,因为在line_no上找到了匹配项。
创建一个id = 4的新行,因为没有要匹配的行(id = 1已经与第一个处理_seq = 1的集合匹配)。
不确定如何去做,正在考虑一个游标,但可能有一个更简单的方法。我目前正在使用多个自联接...就像这样:
Select grp.*
,fm.id as full_match, rm.id as ref_match, lm.id as line_match
,(select min(id) from #existing_items where code = grp.code
and rm.id IS NULL and lm.id IS NULL and fm.id IS NULL and grp.ref IS NULL
) as code_match
-- ,cm.id as code_match
FROM (
select ri.code, sum(ri.qty) qty,ri.line_no,ri.ref, ri.processing_seq
from #received_items ri
group by code, line_no, ref, processing_seq
) grp
LEFT OUTER JOIN
#existing_items fm
ON grp.code = fm.code AND grp.line_no = fm.line_no and grp.ref = fm.ref
LEFT OUTER JOIN
#existing_items rm
ON grp.code = rm.code AND grp.ref = rm.ref
LEFT OUTER JOIN
#existing_items lm
ON grp.code = lm.code AND grp.line_no = lm.line_no
order by grp.processing_seq
这有助于了解要更新哪一行并产生此中间结果:
Code Qty Line_No Ref seq fm.id rm.id lm.id cm.id
ABC123 7.00 NULL NULL 1 NULL NULL NULL 1
ABC123 4.00 NULL 1002 2 NULL NULL NULL NULL
ABC123 4.00 2 1003 3 NULL NULL 2 NULL
ABC123 5.00 NULL NULL 4 NULL NULL NULL 1
需要一种方法来识别最接近的代码匹配,这有效,但不是seq = 4应该有cm.id为NULL - 所以我需要更改我的子查询不返回主要匹配的ID相同的子查询?然后我应该能够插入任何匹配列中没有id的地方。
对如何解决问题的任何见解都非常感激。
答案 0 :(得分:0)
您知道吗,更新现有数据的方式有很多开销。您应该为每个应该更新的行标识,并再次运行更新命令。您可以自己计算服务器资源的成本。循环遍历每条记录,并确定它是否已更改并更新。并且,使用您在其他表上声明的多个表,#EXISTINGITEM,#NEWITEM和您的实际数据。这有很多超载。
我还不知道你的情况是否可能,但是。我想建议的是。假设,我的库存中有一个问题请求。为此,我有一个2表名称, ISSUE_MAST 和 ISSUE_DETL 。问题Mast包含ISSUE_DOC_NO,Detail表包含 ISSUE_DOC_NO 和 SEQ_NO 。
现在,假设我们有一个新的问题请求来维护。然后,我可以简单地将数据保存在 MAST 和 DETL 表中,因为它是全新的Request,所以没有问题。它不是你的问题所在。而且,现在,假设oneday,请求必须改变。然后, 用户将向我提供MAST和DETL信息。而且,现在,我能做的只是删除DOC_NO属于CURRENT DOC NO的所有DETL项目。并且,只需再次插入所有Given行作为Fresh数据。
由于Overload,我根本不喜欢Update逻辑。但是,在某些情况下,我们也必须这样做。但是,我们不应该选择这种方式。如果poosible我们必须删除DETL信息和再次RE插入它,但将取决于您的交易复杂性。
答案 1 :(得分:0)
经过一段时间后,我设法解决了这个问题:
;WITH existing as (
SELECT
id, code, qty, line_no, ref
,ROW_NUMBER() OVER (ORDER BY line_no) AS code_inst
FROM #existing_items
)
,received as (
SELECT
code, SUM(qty) qty, line_no, ref
,ROW_NUMBER() OVER (ORDER BY processing_seq) pseq
,ROW_NUMBER() OVER (PARTITION BY code ORDER BY processing_seq) code_inst
FROM
#received_items
GROUP BY
code, line_no, ref, processing_seq
)
SELECT
recv.*, COALESCE(lm.ID, rm.id, cm.id) AS matched_id
FROM
received recv
LEFT OUTER JOIN
existing lm --line match
ON
recv.code = lm.code and recv.line_no = lm.line_no
LEFT OUTER JOIN
existing rm --ref match
ON
recv.code = rm.code and recv.ref = rm.ref
LEFT OUTER JOIN
existing cm --code match
ON
recv.code = cm.code
AND recv.code_inst = cm.code_inst
AND cm.ref IS NULL
AND lm.id IS NULL AND rm.id IS NULL
连接3次并不理想,但考虑到所涉及的逻辑(不同的匹配标准),它是有意义的。我最终将这个结果集加载到一个表变量中,然后我更新了id匹配的现有位置,并在matches_id为NULL的地方插入。