我有一张ExchangeRates表,其中包含countryid和exchangerate,这是有效的:
ExchangeRateID Country ToUSD ExchangeRateDate
1 Euro .7400 2/14/2011
2 JAP 80.1900 2/14/2011
3 Euro .7700 7/20/2011
请注意,根据日期,可能会有相同的国家/地区具有不同的费率...例如,2011年2月14日欧元的汇率为.7400,现在是.7700 7/20/2011。
我有另一个订单项表,可根据国家/地区列出项目。在此表格中,每个订单项都有与之关联的日期。订单项日期应根据汇率使用相应的日期和国家/地区。因此,如果我在2011年2月16日有一个国家/地区欧元的订单项,则使用上述数据时,应使用2011年2月14日的欧元值而不是7/20/2011的值,因为日期(条件er。 ExchangeRateDate< = erli.LineItemDate)。如果我在表中只有一个项目,但是假设我有一个项目日期为8/1/2011那么这个条件(er.ExchangeRateDate< = erliLineItemDate)将返回多行,因此我的查询将失败。
SELECT
er.ExchangeRateID,
er.CountryID AS Expr1,
er.ExchangeRateDate,
er.ToUSD,
erli.ExpenseReportLineItemID,
erli.ExpenseReportID,
erli.LineItemDate
FROM
dbo.ExpenseReportLineItem AS erli
LEFT JOIN
dbo.ExchangeRate AS er
ON er.CountryID = erli.CountryID
AND DATEADD(d, DATEDIFF(d, 0, er.ExchangeRateDate), 0) <= DATEADD(d, DATEDIFF(d, 0,
erli.LineItemDate), 0)
WHERE (erli.ExpenseReportID = 196)
这个左连接的问题是因为日期是&lt; =行项目日期所以它返回许多记录,我不得不以某种方式这样做但不知道如何。
LineItem表有多条记录,每条记录都有自己的CountryID:
Item Country ParentID LineItemDate
Line Item 1 Euro 1 2/14/2011
Line Item 2 US 1 2/14/2011
Line Item3 Euro 1 2/15/2011
所以有三条记录为ParentID(ExpenseReportID)= 1.那么我拿这些记录并加入ExchangeRate表,其中我的行项目表中的国家/地区=汇率表的国家/地区(该部分很容易)但是我要做的第二个条件是:
AND DATEADD(d, DATEDIFF(d, 0, er.ExchangeRateDate), 0) <= DATEADD(d, DATEDIFF(d, 0,
erli.LineItemDate), 0)
但问题出在这里是因为这会从我的汇率表中返回多行,因为欧元被列出两次。
答案 0 :(得分:3)
我可能在这里遗漏了一些东西,但据我所知,你的问题的“愚蠢”解决方案是使用A ROW_NUMBER函数和外部过滤器与现有的“返回太多条目”查询(这也可以通过CTE,但对于像这样的简单情况,我更喜欢派生表语法:
SELECT *
FROM (
SELECT
er.ExchangeRateID,
er.CountryID AS Expr1,
er.ExchangeRateDate,
er.ToUSD,
erli.ExpenseReportLineItemID,
erli.ExpenseReportID,
erli.LineItemDate,
ROW_NUMBER() OVER (PARTITION BY ExpenseReportID, ExpenseReportLineItemID ORDER BY ExchangeRateDate DESC) AS ExchangeRateOrderID
FROM dbo.ExpenseReportLineItem AS erli
LEFT JOIN dbo.ExchangeRate AS er
ON er.CountryID = erli.CountryID
AND DATEADD(d, DATEDIFF(d, 0, er.ExchangeRateDate), 0)
<= DATEADD(d, DATEDIFF(d, 0, erli.LineItemDate), 0)
WHERE (erli.ExpenseReportID = 196)
--For reasonable performance, it would be VERY nice to put a filter
-- on how far back the exchange rates can go here:
--AND er.ExchangeRateDate > DateAdd(Day, -7, GetDate())
) As FullData
WHERE ExchangeRateOrderID = 1
对不起,如果我误解了,否则希望这有帮助!
答案 1 :(得分:1)
如果你可以在你的ExchangeRates表中添加一个名为(类似的东西)的附加列,这会让你的生活变得更轻松
ExchangeRateToDate
单独的流程可以在添加新条目时更新上一个条目。
然后,你可以查询LineItemDate&gt; = ExhangeRateDate和&lt; = ExchangeRateToDate
(处理最后一个,可能是一个null的ExchangeRateToDate,作为特例)。
答案 2 :(得分:1)
我会创建一个内存表,用ExchangeRateDates From&amp;创建一个ExchangeRate表。要。
在此之后剩下要做的就是在您的查询中加入此CTE而不是您的ExchangeRate表,并添加条件,其中日期为between
日期来自/。
;WITH er AS (
SELECT rn = ROW_NUMBER() OVER (PARTITION BY er1.ExchangeRateID ORDER BY er2.ExchangeRateDate DESC)
, er1.ExchangeRateID
, er1.Country
, ExchangeRateDateFrom = ISNULL(DATEADD(d, 1, er2.ExchangeRateDate), 0)
, ExchangeRateDateTo = er1.ExchangeRateDate
, er1.ToUSD
FROM @ExchangeRate er1
LEFT OUTER JOIN @ExchangeRate er2
ON er1.Country = er2.Country
AND er1.ExchangeRateDate >= er2.ExchangeRateDate
AND er1.ExchangeRateID > er2.ExchangeRateID
)
SELECT er.ExchangeRateID,
er.CountryID AS Expr1,
er.ExchangeRateDateTo,
er.ToUSD,
erli.ExpenseReportLineItemID,
erli.ExpenseReportID,
erli.LineItemDate
FROM dbo.ExpenseReportLineItem AS erli
LEFT JOIN er ON er.CountryID = erli.CountryID
AND DATEADD(d, DATEDIFF(d, 0, er.ExchangeRateDateTo), 0) <= DATEADD(d, DATEDIFF(d, 0, erli.LineItemDate), 0)
AND DATEADD(d, DATEDIFF(d, 0, er.ExchangeRateDateFrom), 0) >= DATEADD(d, DATEDIFF(d, 0, erli.LineItemDate), 0)
WHERE (erli.ExpenseReportID = 196)
and er.rn = 1
DECLARE @ExchangeRate TABLE (
ExchangeRateID INTEGER
, Country VARCHAR(32)
, ToUSD FLOAT
, ExchangeRateDate DATETIME
)
INSERT INTO @ExchangeRate
VALUES (1, 'Euro', 0.7400, '02/14/2011')
, (2, 'JAP', 80.1900, '02/14/2011')
, (3, 'Euro', 0.7700, '07/20/2011')
, (4, 'Euro', 0.7800, '07/25/2011')
;WITH er AS (
SELECT rn = ROW_NUMBER() OVER (PARTITION BY er1.ExchangeRateID ORDER BY er2.ExchangeRateDate DESC)
, er1.ExchangeRateID
, er1.Country
, ExchangeRateDateFrom = ISNULL(DATEADD(d, 1, er2.ExchangeRateDate), 0)
, ExchangeRateDateTo = er1.ExchangeRateDate
, ToUSD = er1.ToUSD
FROM @ExchangeRate er1
LEFT OUTER JOIN @ExchangeRate er2
ON er1.Country = er2.Country
AND er1.ExchangeRateDate >= er2.ExchangeRateDate
AND er1.ExchangeRateID > er2.ExchangeRateID
)
SELECT *
FROM er
WHERE rn = 1
答案 3 :(得分:0)
也许您可以尝试使用table expression进入TOP 1,然后加入表格表达式。那有意义吗?希望这可以帮助。
答案 4 :(得分:0)
这可以通过使用一个或多个CTE来解决。这个早期的SO问题应该有所需的构建块: How can you use SQL to return values for a specified date or closest date < specified date?
请注意,您必须将此修改为您自己的架构,并过滤掉更接近但未来的结果。 我希望这会有所帮助,但如果还不够,那么我相信我可以发布更详细的答案。
答案 5 :(得分:0)
您可以将此作为相关子查询使用,该子查询将为您提供一个表格,其中包含给定日期的最新交换值(在评论中指明):
SELECT *
FROM er
INNER JOIN
(
SELECT CountryID, MAX(ExchangeRateDate) AS ExchangeRateDate
FROM er
WHERE ExchangeRateDate <= '9/1/2011'
-- the above is the date you will need to correlate with the main query...
GROUP BY Country
) iq
ON iq.Country = er.Country AND er.ExchangeRateDate = iq.ExchangeRateDate
因此完整查询应如下所示:
SELECT
iq2.ExchangeRateID,
iq2.CountryID AS Expr1,
iq2.ExchangeRateDate,
iq2.ToUSD,
erli.ExpenseReportLineItemID,
erli.ExpenseReportID,
erli.LineItemDate
FROM dbo.ExpenseReportLineItem AS erli
LEFT JOIN
(
SELECT *
FROM ExchangeRate er
INNER JOIN
(
SELECT CountryID, MAX(ExchangeRateDate) AS ExchangeRateDate
FROM ExchangeRate er
WHERE ExchangeRateDate <= erli.LineItemDate
-- the above is where the correlation occurs...
GROUP BY Country
) iq
ON iq.Country = er.Country AND er.ExchangeRateDate = iq.ExchangeRateDate
) iq2
ON er.CountryID = erli.CountryID
AND DATEADD(d, DATEDIFF(d, 0, iq2.ExchangeRateDate), 0) <= DATEADD(d, DATEDIFF(d, 0, erli.LineItemDate), 0)
WHERE (erli.ExpenseReportID = 196)
答案 6 :(得分:0)
如果我不误解你想做什么,你可以使用外部申请来获得最新的汇率。
select *
from ExpenseReportLineItem erli
outer apply (select top 1 *
from ExchangeRates as er1
where er1.Country = erli.Country and
er1.ExchangeRateDate <= erli.LineItemDate
order by er1.ExchangeRateDate desc) as er