我有一个包含发票的大型数据集,我需要执行一些货币转换。获取数据需要很多加入,但基本的想法是,一张桌子的单独发票费用是美元,而另一张桌子的收费是本地货币,但没有。发票上的个别费用以当地货币提供,因此我需要通过将当地货币总额除以美元总额来计算有效汇率,然后将费用乘以此费率。到目前为止,我已成功完成了以下单条记录:
DECLARE @USD_Total float, @LOC_Total float, @FX_Rate float
SET @USD_Total = (Select SUM (InvoiceTable.USD_ChargeAmount)
FROM
{Some Joins}
WHERE InvoiceID in ('1234567')
Group By InvoiceTable.InvoiceID)
SET @LOC_Total = (Select LocalInvoiceTable.ChargeTotal
FROM
{Some Joins}
WHERE InvoiceID in ('1234567')
Group By LocalInvoiceTable.InvoiceID
SET @FX_Rate = @LOC_Total / @USD_Total
SELECT
InvoiceTable.InvoiceID
SUM(CASE InvoiceTable.ChargeCode when 'TYPE A' THEN InvoiceTable.USD_ChargeAmount ELSE 0 END)*@FX_Rate As Type_A,
SUM(CASE InvoiceTable.ChargeCode when 'TYPE B' THEN InvoiceTable.USD_ChargeAmount ELSE 0 END)*@FX_Rate As Type_B,
SUM(CASE InvoiceTable.ChargeCode when 'TYPE C' THEN InvoiceTable.USD_ChargeAmount ELSE 0 END)*@FX_Rate As Type_C
FROM
{Some Joins}
WHERE InvoiceID in ('1234567')
Group By LocalInvoiceTable.InvoiceID
所以这很好用,但我需要复制数千个发票ID。如何在没有WHERE子句的情况下完成此操作?我是这方面的新手,所以非常感谢任何帮助。我正在使用Microsoft SQL Server 2008。
答案 0 :(得分:0)
是的,你可以。不,你不应该
这只是一个糟糕的编程习惯。您应该分离并隔离程序的不同部分,以便日后维护(想想下一个程序员!)
SQL是一种数据持久化语言,它不是一种很好的过程语言
一定要使用SQL为报表等选择复杂的数据表示。但这里有的是嵌入到数据请求中的业务规则(逻辑)。这些业务规则还在哪里重复?
业务规则应存在于一个且仅存在一个地方,并从那里引用(参见DRY principle)。如果您将业务规则分散到整个系统中,它将很快变得不可维护。历史已经一次又一次地显示出来
使用您选择的服务客户端语言(Java,c#等等,任何体面的OO语言都可以)来完成此任务。对每个数据集一次性选择所有发票号。将整个事物包装在显式事务中,以便在需要时确保稳定的结果
答案 1 :(得分:0)
您不得将其视为程序性程序。 SQL是一种用于集合操作的语言。您需要考虑计算列和连接等术语。首先,您需要按发票计算美元总数,然后将其加入LocalInvoiceTable并除以ChargeTotal以获得外汇汇率。最后加入InvoiceTable并将每个单独的费用乘以外汇汇率。
with UsdTotal as
(
select InvoiceID, sum(USD_ChargeAmount) as USD_ChargeTotal
from InvoiceTable
group by InvoiceID
)
, FxRate as
(
select lit.InvoiceID, lit.ChargeTotal / ut.USD_ChargeTotal as Rate
from LocalInvoiceTable lit
inner join UsdTotal ut
on ut.InvoiceID = lit.InvoiceID
)
select
it.InvoiceId,
it.USD_ChargeAmount as UsdValue,
it.USD_ChargeAmount * fx.Rate as LocalCcyValue
from InvoiceTable it
inner join FxRate fx on fx.InvoiceID = it.InvoiceID
您可以在SQLFiddle中试用。请注意,外汇汇率每天都在变化。如果个人收费在不同的日子实现,则您无法获得有效的外汇汇率和平均值。因此,以当地货币计算的金额将与实际金额不同。
答案 2 :(得分:-1)
不要考虑个别行。您有一组行,因此请根据每个问题的集合进行思考。使用CTE,您可以封装每个部分(问题的每个部分的结果集),并将答案组合在其他CTE或最终查询中。
您的查询的以下修改显示3个CTE:
最后,在主查询中,我们使用有效汇率计算的结果
;WITH USD AS (
SELECT InvoiceID, SUM(InvoiceTable.USD_ChargeAmount) AS [Total]
FROM
{Some Joins}
GROUP BY InvoiceTable.InvoiceID
),
LOC AS (
SELECT InvoiceID, SUM(LocalInvoiceTable.ChargeTotal) AS [Total]
FROM
{Some Joins}
GROUP BY LocalInvoiceTable.InvoiceID
),
FX AS (
SELECT USD.InvoiceID,
CONVERT(MONEY, LOC.Total) / CONVERT(MONEY, USD.Total) AS [Rate]
FROM USD
INNER JOIN LOC
ON LOC.InvoiceID = USD.InvoiceID
),
SELECT InvoiceTable.InvoiceID,
SUM(CASE InvoiceTable.ChargeCode
when 'TYPE A' THEN InvoiceTable.USD_ChargeAmount
ELSE 0 END) * FX.[Rate] AS [Type_A],
SUM(CASE InvoiceTable.ChargeCode
when 'TYPE B' THEN InvoiceTable.USD_ChargeAmount
ELSE 0 END) * FX.[Rate] AS [Type_B],
SUM(CASE InvoiceTable.ChargeCode
when 'TYPE C' THEN InvoiceTable.USD_ChargeAmount
ELSE 0 END) * FX.[Rate] AS [Type_C]
FROM InvoiceTable
{Some Joins}
INNER JOIN FX
ON FX.InvoiceID = InvoiceTable.InvoiceID
修改强>
更多理想的方法是存储插入InvoiceTable和LocalInvoiceTable行时使用的汇率。您可以使用类似于:
InvoiceInfo
(
InvoiceID INT NOT NULL, -- PK, FK to InvoiceTable
ExchangeRate SMALLMONEY NOT NULL,
CurrencyCode CHAR(3) NOT NULL, -- USD, EUR, etc.
InvoiceTotalUSD MONEY, -- optional
InvoiceTotalLocal MONEY -- optional
)
我建议使用ISO 4217货币代码。两个InvoiceTotal *字段仅适用于您需要通过InvoiceID聚合而不需要计算"有效汇率"。
在创建发票时存储信息会将您的查询简化为:
SELECT InvoiceTable.InvoiceID,
SUM(CASE InvoiceTable.ChargeCode
when 'TYPE A' THEN InvoiceTable.USD_ChargeAmount
ELSE 0 END) * II.[ExchangeRate] AS [Type_A],
SUM(CASE InvoiceTable.ChargeCode
when 'TYPE B' THEN InvoiceTable.USD_ChargeAmount
ELSE 0 END) * II.[ExchangeRate] AS [Type_B],
SUM(CASE InvoiceTable.ChargeCode
when 'TYPE C' THEN InvoiceTable.USD_ChargeAmount
ELSE 0 END) * II.[ExchangeRate] AS [Type_C]
FROM InvoiceTable
{Some Joins}
INNER JOIN InvoiceInfo II
ON II.InvoiceID = InvoiceTable.InvoiceID