Is there a way around using column(s) in group by? Pervasive SQL - pervasive

Is it possible to exclude columns from a group by clause? I have two columns (source & cause) that are a part of my select statement that have to be in the group by otherwise I get an error. My issue is that instead of one row for each Job sometimes I get another row that has a value in one of the columns in the group by. I understand why I get this other row, it's because it's in the group by clause but I'm wondering if there's anyway to fix this in the query? or should I try to fix it in php?
Query
select concat(concat(v_job_header.job,'-'),v_job_header.suffix) as Job,v_job_header.part,v_job_header.qty_order,
sum(case when v_job_operations_wc.workcenter = '0750' then v_job_operations_wc.hours_actual end) as WaterJet,
sum(case when v_job_operations_wc.workcenter IN ('0705','0710','0715') then v_job_operations_wc.hours_actual end) as Laser,
sum(case when v_job_operations_wc.workcenter IN ('0600','0610','1006','0650','1315') then v_job_operations_wc.hours_actual end) as Prep,
sum(case when v_job_operations_wc.workcenter IN ('1310','0755') then v_job_operations_wc.hours_actual end) as Machining,
sum(case when v_job_operations_wc.workcenter IN ('1515','1000','1002','1003','0901','1270') then v_job_operations_wc.hours_actual end) as Fab,
sum(case when v_job_operations_wc.workcenter = '1100' then v_job_operations_wc.hours_actual end) as Paint,
sum(case when v_job_operations_wc.workcenter = '1000' then v_job_operations_wc.hours_actual end) as Belts,
sum(case when v_job_operations_wc.workcenter = '1001' then v_job_operations_wc.hours_actual end) as Electrical,
sum(case when v_job_operations_wc.workcenter = '1520' then v_job_operations_wc.hours_actual end) as Crating_Skids,
sum(case when v_job_operations_wc.workcenter IN ('1004','1005','1350','1201') then v_job_operations_wc.hours_actual end) as Final_Assy,
sum(case when v_job_operations_wc.workcenter = '4330' then v_job_operations_wc.hours_actual end) as Shipping,
sum(v_job_operations_wc.hours_estimated) as total_hours_estimated,
gab_source_cause_codes.source,gab_source_cause_codes.cause
from v_job_header
left join v_job_operations_wc on v_job_operations_wc.job = v_job_header.job and v_job_header.suffix = v_job_operations_wc.suffix
left join gab_source_cause_codes on gab_source_cause_codes.job = v_job_operations_wc.job and gab_source_cause_codes.suffix = v_job_operations_wc.suffix and gab_source_cause_codes.seq = v_job_operations_wc.seq
where v_job_header.product_line = '01' and v_job_header.date_closed < '2019-01-01' and v_job_operations_wc.LMO = 'L' and v_job_operations_wc.seq < '99000'
group by Job,v_job_header.part,v_job_header.qty_order,gab_source_cause_codes.source,gab_source_cause_codes.cause
Sample data after running query
| Job | Part |q|Waterjet|Laser|Prep|Machining| Fab |Paint|Belt|elec|crating|final_assy|shipping|total_hours_estimated|source|cause|
|----------|------|-|--------|-----|----|---------|-----|-----|----|----|-------|----------|--------|---------------------|------|-----|
|A06063-002|908135|1| 0.03| 0.78| 1.1| 0.02| | | | 0 | | | 6.6743| | |
|A06097-001|906969|1| | .41|3.05| 9.49| | | | 0 | | | 8.4 | | |
|A06097-001|906969|1| | | | |21.99| | | | | | | 12.3|Machinging|Part Missing|
Expected
| Job | Part |q|Waterjet|Laser|Prep|Machining| Fab |Paint|Belt|elec|crating|final_assy|shipping|total_hours_estimated|source|cause|
|----------|------|-|--------|-----|----|---------|-----|-----|----|----|-------|----------|--------|---------------------|------|-----|
|A06063-002|908135|1| 0.03| 0.78| 1.1| 0.02| | | | 0 | | | 6.6743| | |
|A06097-001|906969|1| | .41|3.05| 9.49|21.99| | | | 0| | | 20.7|Machinging|Part Missing|

