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 声明。
我花了几个小时思考这个问题,进一步简化了示例代码 。
我认为这更有意义,我感谢所有回复并试图帮助回答我所写内容的人。它有帮助,但我仍然无法让它工作。
这似乎是一个重复问题,但并不是因为论坛中的其他解决方案在这种情况下不起作用。
这是对我们的 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 声明。
我花了几个小时思考这个问题,进一步简化了示例代码
我认为这更有意义,我感谢所有回复并试图帮助回答我所写内容的人。它有帮助,但我仍然无法让它工作。