【问题标题】:Is there a more efficient / elegant way to write this code I have?有没有更有效/更优雅的方式来编写我拥有的这段代码?
【发布时间】:2016-04-27 05:09:53
【问题描述】:

我想知道是否有人可以帮助我解决下面的任何或所有代码。我已经让它工作了,但对我来说似乎效率低下,并且可能比最佳速度慢很多。

首先了解此代码的必要性的一些基本背景:

我有一个不包含相应发票编号的运输记录表。我已经浏览了所有表格,并且继续这样做。事实上,直到今天早上我才发现,如果已生成装箱单,我可以通过该装箱单 ID 将装运表链接到装箱单表,并从那里获取发票编号。然而,没有那个链接,我不得不猜测。在大多数情况下,这并不是很困难,因为发票表具有可以匹配的编号、行和版本。但是当编号、线路和发布有多个发货时(例如,当一条线路部分发货时),则可能有多个答案,其中只有一个是正确的。运输表中有一个列说明了该编号、行和版本的日期顺序,这部分帮助了我,但在某些情况下,我用于“猜测”的过程可能有些模棱两可。

我的程序是这样做的。首先,它会创建一个数据表,其中包含发票编号(如果有装箱单链接)。

接下来,它将所有数据转储到第二个表中,这一次使用——仅当第一个表中的发票为 NULL 时——基于按编号对所有运输记录进行分区来“猜测”发票编号,行,发布,日期顺序和日期,然后将其与发票表的相同类型的事物进行比较,并尝试按日期排列所有内容。

最后,它解析该表并找到任何最后的空值,并将它们与该编号、行和版本的任何发票的第一条记录基本匹配。

两种猜测都添加了字符以表明它们实际上是猜测。

IF OBJECT_ID('tempdb..#cosTAble') IS NOT NULL
DROP TABLE #cosTable

DECLARE @cosTable2  TABLE (
     ID             INT IDENTITY
    ,co_num         CoNumType
    ,co_line        CoLineType
    ,co_release     CoReleaseType
    ,date_seq       DateSeqType
    ,ship_date      DateType
    ,inv_num        NVARCHAR(14)
    )

DECLARE
     @co_num_ck     CoNumType
    ,@co_line_ck    CoLineType
    ,@co_release_ck CoReleaseType

DECLARE @Counter1   INT = 0

SELECT cos.co_num, cos.co_line, cos.co_release, cos.date_seq, cos.ship_date, cos.qty_invoiced, pck.inv_num
    INTO #cosTable
    FROM co_ship cos
        LEFT JOIN pckitem pck
            ON cos.pack_num = pck.pack_num
            AND cos.co_num = pck.co_num
            AND cos.co_line = pck.co_line
            AND cos.co_release = pck.co_release

;WITH cos_Order
    AS(
        SELECT co_num, co_line, co_release, qty_invoiced, date_seq, ship_date, ROW_NUMBER () OVER (PARTITION BY co_num, co_line, co_release ORDER BY ship_date) AS cosrow
        FROM co_ship
        WHERE qty_invoiced > 0
    ),

invi_Order
    AS(
        SELECT inv_num, co_num, co_line, co_release, ROW_NUMBER () OVER (PARTITION BY co_num, co_line, co_release ORDER BY RecordDate) AS invirow
        FROM inv_item
        WHERE qty_invoiced > 0
    ),

cos_invi
    AS(
        SELECT cosO.*, inviO.inv_num
        FROM cos_Order cosO
            LEFT JOIN invi_Order inviO
                ON cosO.co_num = inviO.co_num AND cosO.co_line = inviO.co_line AND cosO.cosrow = inviO.invirow)

INSERT INTO @cosTable2
SELECT cosT.co_num, cosT.co_line, cosT.co_release, cosT.date_seq, cosT.ship_date, COALESCE(cosT.inv_num,'*'+cosi.inv_num) AS inv_num
    FROM #cosTable cosT
    LEFT JOIN cos_invi cosi
        ON  cosT.co_num = cosi.co_num
        AND cosT.co_line = cosi.co_line
        AND cosT.co_release = cosi.co_release
        AND cosT.date_seq = cosi.date_seq
        AND cosT.ship_date = cosi.ship_date



