SQL - 从同一列中减去值

时间:2014-05-05 11:22:39

标签: sql sql-server-2008

我有一张表如下

fab_id  x  y  z  m  
12      14 10 3  5
12      10 10 3  4

这里我在id上使用group by子句。现在我要减去那些具有相似id的列值。 例如,按id(12)分组。现在减去(14-10)X,(10-10)Y,(3-3)z,(5-4)m

我知道有一个加法的聚合函数和,但是我可以用它来减去这个值。

还是有其他方法可以达到效果。

注意 - 可能会有变化,可能会出现-ve值。那么任何函数都可以处理这个吗?

又一个例子 - (通过correction_date desc命令,因此结果将首先显示最近的修正)

fab_id  x  y  z  m  correction_date
14      20 12 4  4   2014-05-05 09:03
14      24 12 4  3   2014-05-05 08:05
14      26 12 4  6   2014-05-05 07:12

所以在id(14)上实现group by的结果。现在减去(26-20)X,(12-12)Y,(4-4)z,(6-4)m

7 个答案:

答案 0 :(得分:2)

现在,您已经提供了有关如何处理更多记录的更多信息,并且您发现涉及时间列,这是一个可能的解决方案。查询选择每个fab_id的第一个和最后一个记录,并减去值:

select 
  fab_info.fab_id,
  earliest_fab.x - latest_fab.x,
  earliest_fab.y - latest_fab.y,
  earliest_fab.z - latest_fab.z,
  earliest_fab.m - latest_fab.m
from 
(
  select 
    fab_id, 
    min(correction_date) as min_correction_date,
    max(correction_date) as max_correction_date
  from fab
  group by fab_id
) as fab_info
inner join fab as earliest_fab on 
  earliest_fab.fab_id = fab_info.fab_id and 
  earliest_fab.min_correction_date = fab_info.min_correction_date
inner join fab as latest_fab on 
  latest_fab.fab_id = fab_info.fab_id and 
  latest_fab.min_correction_date = fab_info.max_correction_date;

答案 1 :(得分:1)

如果您总想从最大值中减去最小值:

select 
  fab_id, 
  max(x) - min(x), 
  max(y) - min(y), 
  max(z) - min(z), 
  max(m) - min(m)
from fab
group by fab_id;

答案 2 :(得分:1)

如你所说,总会有两行,你可以简单地做一个'自联接'并相互减去值:

SELECT t1.fab_id, t1.x - t2.x as diffx, t1.y - t2.y as diffy, <remainder columns here>
from <table> t1
inner join <table> t2 on t1.fab_id = t2.fab_id and t1.correctiondate > t2.correctiondate

如果您有两行以上,那么您需要创建子查询或使用窗口排名函数来计算每个fab_id的最大和最小校正日期,然后您可以通过加入这两个子查询来完成与上面相同的操作一起而不是

答案 3 :(得分:1)

;with Ordered as 
(
select 
    fab_id,x,y,z,m,date, 
    row_Number() over (partition by fab_id order by date desc) as Latest,
    row_Number() over (partition by fab_id order by date) as Oldest
from fab
)
select 
   O1.fab_id, 
   O1.x-O2.x,
   O1.y-O2.y, 
   O1.z-O2.z, 
   O1.m-O2.m
from Ordered O1 
join Ordered O2 on 
O1.fab_id = O2.fab_id
where O1.latest = 1 and O2.oldest = 1  

答案 4 :(得分:1)

不幸的是,它的SQL Server 2012具有方便的FIRST_VALUE() / LAST_VALUE() OLAP功能,因此在超过2行的情况下,我们必须做一些不同的事情:< / p>

SELECT fab_id, SUM(CASE WHEN latest = 1 THEN -x ELSE x END) AS x,
               SUM(CASE WHEN latest = 1 THEN -y ELSE y END) AS y,
               SUM(CASE WHEN latest = 1 THEN -z ELSE z END) AS z,
               SUM(CASE WHEN latest = 1 THEN -m ELSE m END) AS m

FROM (SELECT fab_id, x, y, z, m,
             ROW_NUMBER() OVER(PARTITION BY fab_id 
                               ORDER BY correction_date ASC) AS earliest,
             ROW_NUMBER() OVER(PARTITION BY fab_id 
                               ORDER BY correction_date DESC) AS latest
      FROM myTable) fab
WHERE earliest = 1
      OR latest = 1
GROUP BY fab_id
HAVING COUNT(*) >= 2

(和working fiddle。感谢@ AK47进行初始设置。)

产生预期的结果:

FAB_ID   X   Y   Z   M
12       4   0   0   1
14       6   0   0   2

请注意,HAVING COUNT(*) >= 2只会考虑包含更改的行(否则您将获得一些空结果列)。

答案 5 :(得分:-1)

我认为如果你有一致的行或两行,那么下面的代码应该适合你。

select fab_id ,max(x) - min(x) as x
        ,max(y) - min(y) as y
            ,max(z) - min(z) as z
            ,max(m) - main(m) as m
            from Mytable
group by fab_id

即使您在组中获得超过2行,它也会起作用,但减法将来自最小值的最大值。希望它可以帮助你。

编辑:SQL小提琴DEMO

答案 6 :(得分:-1)

CTE可以提供帮助:

WITH cte AS (
    SELECT
        -- Get the row numbers per fab_id ordered by the correction date
        ROW_NUMBER() OVER (PARTITION BY fab_id ORDER BY correction_date ASC) AS rid
        , fab_id, x, y, z, m
    FROM
        YourTable
)
SELECT
    fab_id
    -- If the row number is 1 then, this is our base value
    -- If the row number is not 1 then, we want to subtract it (or add the negative value)
    , SUM(CASE WHEN rid = 1 THEN x ELSE x * -1 END) AS x
    , SUM(CASE WHEN rid = 1 THEN y ELSE y * -1 END) AS y
    , SUM(CASE WHEN rid = 1 THEN z ELSE z * -1 END) AS z
    , SUM(CASE WHEN rid = 1 THEN m ELSE m * -1 END) AS m
FROM
    cte
GROUP BY
    fab_id

请记住,40-10-20等于40 +( - 10)+( - 20)