【问题标题】:T-SQL Query only invoices between Start Date and End DateT-SQL 仅查询开始日期和结束日期之间的发票
【发布时间】:2017-09-07 19:12:16
【问题描述】:

我有一个财政年度的开始日期和结束日期范围:7/1/16 - 6/30/17

我的查询中包含的日期字段是付款日期,可以在 2017 年 6 月 30 日之外。

例子:

  Company  PayonDate
  Bose      9/30/17 <---Outside the 6/30/17 date range and will not show on report. This date will pay in advance. 

我想显示日期范围内的最后付款日期:

例子:

 Company    PayonDate
 Bose       4/1/17 <----Actual paid on date vs. pay on date in the future within the date range. 

有没有办法做到这一点?

提前致谢!

更新:

   SELECT 
   ven.VendorID,
   ven.Name AS [Vendor Name],
   inv.ReferenceNumber AS [Ref. No],
   inv.InvoiceNumber AS [Invoice No],
   inv.Payment AS Payment,
   SubMax.[Pay On Date]
   FROM inv
     INNER JOIN 
        (
        SELECT MAX(ips.PayOnDateTime) AS [Pay On Date], VendorID
        from inv
       LEFT JOIN ips ON ips.SourceID = inv.SourceID AND     ips.InvoiceID     = inv.InvoiceID
        Group by VendorID
       ) SubMax 
       on inv.VendorID = SubMax.VendorID 
    INNER JOIN ven ON inv.SourceID = ven.SourceID AND inv.VendorID = ven.VendorID
   LEFT JOIN ips ON ips.SourceID = inv.SourceID AND ips.InvoiceID = inv.InvoiceID
    WHERE FacilityID = 'HMC'
    AND SubMax.[Pay On Date] BETWEEN @StartDate AND @EndDate
    AND inv.ReferenceNumber LIKE '__-____'
    ORDER BY ven.Name, SubMax.[Pay On Date]

【问题讨论】:

  • 类似SELECT MAX(PayonDate) FROM Table WHERE PayonDate &gt;= '2016-07-01' AND PayonDate &lt; '2017-07-01'
  • 谢谢雅各布。实际上,我的子查询中有它。
  • PayonDate 是什么数据类型?我们可以在这里提供帮助,但我们需要一些细节。这是一个很好的起点。 spaghettidba.com/2015/04/24/…
  • PayonDate 的格式为 YYYY-MM-DD 00:00:00:000。谢谢你的帮助!我还在问题中添加了我的代码。
  • 格式化是什么意思?我在问数据类型是什么?我感觉它是一个 varchar 数据类型。你的变量的数据类型是什么?这些东西将在这里成就或破坏您的代码。

标签: sql sql-server tsql date ssms


【解决方案1】:

澄清我之前的评论:(这太长了,不能成为评论)

我假设 ips 表包含每个 vendorID 的多个付款日期。 那么我们是否可以将我们考虑的最大值日期限制在所需范围内?

也许我还没有完全理解这个问题。

   SELECT ven.VendorID
        , ven.Name AS [Vendor Name]
        , inv.ReferenceNumber AS [Ref. No]
        , inv.InvoiceNumber AS [Invoice No]
        , inv.Payment AS Payment
        , SubMax.[Pay On Date]
   FROM inv
   INNER JOIN (SELECT MAX(ips.PayOnDateTime) AS [Pay On Date]
                    , VendorID
               FROM  inv
               LEFT JOIN ips 
                  ON ips.SourceID = inv.SourceID 
                 AND ips.InvoiceID = inv.InvoiceID
              -- Can we put it here? so that max can only be payondates in your fiscal year?
                 AND ips.PayOnDateTime BETWEEN @StartDate AND @EndDate  
               GROUP BY VendorID) SubMax 
      ON inv.VendorID = SubMax.VendorID 
   INNER JOIN ven 
      ON inv.SourceID = ven.SourceID 
     AND inv.VendorID = ven.VendorID
   LEFT JOIN ips 
      ON ips.SourceID = inv.SourceID 
     AND ips.InvoiceID = inv.InvoiceID
   WHERE FacilityID = 'HMC'
       --WHY HERE
       --AND SubMax.[Pay On Date] BETWEEN @StartDate AND @EndDate  
      AND inv.ReferenceNumber LIKE '__-____'
   ORDER BY ven.Name
          , SubMax.[Pay On Date]