WHILE @Counter1 < (SELECT MAX(ID) FROM @cosTable2) BEGIN
    SET @Counter1 += 1
    SET @co_num_ck = (SELECT co_num FROM @cosTable2 WHERE ID = @Counter1)
    SET @co_line_ck = (SELECT co_line FROM @cosTable2 WHERE ID = @Counter1)
    SET @co_release_ck = (SELECT co_release FROM @cosTable2 WHERE ID = @Counter1)
    IF EXISTS (SELECT * FROM @cosTable2 WHERE ID = @Counter1 AND inv_num IS NULL)
        UPDATE @cosTable2
            SET inv_num = '^' + (SELECT TOP 1 inv_num FROM @cosTable2 WHERE 
                            @co_num_ck = co_num AND
                            @co_line_ck = co_line AND
                            @co_release_ck = co_release)
            WHERE ID = @Counter1 AND inv_num IS NULL
    END

SELECT * FROM @cosTable2
ORDER BY co_num, co_line, co_release, date_seq, ship_date

【问题讨论】:

    标签: tsql


    【解决方案1】:

    你的处境很糟糕——正如@craig.white 和@HLGEM 所建议的那样,你继承了一些没有足够约束来使数据正确或安全的东西......现在你必须“合成”它。我知道猜测是你能做的最好的,而且你可以,至少让你的猜测在性能方面合理。

    在那之后,您应该大声尖叫以获得一些时间来修复数据库 - 以应用所需的约束来防止数据进一步恶化。

    在性能方面,while 循环是一场灾难。你最好用一个更新语句替换整个混乱......就像:

    update c0
    set inv_nbr = '^' + c1.inv_nbr
    from
      @cosTable2 c0
      left outer join
      (
        select
          co_num,
          co_line,
          co_release,
          inv_nbr
        from
          @cosTable2
        where
          inv_nbr is not null
        group by
          co_num,
          co_line,
          co_release,
          inv_nbr        
      ) as c1
      on
        c0.co_num = c1.co_num and
        c0.co_line = c1.co_line and
        c0.co_release = c1.co_release
    where
      c0.inv_num is null
    

    ...与循环做同样的事情,只是在一个语句中。

    【讨论】:

    • 这正是我所需要的,谢谢。我一直在努力处理总是插入相同值的更新语句,这是我无法完成的部分。我也感谢每个人的 cmets 和支持,他们确认我没有疯,我不应该这样做。希望我以后可以改进它。
    • @DaveX,祝你好运 - 我们中的很多人都曾为你着想
    • 我只是在一个完全不同的过程中调整了这个相同的结构。像魅力一样工作。非常感谢。
    • @DaveX,太好了!一旦你看到它完成了,它突然变得很有意义......你可以在任何地方应用它。我在继承的一个项目中有类似的东西。这样的事情很容易让客户提前获得一些布朗尼积分。
    • @Clay - 干得好;你能真正帮助他而不是像我那样向他讲道,真是太好了。抓住了我对业务部门的咆哮,而不是真正试图提供帮助。再次感谢您。
    【解决方案2】:

    在我看来,您正在非常努力地解决一个不应该存在的问题。您所描述的是一种不幸的常见情况,即随着业务的发展,流程在没有意图和特定方向的情况下有机地增长,这使得数据提取几乎不可能自动化。您非常需要一套政策和程序 - 对于(非常粗略和简单的)示例: 1:订单必须存在才能生成装箱单。 2:在生成发票之前,必须有装箱单。
    3:使用装箱单和订单中的数据创建发票(要求什么,挑选什么,我们开什么账单) -再一次,这是一个粗略的例子,只是为了说明这个想法。 所有数据必须在适当的时间输入,否则有人没有完成他们的工作。 在不存在此类数据时,准确、一致地提供良好的管理数据并不是 IT 部门的典型技能。

    【讨论】:

    • 我怀疑他的问题是没有正确使用 FK 约束和数据定义的直接结果。如果发票的装箱单表有 FK 并且如果需要装箱单 ID,则在与装箱单相关之前无法创建发票。他应该试图解决为什么这种情况存在而不是解决它的问题。但是,即使那样,您也需要识别这些当前混乱的记录并修复它们。但这是一次性修复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-31
    • 2019-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    相关资源
    最近更新 更多