2017-10-14 76 views
0

我剛剛開始熟悉SQL,我發現語言很簡單,但也有時非常混亂。例如藉此聲明SQL百分比優雅

SELECT transaction.ID, 
     dt, 
     bundles.package_name as "Package Name", 
     amount_usd, 
     unit_sales, 
CASE 
    WHEN sum(amount_usd) = 0 THEN 0 
    ELSE round(amount_usd*100/ (SELECT sum(amount_usd) FROM transaction 
      WHERE (transaction.code = 'AA') 
      AND (transaction.country_code = 'US') 
      AND (dt BETWEEN '2016-01-01' and '2016-01-04')),2) 
END as percentage 

FROM transaction 
    JOIN bundles 
    ON transaction.package_id= cast(bundles.id as INT) 

WHERE (transaction.code = 'AA') 
AND (transaction.country_code = 'US') 
AND (dt BETWEEN '2016-01-01' and '2016-01-04') 

GROUP BY transaction.ID, dt, "Package Name" 
ORDER BY transaction.ID 
limit 1000 

我發現浪費一點點不得不重複SELECT加上只是正確計算的百分比。有沒有更優雅的解決方案來避免這種情況?


下面是我如何修復它。

如果你想在總量的百分數,你不一定需要嵌套

SELECT t.ID, dt, b.package_name as "Package Name", 
     SUM(amount_usd) as amount_usd, SUM(unit_sales) as unit_sales, 
     SUM(amount_usd) * 1.0/SUM(amount_usd) OVER() as ratio 
FROM transaction t JOIN 
    bundles b 
    ON t.package_id = cast(b.id as INT) 
WHERE (t.code = 'AA') AND 
     (t.country_code = 'US') AND 
     (dt BETWEEN '2016-01-01' and '2016-01-04') 
GROUP BY t.ID, dt, "Package Name" 
ORDER BY t.ID 
LIMIT 1000; 

如果你想收入超過每天總的比你做

SELECT t.ID, dt, b.package_name as "Package Name", 
     SUM(amount_usd) as amount_usd, SUM(unit_sales) as unit_sales, 
     SUM(amount_usd) * 1.0/SUM(amount_usd) OVER (PARTITION BY dt) as ratio 
FROM transaction t JOIN 
    bundles b 
    ON t.package_id = cast(b.id as INT) 
WHERE (t.code = 'AA') AND 
     (t.country_code = 'US') AND 
     (dt BETWEEN '2016-01-01' and '2016-01-04') 
GROUP BY t.ID, dt, "Package Name" 
ORDER BY t.ID 
LIMIT 1000; 
+2

用你正在使用的數據庫標記你的問題。 –

+0

@GordonLinoff added –

回答

0

最SQL的方言支持ANSI標準窗口函數。另外,格式化通常在應用程序中稍後處理。

所以,這通常被寫爲:

SELECT t.ID, dt, b.package_name as "Package Name", 
     SUM(amount_usd) as amount_usd, SUM(unit_sales) as unit_sales, 
     SUM(amount_usd) * 1.0/NULLIF(SUM(SUM(amount_usd)) OVER()) as ratio 
FROM transaction t JOIN 
    bundles b 
    ON t.package_id = cast(b.id as INT) 
WHERE (t.code = 'AA') AND 
     (t.country_code = 'US') AND 
     (dt BETWEEN '2016-01-01' and '2016-01-04') 
GROUP BY t.ID, dt, "Package Name" 
ORDER BY t.ID 
LIMIT 1000; 

在您的查詢的其他問題:

  • 所有符合條件的列名時查詢有多個表。
  • 使用表縮寫作爲表別名 - 寫和讀更容易。
  • 不同表格上的JOIN鍵應該是相同的類型。事實上,他們應該被宣佈爲適當的外鍵關係。
  • 您錯過了SELECT中的某些聚合函數。確保只有未聚集的列是GROUP BY密鑰。

如果您的數據庫供應商不支持ANSI標準功能,那麼您應該採取這些措施。

+0

我假設你的意思是「*當一個**查詢**有多個表*」不「*當一個表有多個表時*」 –

+0

我得到「集合函數調用不能嵌套」 –

+0

@PasqualeSada。 。 。它是有效的ANSI標準SQL。如果您對某個特定數據庫有疑問,則應該使用您正在使用的數據庫標記問題。 –