是否有可能在各个列中逐步减去值来创建PIVOT?

时间:2019-03-25 12:02:47

标签: sql sql-server

有人可以建议我,如何通过一些计算来创建PIVOT? 带有“真实数据”的简单PIVOT没问题,但是我不知道如何包括一些基本的计算,例如在某些列之间减去值...

请,如果您有能力,请尝试使用下面的表和数据示例...

-- Structure
-- ---------

-- Table of Products
CREATE TABLE ListProducts
(
    ProductID INT IDENTITY(1,1) PRIMARY KEY,
    Name NVARCHAR(25)
);

-- Table of Processes
CREATE TABLE ListProcesses
(
    ProcessID INT IDENTITY(1,1) PRIMARY KEY,
    Name NVARCHAR(25)
);

-- DataTable
CREATE TABLE Production
(
    ProductionID INT IDENTITY(1,1) PRIMARY KEY,
    ProductID INT FOREIGN KEY REFERENCES ListProducts(ProductID),
    ProcessID INT FOREIGN KEY REFERENCES ListProcesses(ProcessID),
    Amount INT
);

-- Data
-- ----

INSERT INTO ListProducts(Name) VALUES ('Product1'),('Product2'),('Product3');

INSERT INTO ListProcesses(Name) VALUES ('Process1'),('Process2'),('Process3');

INSERT INTO Production(ProductID,ProcessID,Amount) VALUES
(1,1,25),(2,1,15),(3,1,20),(1,2,10),(2,2,10),(3,2,5),(1,3,5),(2,3,5);

我想像这样获得PIVOT:

| Products | Process1 | Process2 | Process3 |
| Product1 |       15 |        5 |        5 |
| Product2 |        5 |        5 |        5 |
| Product3 |       15 |        5 |     NULL |

您可以看到-输出不像简单的PIVOT,但我的每一个“上一个”列都减去了“下一个”列(当然,最后一列除外)...

非常感谢! :)

3 个答案:

答案 0 :(得分:2)

您可以使用条件聚合:

select lpr.name,
       sum(case when p.processid = 1 then p.amount when p.processid = 2 then -p.amount end) as process1,
       sum(case when p.processid = 2 then p.amount when p.processid = 3 then -p.amount end) as process2,
       sum(case when p.processid = 3 then p.amount end) as process3
from production p join
     listproducts lpr
     on p.productid = lpr.productid join
     listprocesses lpro
     on p.processid = lpro.processid
group by lpr.name;

Here是db <>小提琴。

答案 1 :(得分:0)

您可以像使用PIVOTLEAD一样编写查询。

select [name] as Products, Process1, Process2, Process3 
from   (select t1.Name, 
               t2.amount - Isnull((Lead(t2.amount) 
                                      over(partition by T2.productid 
                                        order by t2.processid ) ), 0) amount, 
               t3.Name as ProcesName 
        from   listproducts t1 
               inner join production t2 
                       ON t1.productid = t2.productid 
               inner join listprocesses t3 
                       ON t3.processid = t2.processid) t 
       pivot ( max(amount) 
             for procesname in ([Process1], 
                                [Process2], 
                                [Process3]) ) pvt 

Online Demo

答案 2 :(得分:0)

您可以在下面使用lead()函数进行尝试

DEMO

with cte as
(
select *,case when processname<>'process3' then 
amount-coalesce(lead(amount) over(partition by productname order by processname),0) else amount end as amt from 
(
select b.name as productname, c.name as processname,amount
from Production a
inner join ListProducts b on a.productid=b.ProductID
inner join ListProcesses c on a.ProcessID=c.ProcessID
)A
)

select productname, max(case when processname='Process1' then amt end) as process1,
max(case when processname='Process2' then amt end) process2,
max(case when processname='Process3' then amt end) process3
from cte 
group by productname

输出:

productname process1    process2    process3
Product1    15            5           5
Product2    5             5           5
Product3    15            5