如何最好地应用更新逻辑

Posted

技术标签:

【中文标题】如何最好地应用更新逻辑【英文标题】:How best to apply update logic 【发布时间】:2013-06-19 19:13:54 【问题描述】:

我需要在更新表期间应用一些逻辑。

existing_items 是目标表,received_items 保存对 existing_items 或新项目的更新。

逻辑是 - 对于每个分组的 received_items,应该在 existing_items 中标识一个匹配的行。如果未找到匹配项,则应创建一个新行。

关键在于行可以匹配多个条件。它们应该始终在代码、line_no(如果给定)、ref(如果给定)上匹配。 received_items 行应按 processing_seq 顺序处理,并可能按给定顺序检查匹配项。

当所有分组的 received_item 都与一个 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 已经与 processing_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 的地方插入。

非常感谢您对如何解决问题的任何见解。

【问题讨论】:

.... 为什么“数量”是 numeric 字段?你能在逻辑上拥有这些东西的“一半”吗?在几乎所有情况下,数量都应该是整数(没有分数)。当您确实有部分金额时,通常是其他内容,并且需要指定单位。除此之外,这是间隙和孤岛问题的变体;你有哪个版本的 SQL Server,有些版本对此有更好的支持。 我为了解释问题而编造了它。数量通常可以以平方米、立方等为单位,我在这里没有说明。 sql 2005 如果我看到标记为quantity 的列,我将假设一个整数计数,句点。如果还有其他问题,我将寻找所描述的测量值(并希望使用单位,无论是在类型信息中还是在列名中)——即volumevolume_in_meters_cubed 等。如果你是尝试将两者存储在同一列中,以后会很痛苦.... 是的。我没有存储在同一列中。此外,这与问题无关,如果您能提供帮助,将不胜感激。称它为小部件或任何有帮助的东西。 【参考方案1】:

您知道吗,更新现有数据的方式有很多开销。您应该为每一行确定应该更新的内容,并再次运行更新命令。您可以自己计算服务器资源的成本。循环遍历每条记录,并识别它是否已更改并更新。并且,使用您声明的多个表,#EXISTINGITEM、#NEWITEMS 和您在其他表上的实际数据。这有很多过载。

我仍然不知道在您的情况下是否可能,但是。我想建议的是。假设,我的库存中有一个问题请求。为此,我有 2 个表名,ISSUE_MASTISSUE_DETL。 Issue Mast 包含 ISSUE_DOC_NO,Detail 表包含 ISSUE_DOC_NOSEQ_NO

现在,假设我们要维护一个新问题请求。然后,我可以简单地将数据保存在 MASTDETL 表中,因为它是全新的请求,所以不会有任何问题。它不是你的问题所在。而且,现在,假设有一天,请求必须改变。然后, 用户将向我提供 MAST 和 DETL 信息。而且,现在,我能做的只是删除 DOC_NO 属于当前 DOC NO 的所有 DETL 项目。而且,只需将所有给定的行再次插入为新鲜数据。

由于重载,我根本不喜欢更新逻辑。但是,在某些情况下,我们也必须这样做。但是,必须的情况下,我们不应该选择这种方式。如果可行,我们必须删除 DETL 信息并再次重新插入它,但这取决于您的事务复杂性。

【讨论】:

在这种情况下我无法删除/重新插入。 假设,您之前有 6 行。现在,我们以下列方式更改了数据: * 修改了第二行。 * 删除了第四行。 * 添加了一个新行。那么,您如何处理已删除的行?以及您用来识别的向上 SEQ 编号?您将如何在第 4 行之后更新您的处理 SEQ?你怎么能把你的第 5 排排成第 4 排,把第 6 排排成 5 排?我们可以这样做,但是您之前复制到 Existing Data 表和 Real 数据表的数据呢?我们现在如何管理诚信?我不认为你这样做是个好方法。 @N.pSubedi - 为了获得最佳解释效果,提供示例代码确实很有帮助。 不需要更新 processing_seq。解决方案是尝试返回一个结果集,此时您可以运行类似UPDATE existing_items set qty = res.qty, ref = res.ref FROM existing_items ei INNER JOIN results res on ei.ID = res.matched_id 的代码。然后,插入新的、不匹配的行:INSERT INTO existing_items (code, line, qty, ref) SELECT code, <line_no_calculation_here>, qty, ref) FROM res WHERE res.matched_id IS NULL。我希望能更好地解释处理的性质@N.pSubedi 此外,existing_items 没有删除 - 仅更新/插入【参考方案2】:

一段时间后,我设法弄清楚了这一点:

;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 匹配的现有位置,并在 match_id 为 NULL 的位置插入。

【讨论】:

以上是关于如何最好地应用更新逻辑的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Azure 数据工厂安全地调用 Azure 逻辑应用

如何使用标准 Azure 逻辑应用的无状态工作流可靠地处理 Azure 服务总线消息

在 Lumen/Laravel 控制器中添加自定义逻辑的最佳实践

如何最好地更新远程机器上正在运行的应用程序

如何在 AngularJS 中干净地构建组件/结构逻辑

SQL递归逻辑