I added the min() function to the source and cause columns. This allowed me to take them out of the group by clause which got rid of the empty row if there was a value for source and cause.
I was able to get my desired output like this:
select concat(concat(v_job_header.job,'-'),v_job_header.suffix) as Job,v_job_header.part,v_job_header.qty_order,sum(case when v_job_operations_wc.workcenter = '0750' then v_job_operations_wc.hours_actual end) as WaterJet,
sum(case when v_job_operations_wc.workcenter IN ('0705','0710','0715') then v_job_operations_wc.hours_actual end) as Laser,
sum(case when v_job_operations_wc.workcenter IN ('0600','0610','1006','0650','1315') then v_job_operations_wc.hours_actual end) as Prep,
sum(case when v_job_operations_wc.workcenter IN ('1310','0755') then v_job_operations_wc.hours_actual end) as Machining,
sum(case when v_job_operations_wc.workcenter IN ('1515','1000','1002','1003','0901','1270') then v_job_operations_wc.hours_actual end) as Fab,
sum(case when v_job_operations_wc.workcenter = '1100' then v_job_operations_wc.hours_actual end) as Paint,
sum(case when v_job_operations_wc.workcenter = '1000' then v_job_operations_wc.hours_actual end) as Belts,
sum(case when v_job_operations_wc.workcenter = '1001' then v_job_operations_wc.hours_actual end) as Electrical,
sum(case when v_job_operations_wc.workcenter = '1520' then v_job_operations_wc.hours_actual end) as Crating_Skids,
sum(case when v_job_operations_wc.workcenter IN ('1004','1005','1350','1201') then v_job_operations_wc.hours_actual end) as Final_Assy,
sum(case when v_job_operations_wc.workcenter = '4330' then v_job_operations_wc.hours_actual end) as Shipping,
sum(v_job_operations_wc.hours_estimated) as total_hours_estimated,
min(gab_source_cause_codes.source),min(gab_source_cause_codes.cause)
from v_job_header
left join v_job_operations_wc on v_job_operations_wc.job = v_job_header.job and v_job_header.suffix = v_job_operations_wc.suffix
left join gab_source_cause_codes on gab_source_cause_codes.job = v_job_operations_wc.job and gab_source_cause_codes.suffix = v_job_operations_wc.suffix and gab_source_cause_codes.seq = v_job_operations_wc.seq
where v_job_header.product_line = '01' and v_job_header.date_closed < '2019-01-01' and v_job_operations_wc.LMO = 'L' and v_job_operations_wc.seq < '99000'
group by Job,v_job_header.part,v_job_header.qty_order

Related

SQL multiple conditions CASE WHEN and or

