SQL Server 2014 從表中提取值,行列和小計中的雙重連接
我有一張歐洲央行每日匯率表
FXDate EUR USD AUD BGN BRL CAD CHF .... 30/06/2017 00:00 1.00 1.1412 1.4851 1.9558 3.76 1.4785 1.093 29/06/2017 00:00 1.00 1.1413 1.4868 1.9558 3.7476 1.4867 1.0935 28/06/2017 00:00 1.00 1.1375 1.4986 1.9558 3.7632 1.4888 1.0913 27/06/2017 00:00 1.00 1.1278 1.4819 1.9558 3.7216 1.4895 1.0883 26/06/2017 00:00 1.00 1.1187 1.4771 1.9558 3.7259 1.4812 1.0881 23/06/2017 00:00 1.00 1.1173 1.4764 1.9558 3.7293 1.4783 1.0851 22/06/2017 00:00 1.00 1.1169 1.4812 1.9558 3.7164 1.4853 1.0867 21/06/2017 00:00 1.00 1.1147 1.4738 1.9558 3.7028 1.4803 1.0857 20/06/2017 00:00 1.00 1.1156 1.4674 1.9558 3.6845 1.4812 1.0854 19/06/2017 00:00 1.00 1.1199 1.4705 1.9558 3.6957 1.4827 1.087
然後我有一個這樣的銷售表:
UserName Purchasedate Currency Price Quantity John 24/06/2017 14:53 EUR 5.4 3 Jude 24/06/2017 18:47 USD 4 2 Jack 25/06/2017 07:34 USD 6.35 2 Jill 25/06/2017 11:42 EUR 4.15 1 Joe 26/06/2017 11:13 USD 4.50 1
我需要創建一個表格,其中包含給定貨幣的最新匯率,以及每日金額的摘要(如果可能),如下所示:
UserName PurchaseDate Currency Price Quantity ExchangeRate ConvertedAmountEUR John 24/06/2017 EUR 5.4 3 1.00 16.20 Jude 24/06/2017 USD 4 2 1.1173 8.94 //Exchange rate of 23rd since for 24th is not available DAILY TOTAL 24/06/2017 25.14 Jack 25/06/2017 USD 6.35 2 1.1173 14.19 //Exchange rate of 23rd since for 24th is not available Jill 25/06/2017 EUR 4.15 1 1.00 4.15 DAILY TOTAL 25/06/2017 18.34 Joe 26/06/2017 USD 4.50 1 1.1187 5.03 //Exchange rate of 26th DAILY TOTAL 26/06/2017 5.03
我嘗試使用交叉連接來提取正確的匯率,但是存在“不匹配天數”的問題,而不能使用匯總進行小計,因為它需要分組,而我每次購買都需要單獨的行
甚至可以提出部分解決方案嗎?
謝謝
這可以逐步完成。
首先:我們有表格
sales
區分 thePurchaseDateTime
和 thePurchaseDate
:CREATE TABLE sales ( UserName varchar(100), PurchaseDateTime datetime, Currency character(3), Price numeric(10,2), Quantity numeric(10,2), PurchaseDate AS CAST(PurchaseDateTime AS date), -- Computed column PRIMARY KEY (UserName, PurchaseDateTime) ) ; -- Secondary index, to help some JOINs CREATE INDEX idx_sales_date ON sales(PurchaseDate, UserName);
這將使我們的生活更輕鬆,因為我們已經預先計算了日期。
您需要做的下一件事是取消透視
exchange_rate
表:CREATE TABLE #exchange_rates_EUR ( FXDate date, Currency char(3), ExchangeRate decimal(10,4), PRIMARY KEY (Currency, FXDate) ) ; INSERT INTO #exchange_rates_EUR SELECT FXDate, 'EUR' AS Currency, EUR AS ExchangeRate FROM exchange_rates_pivot UNION SELECT FXDate, 'USD' AS Currency, USD AS ExchangeRate FROM exchange_rates_pivot // do the same for all currencies .. omitted here for simplicity
注意:我使用了
exchange_rates_pivot
您原來的透視匯率表的名稱。您需要此中間步驟才能稍後在正確的 JOIN 上執行(實際上您不能在行和列中進行 JOIN。您不能將列名視為值
$$ at least, not in any easy fashion $$). 您也可以使用
UNPIVOT
SQL Server 中的基礎結構,但這更符合 SQL 標準,儘管可能效率不高。該表的內容如下所示:
SELECT TOP 12 * FROM #exchange_rates_EUR ORDER BY FXDate, Currency ;
外匯日期 | 貨幣 | 匯率 :------------------ | :------- | :----------- 19/06/2017 00:00:00 | 澳元 | 1.4705 19/06/2017 00:00:00 | BGN | 1.9558 19/06/2017 00:00:00 | 加元 | 1.4827 19/06/2017 00:00:00 | 瑞士法郎 | 1.0870 19/06/2017 00:00:00 | 歐元 1.0000 19/06/2017 00:00:00 | 美元 | 1.1199 20/06/2017 00:00:00 | 澳元 | 1.4674 20/06/2017 00:00:00 | BGN | 1.9558 20/06/2017 00:00:00 | 加元 | 1.4812 20/06/2017 00:00:00 | 瑞士法郎 | 1.0854 20/06/2017 00:00:00 | 歐元 1.0000 20/06/2017 00:00:00 | 美元 | 1.1156
您需要做的第二件事是找到您所有人的匯率
sales
並將資訊放在一起。對於每個特定的購買,匯率是通過以下方式找到的:
SELECT TOP 1 ExchangeRate FROM #exchange_rates_EUR er WHERE er.Currency = s.Currency AND er.FXDate <= s.PurchaseDate ORDER BY er.FXDate DESC ;
請注意, 和 的組合
TOP 1
將為ORDER BY
您提供當天的貨幣兌換,如果不可用,則為提供此資訊的最接近的先前日期;正如我從你的例子中推斷出來的。為了完整起見,它實際上應該除以歐元的匯率,以防匯率數據不是基於歐元 = 1.00。在這一點上,我還沒有做到不要使事情過於復雜。這將導致我們進行以下查詢:
SELECT q1.UserName, q1.PurchaseDate, q1.Currency, q1.Price, q1.Quantity, q1.ExchangeRate, CAST(q1.Price * q1.Quantity * q1.ExchangeRate AS decimal(10,2)) AS ConvertedAmountEUR FROM ( SELECT s.UserName, s.PurchaseDate, s.Currency, s.Price, s.Quantity, -- Subquery to retrieve Exchange Rate CAST ( (SELECT TOP 1 ExchangeRate FROM #exchange_rates_EUR er WHERE er.Currency = s.Currency AND er.FXDate <= s.PurchaseDate ORDER BY er.FXDate DESC ) AS decimal(10,4)) AS ExchangeRate FROM sales s ) AS q1 ORDER BY PurchaseDate, UserName ;
…這導致:
使用者名 | 購買日期 | 貨幣 | 價格 | 數量 | 匯率 | 兌換金額EUR :------- | :------------------ | :------- | :---- | :------- | :----------- | :----------------- 約翰 | 24/06/2017 00:00:00 | 歐元 | 5.40 | 3.00 | 1.0000 | 16.20 裘德 | 24/06/2017 00:00:00 | 美元 | 4.00 | 2.00 | 1.1173 | 8.94 傑克 | 25/06/2017 00:00:00 | 美元 | 6.35 | 2.00 | 1.1173 | 14.19 吉爾 | 25/06/2017 00:00:00 | 歐元 | 4.15 | 1.00 | 1.0000 | 4.15 喬 | 26/06/2017 00:00:00 | 美元 | 4.50 | 1.00 | 1.1187 | 5.03
最後,我們還計算“每日總計”,並
UNION ALL
使用我們已有的數據執行 a。在WITH
這種情況下,聲明會派上用場。需要一些小技巧來簡化排序(查找OrderBy
列)。這是通過以下語句完成的:
; WITH exchanged_sales AS ( SELECT q1.UserName, q1.PurchaseDate, q1.Currency, q1.Price, q1.Quantity, q1.ExchangeRate, CAST(q1.Price * q1.Quantity * q1.ExchangeRate AS decimal(10,2)) AS ConvertedAmountEUR, 0 AS OrderBy FROM ( SELECT s.UserName, s.PurchaseDate, s.Currency, s.Price, s.Quantity, -- Subqueries to retrieve Exchange Rate CAST ( (SELECT TOP 1 ExchangeRate FROM #exchange_rates_EUR er WHERE er.Currency = s.Currency AND er.FXDate <= s.PurchaseDate ORDER BY er.FXDate DESC) / (SELECT TOP 1 ExchangeRate FROM #exchange_rates_EUR er WHERE er.Currency = 'EUR' AND er.FXDate <= s.PurchaseDate ORDER BY er.FXDate DESC) AS decimal(10,4)) AS ExchangeRate FROM sales s ) AS q1 ) SELECT UserName, PurchaseDate, Currency, Price, Quantity, ExchangeRate, ConvertedAmountEUR FROM (-- The purchases date, user SELECT * FROM exchanged_sales UNION -- The daily totals SELECT 'DAILY TOTAL' AS UserName, PurchaseDate, NULL AS Currency, NULL AS Price, NULL AS Quantity, NULL AS ExchangeRate, SUM(ConvertedAmountEUR) AS ConvertedAmountEUR, 1 AS OrderBy FROM exchanged_sales GROUP BY PurchaseDate ) AS q ORDER BY PurchaseDate, OrderBy, UserName ;
…其結果是:
使用者名 | 購買日期 | 貨幣 | 價格 | 數量 | 匯率 | 兌換金額EUR :---------- | :----------- | :------- | :---- | :------- | :----------- | :----------------- 約翰 | 2017 年 6 月 24 日 | 歐元 | 5.40 | 3.00 | 1.0000 | 16.20 裘德 | 2017 年 6 月 24 日 | 美元 | 4.00 | 2.00 | 1.1173 | 8.94 每日總計 | 2017 年 6 月 24 日 | | | | | 25.14 傑克 | 25/06/2017 | 美元 | 6.35 | 2.00 | 1.1173 | 14.19 吉爾 | 25/06/2017 | 歐元 | 4.15 | 1.00 | 1.0000 | 4.15 每日總計 | 25/06/2017 | | | | | 18.34 喬 | 2017 年 6 月 26 日 | 美元 | 4.50 | 1.00 | 1.1187 | 5.03 每日總計 | 2017 年 6 月 26 日 | | | | | 5.03
您可以在此處查看**dbfiddle的所有分步詳細資訊
如果您只需要一個語句中的所有內容,則可以將 #exchange_rate 的等價物作為 WITH 的一部分。這會給你一個非常大的聲明,不是那麼容易閱讀……對於多合一版本的dbfiddle這裡