数学与SQL中的前一行,避免嵌套查询?

时间:2010-01-08 13:35:01

标签: sql db2

我想对SQL请求中的前几行进行一些数学运算,以避免在我的代码中执行此操作。

我有一个表格,代表两个实体的销售额(这里所代表的数据没有多大意义,只是一个摘录):

YEAR    ID      SALES             PURCHASE         MARGIN
2009    1       10796820,57       2662369,19       8134451,38
2009    2        2472271,53       2066312,34        405959,19
2008    1        9641213,19       1223606,68       8417606,51
2008    2        3436363,86       2730035,19        706328,67

我想知道销售,购买,保证金......是如何发展的,并将其与前一年进行比较。

简而言之,我想要一个预先计算好的演变的SQL结果:

YEAR    ID    SALES         SALES_EVOLUTION    PURCHASE      PURCHASE_EVOLUTION  MARGIN        MARGIN_EVOLUTION
2009    1     10796820,57   11,99              2662369,19    117,58              8134451,38     -3,36
2009    2      2472271,53   -28,06             2066312,34    -24,31               405959,19    -42,53
2008    1      9641213,19                      1223606,68                        8417606,51 
2008    2      3436363,86                      2730035,19                         706328,67 

我可以做一些丑陋的事情:

SELECT *, YEAR, ID, SALES , (SALES/(SELECT SALES FROM TABLE WHERE YEAR = OUTER_TABLE.YEAR-1 AND ID = OUTER_TABLE.ID) -1)*100 as SALES_EVOLUTION (...) 
FROM TABLE as OUTER_TABLE 
ORDER BY YEAR DESC, ID ASC

但我有20个字段,我必须做一个嵌套查询,这意味着我会有一个非常庞大和丑陋的查询。

有没有更好的方法来做这个,少用SQL?

3 个答案:

答案 0 :(得分:2)

旧skool解决方案:

SELECT c.YEAR, c.ID, c.SALES, c.PURCHASE, c.MARGIN
,      p.YEAR, p.ID, p.SALES, p.PURCHASE, p.MARGIN
FROM       tab AS c -- current
INNER JOIN tab AS p -- previous
ON         c.year = p.year - 1
AND        c.id   = p.id

如果您有一个具有分析功能的数据库(MS SQL,Oracle),您可以使用LEAD或LAG分析函数,请参阅http://www.oracle-base.com/articles/misc/LagLeadAnalyticFunctions.php

我认为这是正确的应用程序:

SELECT     c.YEAR, c.ID, c.SALES, c.PURCHASE, c.MARGIN
,          LAG(c.YEAR, 1, 0) OVER (ORDER BY ID,YEAR)
,          LAG(c.ID, 1, 0) OVER (ORDER BY ID,YEAR)
,          LAG(c.SALES, 1, 0) OVER (ORDER BY ID,YEAR)
,          LAG(c.PURCHASE, 1, 0) OVER (ORDER BY ID,YEAR)
,          LAG(c.MARGIN, 1, 0) OVER (ORDER BY ID,YEAR)
FROM       tab AS c -- current

(不太确定,还没玩过这么多)

答案 1 :(得分:2)

使用sql server(但这应该适用于几乎所有的sql),提供的表可以使用 LEFT JOIN

DECLARE @Table TABLE(
        [YEAR] INT,
        ID INT,
        SALES FLOAT,           
        PURCHASE FLOAT,     
        MARGIN FLOAT
)

INSERT INTO @Table ([YEAR],ID,SALES,PURCHASE,MARGIN) SELECT 2009,1,10796820.57,2662369.19,8134451.38 
INSERT INTO @Table ([YEAR],ID,SALES,PURCHASE,MARGIN) SELECT 2009,2,2472271.53,2066312.34,405959.19 
INSERT INTO @Table ([YEAR],ID,SALES,PURCHASE,MARGIN) SELECT 2008,1,9641213.19,1223606.68,8417606.51 
INSERT INTO @Table ([YEAR],ID,SALES,PURCHASE,MARGIN) SELECT 2008,2,3436363.86,2730035.19,706328.67 


SELECT  cur.*,
        ((cur.Sales / prev.SALES) - 1) * 100
FROM    @Table cur LEFT JOIN
        @Table prev ON cur.ID = prev.ID AND cur.[YEAR] - 1 = prev.[YEAR]

LEFT JOIN 将允许您仍然看到2008年的值,其中 INNER JOIN 不会

答案 2 :(得分:1)

你可以这样做:

SELECT t1.*, t1.YEAR, t1.ID, t1.SALES , ((t1.sales/t2.sales) -1) * 100 as SALES_EVOLUTION
 (...) 
FROM Table t1 JOIN Table t2 ON t1.Year = (t2.Year + 1) AND t1.Id = t2.Id
ORDER BY t1.YEAR DESC, t1.ID ASC

现在,如果你想比较更多年份,你必须做更多的连接,所以这是一个稍微丑陋的解决方案。