I have joined two tables (tbl1 and tbl2). AnimalNo is present in both tables, but it is the primary key of tbl1 and can occur multiple times in tbl2 (if the AnimalNo is associated with multiple ConditionID)
tbl1
AnimalNo | KillDate
1 | 01/01/2019
2 | 01/01/2019
3 | 01/01/2019
4 | 01/01/2020
5 | 01/01/2020
tbl2
AnimalNo | ConditionID
1 | 1
1 | 2
2 | 1
3 | 1
3 | 2
4 | 1
5 | 1
5 | 2
I would like a table where I get a count of the AnimalID which had each condition and the count of the AnimalNo which had both ConditionID 1 & 2, in the above example:
Year | N_killed | Type1 | Type2 | Both
2019 | 3 | 3 | 2 | 2
2020 | 2 | 2 | 1 | 1
I have this query which is successful at telling me the number of AnimalNo with each individual ConditionID but I would like to add the last column called Both which has a count of the AnimalNo which have both ConditionID 1 & 2
SELECT
DATEPART(year, tbl1.KillDate) AS KillYear,
COUNT(Distinct tbl1.AnimalNo) AS N_Killed,
COUNT(CASE WHEN tbl2.ConditionId =1 THEN 1 END) AS Type1,
COUNT(CASE WHEN tbl2.ConditionId =2 THEN 1 END) AS Type2
FROM tbl1 LEFT JOIN
tbl2 ON tbl1.AnimalNo = tbl2.AnimalNo
WHERE YEAR(tbl1.KillDate) >=2012
GROUP BY DATEPART(year, KillDate)
ORDER BY DATEPART(year, KillDate)
I think this is that you want
SELECT
DATEPART(year, tbl1.KillDate) AS KillYear,
COUNT(Distinct tbl1.AnimalNo) AS N_Killed,
COUNT(CASE WHEN tbl2.ConditionId =9 THEN 1 END) AS Type1a,
COUNT(CASE WHEN tbl2.ConditionId =75 THEN 1 END) AS Type1b,
COUNT(CASE WHEN tbl2.ConditionId =23 THEN 1 END) AS Type2a,
COUNT(CASE WHEN tbl2.ConditionId =81 THEN 1 END) AS Type2b,
COUNT(CASE WHEN tbl2.ConditionId IN (9,75) OR tbl2.ConditionId IN (23,81) BothTypes
FROM tbl1 LEFT JOIN
tbl2 ON tbl1.AnimalNo = tbl2.AnimalNo
WHERE YEAR(tbl1.KillDate) >=2012
GROUP BY DATEPART(year, KillDate)
ORDER BY DATEPART(year, KillDate)
Try this:
declare #tbl1 table
(
AnimalNo int
,KillDate date
)
insert into #tbl1(AnimalNo, KillDate)
select 1, '2019-01-01' union
select 2, '2019-01-01' union
select 3, '2019-01-01' union
select 4, '2020-01-01' union
select 5, '2020-01-01'
declare #tbl2 table
(
AnimalNo int
,ConditionID int
)
insert into #tbl2(AnimalNo, ConditionID)
select 1,1 union
select 1,2 union
select 2,1 union
select 3,1 union
select 3,2 union
select 4,1 union
select 5,1 union
select 5,2
select
year(k.KillDate) as [Year]
,count(distinct k.AnimalNo) as N_Killed
,sum(c.Type1)
,sum(c.Type2)
,sum(case when c.Type1 = 1 and c.Type2 = 1 then 1 else 0 end) as Both
from
#tbl1 k
JOIN
(
select
c.AnimalNo
,max(case when c.ConditionID = 1 then 1 else 0 end) as Type1
,max(case when c.ConditionID = 2 then 1 else 0 end) as Type2
from
#tbl2 c
group by c.AnimalNo
) c
on k.AnimalNo = c.AnimalNo
group by year(k.KillDate)

Date counts to be display in specific conditions in the stored proc like [0-6 days],[7-14 days] etc

I am creating a ssrs report and SP. so i have requirement like this below.
I have table called management in that we have a column description so the data under the
description are only 'Open' and 'Closed'.
I have parameter called User, Start Date and End Date
I need to display the user who all have the count of open cases which are falls under between the start date and
end date in the below conditions.
The conditions are
0-5 days
6-11 days
12-18 days.
For ex:
If i enter start date(MM/DD/YYYY) as 12-1-2019 and end date as 12-31-2019
So i need to display users who has the open case count between the 0-5 days,6-11 days and 12-18 days.
how about something like that?
select [0-5] = SUM(IIF(DATEDIFF(day,OpenDate, CloseDate) >= 0 and DATEDIFF(day,OpenDate, CloseDate) <= 5,1,0))
,[6-11] = SUM(IIF(DATEDIFF(day,OpenDate, CloseDate) >= 6 and DATEDIFF(day,OpenDate, CloseDate) <= 11,1,0))
,[12-18] = SUM(IIF(DATEDIFF(day,OpenDate, CloseDate) >= 12 and DATEDIFF(day,OpenDate, CloseDate) <= 18,1,0))
from tblOpenClose
With a bit of conditional aggregation.
Combined with a Cross Apply for the ranges.
SELECT t.UserId, a.DateDiffRange
, COUNT(CASE WHEN t.Description LIKE 'Open%' THEN 1 END) AS [Open]
, COUNT(CASE WHEN t.Description LIKE 'Closed%' THEN 1 END) AS [Closed]
, COUNT(*) AS [Total]
FROM management AS t
CROSS APPLY
(
SELECT
(CASE
WHEN DATEDIFF(day, t.[Start Date], t.[End Date]) BETWEEN 0 AND 5 THEN '00-05'
WHEN DATEDIFF(day, t.[Start Date], t.[End Date]) BETWEEN 6 AND 11 THEN '06-11'
WHEN DATEDIFF(day, t.[Start Date], t.[End Date]) BETWEEN 12 AND 18 THEN '12-18'
WHEN DATEDIFF(day, t.[Start Date], t.[End Date]) BETWEEN 19 AND 30 THEN '19-30'
END) AS DateDiffRange
) AS a
WHERE t.[Start Date] >= CAST('2019-12-01' AS DATE)
AND t.[End Date] BETWEEN t.[Start Date] AND EOMONTH(t.[Start Date])
GROUP BY YEAR(t.[Start Date]), MONTH(t.[Start Date]), t.UserId, a.DateDiffRange
ORDER BY t.UserId, a.DateDiffRange;
And for more metrics per user?
Check this out for inspiration:
SELECT (YEAR(t.[Start Date])*100+MONTH(t.[Start Date])) AS YearMonth, t.UserId
, SUM(CASE WHEN a.DateDiff BETWEEN 0 AND 5 THEN a.IsOpen END) AS [Opened Within 0-5]
, SUM(CASE WHEN a.DateDiff BETWEEN 6 AND 11 THEN a.IsOpen END) AS [Opened Within 6-11]
, SUM(CASE WHEN a.DateDiff BETWEEN 12 AND 18 THEN a.IsOpen END) AS [Opened Within 12-18]
, SUM(CASE WHEN a.DateDiff BETWEEN 19 AND 30 THEN a.IsOpen END) AS [Opened Within 19-30]
, SUM(CASE WHEN a.DateDiff BETWEEN 0 AND 5 THEN a.IsClosed END) AS [Closed Within 0-5]
, SUM(CASE WHEN a.DateDiff BETWEEN 6 AND 11 THEN a.IsClosed END) AS [Closed Within 6-11]
, SUM(CASE WHEN a.DateDiff BETWEEN 12 AND 18 THEN a.IsClosed END) AS [Closed Within 12-18]
, SUM(CASE WHEN a.DateDiff BETWEEN 19 AND 30 THEN a.IsClosed END) AS [Closed Within 19-30]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 1 AND 5 THEN a.IsOpen END) AS [Opened Start 1-5]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 6 AND 11 THEN a.IsOpen END) AS [Opened Start 6-11]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 12 AND 18 THEN a.IsOpen END) AS [Opened Start 12-18]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 19 AND 30 THEN a.IsOpen END) AS [Opened Start 19-31]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 1 AND 5 THEN a.IsClosed END) AS [Closed Start 0-5]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 6 AND 11 THEN a.IsClosed END) AS [Closed Start 6-11]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 12 AND 18 THEN a.IsClosed END) AS [Closed Start 12-18]
, SUM(CASE WHEN DAY(t.[Start Date]) BETWEEN 19 AND 31 THEN a.IsClosed END) AS [Closed Start 19-31]
, COUNT(*) AS [Total]
FROM management AS t
CROSS APPLY
(
SELECT
DATEDIFF(day, t.[Start Date], t.[End Date]) AS [DateDiff],
CASE WHEN t.Description LIKE 'Open%' THEN 1 END AS [IsOpen],
CASE WHEN t.Description LIKE 'Closed%' THEN 1 END AS [IsClosed]
) AS a
WHERE t.[Start Date] >= CAST('2019-12-01' AS DATE)
AND t.[End Date] BETWEEN t.[Start Date] AND EOMONTH(t.[Start Date])
GROUP BY YEAR(t.[Start Date]), MONTH(t.[Start Date]), t.UserId
ORDER BY YearMonth, t.UserId;
YearMonth | UserId | Opened Within 0-5 | Opened Within 6-11 | Opened Within 12-18 | Opened Within 19-30 | Closed Within 0-5 | Closed Within 6-11 | Closed Within 12-18 | Closed Within 19-30 | Opened Start 1-5 | Opened Start 6-11 | Opened Start 12-18 | Opened Start 19-31 | Closed Start 0-5 | Closed Start 6-11 | Closed Start 12-18 | Closed Start 19-31 | Total
--------: | -----: | ----------------: | -----------------: | ------------------: | ------------------: | ----------------: | -----------------: | ------------------: | ------------------: | ---------------: | ----------------: | -----------------: | -----------------: | ---------------: | ----------------: | -----------------: | -----------------: | ----:
201912 | 101 | 4 | 4 | 3 | 1 | null | 1 | 3 | 1 | 10 | null | 2 | null | 5 | null | null | null | 17
201912 | 102 | 3 | 2 | null | null | null | null | null | null | 5 | null | null | null | null | null | null | null | 5
Test on db<>fiddle here

