如何优化以下SQL代码?

时间:2017-09-07 16:07:32

标签: sql sql-server sql-server-2008

我在SQL Server中创建了一个使用两个表tbPOValidationtbPOValidationTemp的存储过程。

如果tbPOValidationTemp中有tbPOValidation行,则使用tbPOValidation中的值更新tbPOValidationTemp

如果不存在,则将tbPOValidationTemp行插入tbPOValidation

这个SQL做了那个工作,但我认为我所做的并不安全。在哪些方面我可以优化代码并使其更安全,以便正确地完成工作?

CREATE PROCEDURE spPOValidation
AS
BEGIN
    SET NOCOUNT ON;

    IF NOT EXISTS(SELECT * 
                  FROM tbPOValidation 
                  WHERE ShoppingCartNo IN (SELECT ShoppingCartNo 
                                           FROM tbPOValidationTemp)
                    AND LineItemNo IN (SELECT LineItemNo 
                                       FROM tbPOValidationTemp) 
                    AND PONo IN (SELECT PONo FROM tbPOValidationTemp))
    BEGIN
        INSERT INTO tbPOValidation (SupplierName, DUNS, PONo, LineItemNo, PurchDocItemDesc, POIssueDate, DeliveryDate, PurchDocType, MtrNo,
        Location, PayTerms, BlanketNo, BlanketLineItemNo, ShoppingCartNo, SHCItmNo, ItemPricing, ItmPrcCurrency, Per, POValue, POValueCurrency,
        Qty, UOM, MFGName, MFGPartNO, Description, Remarks, Accept, AcceptedBy, AcceptedOn, RejectionReason)
            SELECT 
                SupplierName, DUNS, PONo, LineItemNo, PurchDocItemDesc, 
                POIssueDate, DeliveryDate, PurchDocType, MtrNo,
                Location, PayTerms, BlanketNo, BlanketLineItemNo, 
                ShoppingCartNo, SHCItmNo, ItemPricing, ItmPrcCurrency, Per, 
                POValue, POValueCurrency, Qty, UOM, MFGName, MFGPartNO, 
                Description, Remarks, Accept, AcceptedBy, AcceptedOn, RejectionReason 
            FROM 
                tbPOValidationTemp
    END
    ELSE
    BEGIN
        UPDATE t
        SET t.SupplierName = v.SupplierName, t.DUNS = v.DUNS, 
            t.PONo = v.PONo, t.LineItemNo = v.LineItemNo, 
            t.PurchDocItemDesc = v.PurchDocItemDesc,
            t.POIssueDate = v.POIssueDate, t.DeliveryDate = v.DeliveryDate, 
            t.PurchDocType = v.PurchDocType, t.MtrNo = v.MtrNo, 
            t.Location = v.Location, t.PayTerms = v.PayTerms, 
            t.BlanketNo = v.BlanketNo, 
            t.BlanketLineItemNo = v.BlanketLineItemNo, 
            t.ShoppingCartNo = v.ShoppingCartNo, 
            t.SHCItmNo = v.SHCItmNo, t.ItemPricing = v.ItemPricing, 
            t.ItmPrcCurrency = v.ItmPrcCurrency, t.Per = v.Per, 
            t.POValue = v.POValue, t.POValueCurrency = v.POValueCurrency, 
            t.Qty = v.Qty, t.UOM = v.UOM, t.MFGName = v.MFGName, 
            t.MFGPartNO = v.MFGPartNO, t.Description = v.Description, 
            t.Remarks = v.Remarks, t.Accept = v.Accept, 
            t.AcceptedBy = v.AcceptedBy, t.AcceptedOn = v.AcceptedOn, 
            t.RejectionReason = v.RejectionReason
        FROM
            tbPOValidation t
        JOIN 
            tbpovalidationtemp v ON t.ShoppingCartNo = v.ShoppingCartNo 
                                 AND t.LineItemNo = v.LineItemNo 
                                 AND t.PONo = v.PONo
    END

    TRUNCATE TABLE tbPOValidationTemp
END

1 个答案:

答案 0 :(得分:0)

由于您的INNER JOIN谓词,您的更新部分自然会将结果限制为存在的结果。对于不存在的记录,您可以使用相同的逻辑用LEFT JOIN重写插入部分:

INSERT INTO tbPOValidation (SupplierName, DUNS, PONo, LineItemNo, PurchDocItemDesc, POIssueDate, DeliveryDate, PurchDocType, MtrNo,
                Location, PayTerms, BlanketNo, BlanketLineItemNo, ShoppingCartNo, SHCItmNo, ItemPricing, ItmPrcCurrency, Per, POValue, POValueCurrency,
                Qty, UOM, MFGName, MFGPartNO, Description, Remarks, Accept, AcceptedBy, AcceptedOn, RejectionReason)
SELECT SupplierName, DUNS, PONo, LineItemNo, PurchDocItemDesc, POIssueDate, DeliveryDate, PurchDocType, MtrNo,
           Location, PayTerms, BlanketNo, BlanketLineItemNo, ShoppingCartNo, SHCItmNo, ItemPricing, ItmPrcCurrency, Per, POValue, POValueCurrency,
           Qty, UOM, MFGName, MFGPartNO, Description, Remarks, Accept, AcceptedBy, AcceptedOn, RejectionReason 
FROM tbPOValidationTemp T
LEFT JOIN tbPOValidation T2 on T.ShoppingCartNo = T2.ShoppingCartNo
                               and T.LineItemNo = T2.LineItemNo
                               and T.PONo = T2.PONo
WHERE T2.ShoppingCartNo IS NULL --NULL filter to complete anti-join and only 
                                --insert records that do not exist

之后只需进行更新即可。这将删除所有令人困惑的if逻辑和in()子查询,对我来说,更容易阅读。请注意,我假设您要检查完整记录中ShoppingCartNoLineItemNoPONo的匹配项,而不只是检查它们是否存在于主表中。