将相对复杂的业务逻辑添加到SQL查询中

时间:2015-07-08 11:18:08

标签: sql sql-server-2012

过去几天,我在SO用户中获得了一些极好的帮助,他们对SQL的了解显然远远超出了我的能力。现在,我可以再次向那些比我更有知识的人提供一些建议。这个问题主要来自here

我已经调整了原始查询以满足要求,现在看起来像这样:

DECLARE @startDate date = '2015-01-05',
        @endDate date = '2015-06-05',
        @tempDeduction decimal(10, 4) = NULL



SELECT (SELECT
    ContactId AS '@ContactId',
    VesselOwner AS '@Owner',
    Owed AS '@Owed',
    WeeklyDeductionRate AS '@WeeklyDeductionRate',
    FromMinimumReturn AS '@FromMinimumReturn',
    DeductionRate AS '@DeductionRate',
    TotalDeductions AS '@TotalDeductions',
    TotalToBeReturned AS '@TotalToBeReturned',
    InternalCommission AS '@InternalCommissionRate',
    InternalDeduction AS '@InternalDeductionRate',



    (SELECT DISTINCT
      ld1.ProductId AS '@ProductId',
      FORMAT(AVG(ld1.UnitPrice), 'N2') AS '@Cost',
      FORMAT(SUM(ld1.Quantity), 'N2') AS '@Quantity'

    FROM LandingDetails ld1
    INNER JOIN dbo.LandingHeaders lh1
      ON ld1.LandingId = lh1.LandingId
    WHERE Posted = 0
    AND lh1.VesselOwner = a.VesselOwner
    GROUP BY ld1.ProductId
    FOR xml PATH ('Products'), TYPE)

  FROM (SELECT
    Contacts.ContactId AS ContactId,
    LandingHeaders.VesselOwner AS VesselOwner,
    FORMAT(SUM(LandingDetails.Quantity * LandingDetails.UnitPrice), 'N2') AS Owed,
    SocietyMemberships.WeeklyDeductionRate AS WeeklyDeductionRate,
    SocietyMemberships.FromMinimumReturn AS FromMinimumReturn,
    Deductions.DeductionRate,
    Vessels.InternalCommission AS InternalCommissionRate,
    Vessels.InternalDeduction AS InternalDeductionRate,
    FORMAT(CASE
      WHEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) - (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate) > FromMinimumReturn THEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate
      ELSE SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate
    END, 'N2') AS TotalDeductions,


    --need to add some logic here I presume that utiles the sql below that is being used to calculate the total to be returned


    FORMAT(SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) -
    (CASE
      WHEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) - (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate) > FromMinimumReturn THEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate
      ELSE SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate
    END), 'N2') AS TotalToBeReturned


  FROM dbo.LandingDetails
  INNER JOIN dbo.LandingHeaders
    ON LandingDetails.LandingId = LandingHeaders.LandingId
  INNER JOIN dbo.Vessels
    ON LandingHeaders.VesselId = Vessels.VesselId
  INNER JOIN dbo.Contacts
    ON Vessels.OwnerId = Contacts.ContactId
  INNER JOIN dbo.SocietyMemberships
    ON Contacts.SocietyId = SocietyMemberships.SocietyId
  INNER JOIN dbo.Deductions
    ON Vessels.DeductionId = Deductions.DeductionId
  WHERE LandingHeaders.Posted = 0
  AND LandingDate1 BETWEEN @startDate AND @endDate
  GROUP BY ContactId,
           LandingHeaders.VesselOwner,
           SocietyMemberships.WeeklyDeductionRate,
           SocietyMemberships.FromMinimumReturn,
           Deductions.DeductionRate) a
  ORDER BY ContactId

  FOR xml PATH ('Owner'), TYPE)

FOR xml PATH ('PurchaseOrders'), TYPE

我添加了逻辑,这样xml也会显示最终的金额((一旦扣除已经从已欠款中删除)将被返回(除了由于舍入误差导致奇数记录偶尔出现1便士差异)货币数据类型)它可以按照我的意愿运作。

我现在正试图建立实现最后一小块逻辑的最佳方法。第一个select语句中有两个新列:InternalCommission和InternalDeduction。这些实际上是互斥的(换句话说,如果一个包含大于0的值,另一个将为0),它们用于计算要添加或扣除的金额(当前为TotalToBeReturned的百分比)。目标是最终得到xmlattributes,显示在通信或扣除中支付或扣除的金额,并调整TotalToBeReturned以反映这些新要求。

