如何找到两个行值的差异并将其存储在同一个表中的第三行?

时间:2014-05-14 05:29:48

标签: sql-server

我想找到一个表的两行之间的差异,并将差值插入同一个表中的第三行。如果第一行值小于第二行,则差异应出现在括号内而不是负符号中。

例如:

Name        S1   S2   S3   S4

xxx         98   70   50   85    
xxx1        50   90   35  105    
Diff        48  (20)  15  (20)

请说是否可以在前端,也就是在gridview中存储值之后。但在Gridview中,colums和rows是Transposed。然后在网格视图中将两列存储的差异存储为第三个新列。

2 个答案:

答案 0 :(得分:0)

以下是一些可以执行此操作的代码:

SELECT
     Name
    ,S1
    ,S2
FROM 
(
    select
         x.Name as xName
        ,CONVERT(varchar(99), x.S1) as xS1      -- Have to convert everything since you require negatives as ()
        ,CONVERT(varchar(99), x.S2) as xS2
        ,1 as xOrder                            -- To ensure the rows are presented as requested

        ,x1.Name as x1Name
        ,CONVERT(varchar(99), x1.S1) as x1S1
        ,CONVERT(varchar(99), x1.S2) as x1S2
        ,2 as x1Order

        ,case 
            when SIGN(x.S1 - x1.S1) = -1 
                then '(' + CONVERT(varchar(99), x.S1 - x1.S1) + ')'
            else CONVERT(varchar(99), x.S1 - x1.S1)
        end as d1
        ,case 
            when SIGN(x.S2 - x1.S2) = -1 
                then '(' + CONVERT(varchar(99), x.S2 - x1.S2) + ')'
            else CONVERT(varchar(99), x.S2 - x1.S2)
        end as d2
        -- etc for S3 and S4
        ,3 as DiffOrder
    from
        (select * from dbo.Data where Name = 'xxx') as x
    inner join
        (select * from dbo.Data where Name = 'xxx1') as x1
        on x1.Name = x.Name + '1'   -- I suspect your row matching conditin will have 
                                    -- to me more sophisticated that this in realit
) as Data
-- The cross apply does an UNPIVOT on the cheap
CROSS APPLY ( VALUES
                (xName, xS1, xS2, xOrder),
                (x1Name, x1S1, x1S2, x1Order),
                ('Diff', d1, d2, DiffOrder)
            ) -- Close paren from the CROSS APPLY
            as ca(Name, S1, S2, SortOrder)
order by ca.SortOrder;

让你的表示层执行底片的格式化要好得多。

因为您需要以这种方式呈现的否定,所以列必须是CONVERTed字符类型。这增加了SQL的复杂性。这也可能意味着他们不再是右对齐的。同样,优秀的演示软件应该能够比SQL更好地为您处理。

我怀疑在你的实际系统中你会有很多行对。你还没有说明与他们匹配的规则是什么。您必须将其添加到代码中。请务必更改排序以解决此问题。

如果您发现布局更易于理解和维护,则可以使用CTE重新格式化代码。

答案 1 :(得分:0)

我不知道你打算如何将varchar插入数字列。我假设s1-s4是数字,因为它们应该是。

你的数据是颠倒过来的,所以最好先将它旋转90度进行计算,然后在结果后再将其旋转显示正确:

declare @t table(Name varchar(4), S1 int, S2 int, S3 int, S4 int)

insert @t values('xxx',98,70,50,85),
('xxx1',50,90,35,105)
--Diff        48  (20)  15  (20)

-- this next part can be put into a view

;with cte as
(
select 
sum(case when Name = 'xxx' then Value else -value end) Total, Col 
from @t t1
UNPIVOT      
(Value FOR Col IN           
([S1], [S2], [S3], [S4]) ) AS unpvt  
group by col
), cte2 as
(
select case when Total < 0 then 
'(' + cast(-Total as varchar(10))+')'
else cast(Total as varchar(10)) end Totalvarchar, Col
from cte
)
select Name, 
cast(S1 as varchar(20)) S1, cast(S2 as varchar(20)) S2, 
cast(S3 as varchar(20)) S3, cast(S4 as varchar(20)) S4
from @t
union all
select 'Diff' Name, [S1], [S2], [S3], [S4]
from
cte2
PIVOT (max(TotalVarchar) FOR [Col] IN ([S1], [S2], [S3], [S4])) AS pvt 

结果:

Name   S1   S2   S3   S4
xxx    98   70   50   85
xxx1   50   90   35  105
Diff   48 (20)   15 (20)