Transposing columns sql server

I have a slightly complex query below:
with t as (
select a.ID, a.Date_Reported AS [Date Sent], b.Date_Received AS [Date Returned],
(datediff(dd, a.date_reported, b.date_received)
+ CASE WHEN Datepart(dw, b.date_received) = 7 THEN 1 ELSE 0 END
- (Datediff(wk, a.date_reported, b.date_received) * 2 )
- CASE WHEN Datepart(dw, b.date_received) = 1 THEN 1 ELSE 0 END +
- CASE WHEN Datepart(dw, b.date_received) = 1 THEN 1 ELSE 0
END) AS [Time_Spent]
from TX_ext a
join TX b on b.id on a.id
)
select
sum(case when Time_Spent between 0 and 3 then 1 else 0 end) as _0_3_days,
sum(case when Time_Spent = 4 then 1 else 0 end) as _4_days,
sum(case when Time_Spent = 5 then 1 else 0 end) as _5_days,
sum(case when Time_Spent between 6 and 8 then 1 else 0 end) as _6_8_days,
sum(case when Time_Spent >= 9 then 1 else 0 end) as more_than_9_days,
avg(case when Time_Spent between 0 and 3 then 100.0 else 0 end) as _0_3_percent,
avg(case when Time_Spent = 4 then 100.0 else 0 end) as _4_percent,
avg(case when Time_Spent = 5 then 100.0 else 0 end) as _5_percent,
avg(case when Time_Spent between 6 and 8 then 100.0 else 0 end) as _6_8_percent,
avg(case when Time_Spent >= 9 then 100.0 else 0 end) as more_than_9_day_percent
from t
The above query gives me the below table:
0-3 | 4 | 5 | 6-8 | 9+ | 0-3% | 4% | 5% | 6-8% | 9+%
2 | 3 | 1 | 3 | 1 | 20 | 30 | 10 | 30 | 10
However what I would ideally like is this (the % figures transposed as a row) and also headings as the FIRST column:
Time Taken (days) | 0-3 | 4 | 5 | 6-8 | 9+
Count | 2 | 3 | 1 | 3 | 1
% | 20 | 30| 10| 30 | 10
Any ideas? Thanks in advance
you can do this using CROSS APPLY like below query
See live demo
; with t as
(
select
a.ID,
a.Date_Reported AS [Date Sent],
b.Date_Received AS [Date Returned],
(datediff(dd, a.date_reported, b.date_received)
+ CASE WHEN Datepart(dw, b.date_received) = 7 THEN 1 ELSE 0 END
- (Datediff(wk, a.date_reported, b.date_received) * 2 )
- CASE WHEN Datepart(dw, b.date_received) = 1 THEN 1 ELSE 0 END +
- CASE WHEN Datepart(dw, b.date_received) = 1 THEN 1 ELSE 0
END) AS [Time_Spent]
from TX_ext a
join TX b on b.id on a.id
)
select V.*
from
(
select
sum(case when Time_Spent between 0 and 3 then 1 else 0 end) as _0_3_days,
sum(case when Time_Spent = 4 then 1 else 0 end) as _4_days,
sum(case when Time_Spent = 5 then 1 else 0 end) as _5_days,
sum(case when Time_Spent between 6 and 8 then 1 else 0 end) as _6_8_days,
sum(case when Time_Spent >= 9 then 1 else 0 end) as more_than_9_days,
avg(case when Time_Spent between 0 and 3 then 100.0 else 0 end) as _0_3_percent,
avg(case when Time_Spent = 4 then 100.0 else 0 end) as _4_percent,
avg(case when Time_Spent = 5 then 100.0 else 0 end) as _5_percent,
avg(case when Time_Spent between 6 and 8 then 100.0 else 0 end) as _6_8_percent,
avg(case when Time_Spent >= 9 then 100.0 else 0 end) as more_than_9_day_percent
from t
) T1
cross apply
( values
('Count',[_0_3_days] , [_4_days] , [_5_days] , [_6_8_days] , [more_than_9_days]),
('%',[_0_3_percent] , [_4_percent] , [_5_percent] , [_6_8_percent] , [more_than_9_day_percent] )
)
v([Time Taken (days)],[0-3],[4],[5],[6-8],[9+])
select
sum(case when Time_Spent between 0 and 3 then 1 else 0 end) as _0_3,
sum(case when Time_Spent = 4 then 1 else 0 end) as _4,
sum(case when Time_Spent = 5 then 1 else 0 end) as _5,
sum(case when Time_Spent between 6 and 8 then 1 else 0 end) as _6_8,
sum(case when Time_Spent >= 9 then 1 else 0 end) as more_than_9
from t
union
select
avg(case when Time_Spent between 0 and 3 then 100.0 else 0 end) as _0_3,
avg(case when Time_Spent = 4 then 100.0 else 0 end) as _4,
avg(case when Time_Spent = 5 then 100.0 else 0 end) as _5,
avg(case when Time_Spent between 6 and 8 then 100.0 else 0 end) as _6_8,
avg(case when Time_Spent >= 9 then 100.0 else 0 end) as more_than_9
from t