我的感觉是我需要将创建TotalToBeReturned的部分分配给一个临时值(作为@tempDeduction添加到sql的顶部,然后使用它来执行必要的逻辑。但是如果我尝试的话在我在sql编译器不喜欢的查询中添加注释的地方下面设置该变量。

我的推理是否正确,如果是这样,我应该如何设置该变量并使用它来应用业务逻辑?

由于

1 个答案:

答案 0 :(得分:0)

万一有人应该偶然发现这一点,并希望看到解决方案。最重要的是,在执行逻辑时,绝对有必要引用实际的基础表名而不是别名。最后,以下工作。

该语言被故意设置为英式英语,因为我想在结果xml中使用£符号。 sqlserver常常以美国英语为默认值。

SET LANGUAGE 'British English'
DECLARE @startDate date ,
        @endDate date 




SELECT (SELECT
    ContactId AS '@ContactId',
    VesselOwner AS '@Owner',
    FORMAT(Owed, 'N2') AS '@Owed',
    FORMAT(WeeklyDeductionRate, 'C') AS '@WeeklyDeductionRate',
    FORMAT(FromMinimumReturn, 'C') AS '@FromMinimumReturn',
    FORMAT(DeductionRate, 'P') AS '@DeductionRate',
    FORMAT(TotalDeductions, 'N2') AS '@TotalDeductions',
    Format(TempReturn, 'N2') AS '@TempReturn',
    FORMAT(InternalCommission, 'P') AS '@InternalCommissionRate',
    FORMAT(InternalDeduction, 'P') AS '@InternalDeductionRate',
    FORMAT(InternalCommissionAmount, 'N2') AS '@InternalCommissionAmount',
    FORMAT(InternalDeductionAmount, 'N2') AS '@InternalDeductionAmount',
    FORMAT(TotalToBeReturned, 'N2') AS '@TotalToBeReturned',

    (SELECT DISTINCT
      ld1.ProductId AS '@ProductId',
      FORMAT(AVG(ld1.UnitPrice), 'N2') AS '@Cost',
      FORMAT(SUM(ld1.Quantity), 'N2') AS '@Quantity'

    FROM LandingDetails ld1
    INNER JOIN dbo.LandingHeaders lh1
      ON ld1.LandingId = lh1.LandingId
    WHERE Posted = 0
    AND lh1.VesselOwner = a.VesselOwner
    GROUP BY ld1.ProductId
    FOR xml PATH ('Products'), TYPE)

  FROM (SELECT
    Contacts.ContactId AS ContactId,
    LandingHeaders.VesselOwner AS VesselOwner,
    SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) AS Owed,
    SocietyMemberships.WeeklyDeductionRate AS WeeklyDeductionRate,
    SocietyMemberships.FromMinimumReturn AS FromMinimumReturn,
    Deductions.DeductionRate,
    Vessels.InternalCommission,
    Vessels.InternalDeduction,
    CASE
      WHEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) - (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate) > FromMinimumReturn THEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate
      ELSE SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate
    END AS TotalDeductions,


    SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) -
    (CASE
      WHEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) - (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate) > FromMinimumReturn THEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate
      ELSE SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate
    END) AS TempReturn,



    (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) -
    (CASE
      WHEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) - (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate) > FromMinimumReturn THEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate
      ELSE SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate
    END)) * InternalCommission AS InternalCommissionAmount,

    (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) -
    (CASE
      WHEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) - (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate) > FromMinimumReturn THEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate
      ELSE SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate
    END)) * InternalDeduction AS InternalDeductionAmount,


    CASE
      WHEN (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) -
        (CASE
          WHEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) - (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate) > FromMinimumReturn THEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate
          ELSE SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate
        END)) * InternalCommission > 0 THEN (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) -
        (CASE
          WHEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) - (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate) > FromMinimumReturn THEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate
          ELSE SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate
        END)) + ((SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) -
        (CASE
          WHEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) - (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate) > FromMinimumReturn THEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate
          ELSE SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate
        END)) * InternalCommission)

      ELSE (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) -
        (CASE
          WHEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) - (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate) > FromMinimumReturn THEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate
          ELSE SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate
        END)) + ((SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) -
        (CASE
          WHEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) - (SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate) > FromMinimumReturn THEN SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate + WeeklyDeductionRate
          ELSE SUM(LandingDetails.Quantity * LandingDetails.UnitPrice) * DeductionRate
        END)) * InternalDeduction)
    END AS TotalToBeReturned





  FROM dbo.LandingDetails
  INNER JOIN dbo.LandingHeaders
    ON LandingDetails.LandingId = LandingHeaders.LandingId
  INNER JOIN dbo.Vessels
    ON LandingHeaders.VesselId = Vessels.VesselId
  INNER JOIN dbo.Contacts
    ON Vessels.OwnerId = Contacts.ContactId
  INNER JOIN dbo.SocietyMemberships
    ON Contacts.SocietyId = SocietyMemberships.SocietyId
  INNER JOIN dbo.Deductions
    ON Vessels.DeductionId = Deductions.DeductionId
  WHERE LandingHeaders.Posted = 0
  AND LandingDate1 BETWEEN @startDate AND @endDate
  GROUP BY ContactId,
           LandingHeaders.VesselOwner,
           SocietyMemberships.WeeklyDeductionRate,
           SocietyMemberships.FromMinimumReturn,
           Deductions.DeductionRate,
           Vessels.InternalCommission,
           Vessels.InternalDeduction) a
  ORDER BY ContactId

  FOR xml PATH ('Owner'), TYPE)

FOR xml PATH ('PurchaseOrders'), TYPE