SQL 在发货日期之前的最近日期加入表格

SQL Join Tables on Closest Date BEFORE Shipped Date

这似乎是一个重复问题,但并不是因为论坛中的其他解决方案在这种情况下不起作用。

这是对我们的 ERP 数据库的查询,它试图获取零件的最终销售商品总成本。基本上,ERP 可以很容易地计算出所有直接成本,但不计算报废成本。

我被困在 FROM 部分的子查询中,标记为:

>>>>>>HELP NEEDED STARTING HERE

子查询,正如现在所写的那样,提取所有发给我们的废料供应商的货物并获得每磅的每月平均费率,然后根据 alloy 类型、月份和年。

我的财务部门告诉我平均值不是一个好的解决方案,因为一些金属价格波动太大,或者他们不在零件发货的同一个月出售废金属,所以这行不通。

我需要了解从我们工厂运出零件之前的最近日期起,我们为废金属支付的费率。

我在 Stack Overflow 上找到了其他示例,这些示例显示了执行此操作的方法,但主表和子查询表重叠,因此我看到的其他解决方案都失败了。我在下面的代码中发表了评论来展示和解释这一点。

我完全接受我处理这个错误的想法。我怎样才能使这项工作?

DECLARE @Date_From                      AS  DATETIME;
DECLARE @Date_To                        AS  DATETIME;
SET     @Date_From                      = '2016-10-01 00:00:00.000';
SET     @Date_To                        =  GETDATE()       ;
 -- Start Main query     
SELECT TOP 10
   CCustomer.Customer_Type          AS  'Industry'
  ,SShipper.Ship_Date               AS  'Ship_Date'
  ,SSContainer.Serial_No            AS  'Serial_No'
  ,PPart.Grade                      AS  'Alloy'
  ,tbl_ScrapValue.Scrap_Value_per_lb    AS 'Scap_Value_per_lb'

FROM
            Sales_v_Shipper_Line          AS SSLine 
      JOIN  Sales_v_Shipper               AS SShipper
        ON  SShipper.Shipper_Key = SSLine.Shipper_Key
      JOIN  Part_v_Part                   AS PPart
        ON  SSLine.Part_Key = PPart.Part_Key
      JOIN  Common_v_Customer             AS CCustomer
        ON  SShipper.Customer_No   = CCustomer.Customer_No
 -- >>>>>>HELP NEEDED STARTING HERE
 -- Below is the sub query that pulls the scrap sales value per pound.
 --  The key point is that both shipments to our customers of real parts,
 --   and the 'shipments' of scrap metal sales come from the same tables,
 --  mainly Part_v_Part and Sales_v_Shipper, because of that the other 
--solutions for the 'join by closest date' in the forums don't work.

LEFT OUTER  JOIN  (SELECT
                     MONTH(SShipper.Ship_Date)       AS 'Scrap_Ship_Month'
                    ,YEAR(SShipper.SHip_Date)        AS 'Scrap_Ship_Year'
                    ,PPart.Grade                     AS  'Alloy'
                    ,AVG(AARIDist.Unit_Price)        AS 'Scrap_Value_per_lb'

                FROM
                        Sales_v_Shipper               AS  SShipper
                  JOIN  Sales_v_Shipper_Line          AS  SS_Line
                    ON  SShipper.Shipper_Key = SS_Line.Shipper_Key  
                  JOIN  Part_v_Part                   AS PPart
                    ON  SS_Line.Part_Key = PPart.Part_Key
                  JOIN  Common_v_Customer             AS  CCustomer
                    ON  SShipper.Customer_No = CCustomer.Customer_No

                WHERE CCustomer.Customer_Code     = 'Scrap_Vendor'
                AND SSHipper.Ship_Date <= @Date_To

            GROUP BY
                 MONTH(SShipper.Ship_Date)
                ,YEAR(SShipper.SHip_Date)
                ,PPart.Grade
               ) AS tbl_ScrapValue
  ON  PPart.Grade = tbl_ScrapValue.Alloy 
      AND
        YEAR(SShipper.Ship_Date) = YEAR(tbl_ScrapValue.Scrap_Ship_Year)
      AND
        MONTH(SShipper.Ship_Date) =(tbl_ScrapValue.Scrap_Ship_Month)

--- >>>>HELP NEEDED ENDS HERE
WHERE
    AND SShipper.Ship_Date >= @Date_From
    AND SSHipper.Ship_Date <= @Date_To      
 GROUP BY
      SShipper.Shipper_No
      ,SShipper.Ship_Date
      ,CCustomer.Customer_Type
      ,SSContainer.Quantity
      ,PPart.Grade