Select data with only specific factors from many

I'm using T-SQL
I have a table: user session with platform source.
I need to get users who used only "Android" and "Desktop".
Data Example:
ID | Source | DateTime
1 | Android | 2016-06-01
1 | Desktop | 2016-06-01
2 | Android | 2016-06-02
3 | iOS | 2016-06-01
3 | Desktop | 2016-06-02
3 | Android | 2016-06-03
Expected result:
ID = 1
ID = 2 is wrong, because it has only "Android"
ID = 3 is wrong, because it has "IOS"
I call this a set-within-sets query. I like to approach this using group by and having, because this is a very flexible method for expressing these conditions:
select id
from t
group by id
having sum(case when source = 'Android' then 1 else 0 end) > 0 and -- has Android
sum(case when source = 'Desktop' then 1 else 0 end) > 0 and -- has Desktop
sum(case when source not in ('Android', 'Desktop') then 1 else 0 end) = 0 -- has nothing else
Try this:
SELECT Id
FROM mytable
GROUP BY Id
HAVING COUNT(*) = COUNT(CASE WHEN Source='Android' THEN 1 END) +
COUNT(CASE WHEN Source='Desktop' THEN 1 END) AND
COUNT(CASE WHEN Source='Desktop' THEN 1 END) > 0 AND
COUNT(CASE WHEN Source='Android' THEN 1 END) > 0
Try this
select id from your_table
group by id
having
max(case when source in ('Android') then 1 else 0 end))=1
and
max(case when source in ('Desktop') then 1 else 0 end))=1
and count(distinct source)=2
Try to use
Select *
from yourtable a
where a.source = 'Android'
and not exist (Select b.id
from yourtable b
where b.id = a.id and b.source <> 'Android')