【讨论】:

  • 这行得通!基本上,如果这就是我对为什么代码也没有按照我想要的方式工作的理解,那么我将参数日期放在不正确的位置。对吗?
  • 是的。您需要在确定最大 [支付日期] 之前应用日期范围限制。因此,通过确保 max 只能选择您的财政日期范围内的日期,那么 max 只能是该财政范围内的日期。限制不能在 WHERE 子句上,因为您将 ips 作为左连接。因此连接上的 AND 标准。这样,名为SubMax 的派生表/内联视图只会在指定范围内的日期支付。我不完全理解你在这里做什么,所以在它进入生产系统之前测试一下这个废话! (对任何答案的明智建议)
  • 另请注意,我认为这是@JacobH 在他的第一条评论中提到的;但他们没有详细说明放置位置;这就是根本问题所在。关于测试评论请确保您测试边缘情况,例如6/30/17 13:15 BETWEEN 使用的 payonDatetime 将排除该记录;当你想要它的时候!这是肖恩所暗示的一个元素!
【解决方案2】:

我发现日期维度表是天赐之物,尤其是在处理不从 1 月 1 日开始的财政年度季度时。它们添加了一个额外的表来加入,但它们节省了大量的处理和思考。有关一个好的日期暗表,请参阅 Aaron Bertrand 的示例 - https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/。根据您认为需要的内容进行自定义;我制作了几个不同的版本,有时以它为基础。但请记住,我们的目标是创建一次并在需要时使用它。

在上面的示例中,构建一个日期表,列出大量日期的所有日期,并包括财政年度。然后只需在 FY 是您需要参考的年份的日期加入日期表。

窗口函数也派上用场。可能是这样的:

SELECT * 
FROM (
    SELECT 
          ven.VendorID
        , ven.Name AS [Vendor Name]
        , inv.ReferenceNumber AS [Ref. No]
        , inv.InvoiceNumber AS [Invoice No]
        , inv.Payment AS Payment
        , ips.PayOnDateTime AS [Pay On Date]
        , d.theFYYear
        , ROW_NUMBER() OVER (PARTITION BY inv.InvoiceNumber ORDER BY ips.payOnDateTime DESC) AS rn
    FROM ven
    INNER JOIN inv ON ven.vendorID = inv.vendorID
        AND inv.FacilityID = 'HMC'
        AND inv.ReferenceNumber LIKE '__-____'
    INNER JOIN ips ON ips.SourceID = inv.SourceID 
        AND ips.InvoiceID = inv.InvoiceID
        AND ips.PayOnDateTime >= @StartDate
        AND ips.PayOnDateTime <= @EndDate
    INNER JOIN ref_DateDimension d ON ips.PayOnDateTime = d.theDate
        AND d.theFYYear = 'FY2017' -- Or whatever FY you need current
    ) s1
WHERE s1.rn = 1

【讨论】:

  • 我创建了一个脚本来创建一个使用非标准 FY 开始日期的日期维度。我需要写博客。
  • 如果保留 StartDate 和 EndDate 参数,则日期表没有意义。但我可以确认日期表非常有用。只是一个额外的简短解释:它应该包含每个日期的一行,并根据需要包含尽可能多的属性(日期本身、星期几、月、年、日、周、财政年度、其他经常使用的不同 varchar 格式的日期数据库/表)。
  • @RaphaelMüllner 加入它是有意义的。 ips 表会将日期限制为开始和结束日期范围,然后仅将这些日期与您关心的 FY 年份相结合。这将使您为其生成的 row_number() 成为您想要的 FY 免责声明中的最大日期:我讨厌日期..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多