这是上面查询的示例输出,您可以看到 'Scrap_Value_per_lb' 失败了:

[![Sample_Output][1]][1]

Industry              Ship_Date         Serial_No Alloy Scap_Value_per_lb
Material Processing 17-Oct-16 4:47:00 PM S472091  C182 NULL 
Material Processing 17-Oct-16 4:47:00 PM S472210  C182 NULL 
Material Processing 17-Oct-16 4:47:00 PM S472211  C182 NULL 
Electronics         17-Oct-16 4:27:00 PM S436738  C180 NULL 
Electronics         17-Oct-16 4:27:00 PM S463290  C180 NULL 
Electronics         17-Oct-16 4:27:00 PM S463315  C180 NULL 
Electronics         17-Oct-16 4:27:00 PM S463327  C180 NULL 
Electronics         17-Oct-16 4:27:00 PM S463333  C180 NULL 
Electronics         17-Oct-16 4:27:00 PM S463345  C180 NULL 
Electronics         17-Oct-16 4:27:00 PM S463354  C180 NULL 

更新

这是 2016 年 10 月 19 日上午 7 点进行的第二次编辑,以进一步简化代码,在代码中添加注释以根据其他人的反馈进行澄清。

因此,如果我理解正确的话,您希望子查询 return 只有一行(外部查询中的每一行都相同吗?)

SELECT Top 1 
                     SShipper.Ship_Date
                    ,PPart.Grade                AS  'Alloy'
                    ,AARIDist.Unit_Price        AS 'Scrap_Value_per_lb'

                FROM
                        Sales_v_Shipper               AS  SShipper
                  JOIN  Sales_v_Shipper_Line          AS  SS_Line
                    ON  SShipper.Shipper_Key = SS_Line.Shipper_Key  
                  JOIN  Part_v_Part                   AS PPart
                    ON  SS_Line.Part_Key = PPart.Part_Key
                  JOIN  Common_v_Customer             AS  CCustomer
                    ON  SShipper.Customer_No = CCustomer.Customer_No
                  JOIN  Accounting_v_AR_Invoice_Dist  AS  AARIDist
                    ON  SS_Line.Shipper_Line_Key = AARIDist.Shipper_Line_Key

                WHERE CCustomer.Customer_Code     = 'Scrap_Value'
                AND SSHipper.Ship_Date <= @Date_To
                AND AARIDIst.Unit_Price < AARIDist.Quantity
                AND AARIDist.Unit_Price > '0'

                Order By SShipper.Ship_Date Desc

               ) AS tbl_SValue

如果子查询的值对于外部查询的每一行都应该不同,那么我需要知道子查询中的每一行是如何连接到外部查询中的行的

所以当您出售某种 alloy 的金属时,您出售了所有可用的东西,即没有剩余?

然后您从买入 table 中获取记录,并将它们与同一 alloy 的下一个卖出记录合并。这可以通过交叉应用来实现。这是一个简单的 tables 查询,让您知道需要什么:

select
  year(matched_sold.sold_date),
  month(matched_sold.sold_date),
  sum(bought.amount * bought.price)
from bought
cross apply
(
  select top 1 *
  from sold
  where sold.alloy = bought.alloy
  and sold.sold_date > bought.bought_date
  order by sold.sold_date desc
) matched_sold
group by
  year(matched_sold.sold_date),
  month(matched_sold.sold_date);

不知道我是否答对了你的问题。您希望通过在日期字段上使用 JOIN 来连接两个结果集,但不保证完全匹配。可能您可以使用 ROW_NUMBER 函数生成分区行号,包括排序,然后加入行号,例如ROW_NR = 1.

TABLE 1                 TABLE 2
ROW_NR DATE       ID    ROW_NR DATE       ID
------ ---------- --    ------ ---------- --
     1 10/25/2016  1 -match- 1 10/27/2016  1 
     2 10/24/2016  1        
     3 10/20/2016  1
     4 10/19/2016  1
     1 10/23/2016  2 -match- 1 10/28/2016  2
     2 10/15/2016  2        
     3 10/09/2016  2
     4 10/08/2016  2     

Table 中的行编号 1:

  • TABLE1 的数据 TABLE1.DATE <= TABLE2.DATE

  • 按 ID 分区

  • 按 ID 和 DATE DESC 排序

Table2 中的行编号:

  • ROW_NR 总是 1

有了它,您可以在数据字段上隐式联接而无需完全匹配。很抱歉没有提供 SQL 声明。

我花了几个小时思考这个问题,进一步简化了示例代码

我认为这更有意义,我感谢所有回复并试图帮助回答我所写内容的人。它有帮助,但我仍然无法让它工作。