SQL SUM() conditions questions

I have a table that looks like this:
+----+------+--------+----------+
| ID | Code | OpType | Quantity |
+----+------+--------+----------+
| 0 | A | IN | 7 |
| 1 | B | IN | 8 |
| 2 | A | OUT | 2 |
| 3 | B | IN | 7 |
| 4 | B | OUT | 12 |
+----+------+--------+----------+
I want the SUM(Quantity) depending on the OpType. When OpType is OUT, the Quantity field should be multiplied with -1.
The result of the query should be:
Code IN OUT Final
A 7 2 5
B 15 12 3
I've tried this, but it doesn't work:
SELECT(SELECT SUM(Quantity) FROM Table WHERE OpType = 'IN') AS[IN], (SELECT SUM(Quantity) FROM Table WHERE OpType = 'OUT') AS[OUT], (SELECT SUM(Quantity) FROM Table WHERE OpType = 'IN') - (SELECT SUM(Quantity) FROM Table WHERE OpType = 'OUT') AS[Final]
FROM Table
GROUP BY Code
SQL Server has PIVOT functionality.
SELECT [Code], [IN], [OUT], [IN] - [OUT] AS [Final]
FROM
(
SELECT [Code], OpType, SUM(Quantity) Quantity
FROM TableName
GROUP BY [Code], OpType
) org
PIVOT
(
MAX(Quantity)
FOR OpType IN ([IN],[OUT])
) pvt
SQLFiddle Demo
TSQL PIVOT
OUTPUT
╔══════╦════╦═════╦═══════╗
║ CODE ║ IN ║ OUT ║ FINAL ║
╠══════╬════╬═════╬═══════╣
║ A ║ 7 ║ 2 ║ 5 ║
║ B ║ 15 ║ 12 ║ 3 ║
╚══════╩════╩═════╩═══════╝
I would use a CASE statement inside the SUM for each column so that you only sum the desired values (i.e. for the IN column only SUM up the quantities with OpType='IN' and for the OUT column only SUM up the quantities with OpType='OUT')
SELECT Code,
SUM(CASE WHEN OpType = 'IN' THEN Quantity ELSE 0 END) as [IN],
SUM(CASE WHEN OpType = 'OUT' THEN Quantity ELSE 0 END) as [OUT],
SUM(CASE WHEN OpType = 'OUT' THEN -1 * Quantity ELSE Quantity END) as [FINAL]
FROM Table
GROUP BY Code
UPDATE: In a comment to JW 웃's answer, you asked about getting the IN, OUT and FINAL sums between two dates. Below is an updated query which will do that.
DECLARE #InitialSumDate DATETIME = '4/22/2013', #EndDate DATETIME = '4/23/2013'
SELECT
#InitialSumDate as [InitialSumDate], #EndDate as [EndDate],
Code,
SUM(CASE WHEN PurchaseDate <= #InitialSumDate AND OpType = 'OUT' THEN -1 * Quantity WHEN PurchaseDate <= #InitialSumDate AND OpType = 'IN' THEN Quantity ELSE 0 END) as [InitialSum],
SUM(CASE WHEN PurchaseDate > #InitialSumDate AND PurchaseDate <= #EndDate AND OpType = 'IN' THEN Quantity ELSE 0 END) as [IN],
SUM(CASE WHEN PurchaseDate > #InitialSumDate AND PurchaseDate <= #EndDate AND OpType = 'OUT' THEN Quantity ELSE 0 END) as [OUT],
SUM(CASE WHEN OpType = 'OUT' AND PurchaseDate <= #EndDate THEN -1 * Quantity WHEN OpType = 'IN' AND PurchaseDate <= #EndDate THEN Quantity ELSE 0 END) as [FINAL]
FROM #Table
GROUP BY Code

Resources