Reputation: 4282
My sample data source is following
declare @t1 as table
(
sn int,
site varchar(max),
cond varchar(max),
val int
)
insert into @t1
select *
from
(values
(1, 'site1', 'X', 100),
(2, 'site1', 'Y', 200),
(3, 'site1', 'Z', 300),
(1, 'site2', 'A', 100),
(2, 'site2', 'B', 200),
(3, 'site2', 'C', 300),
(1, 'site3', 'X', 100),
(2, 'site3', 'P', 200),
(3, 'site3', 'Q', 300),
(1, 'site4', 'A', 100),
(2, 'site4', 'Y', 200),
(3, 'site4', 'Q', 300),
(1, 'site5', 'E', 100),
(1, 'site5', 'E', 1000),
(2, 'site5', 'F', 200),
(3, 'site5', 'G', 300)
) t (a, b, c, d)
I want SQL to check if there exists any row with cond=X
or cond=Y
by site and if yes, don't perform any aggregation; if no, perform a sum of val.
I am currently achieving it by following
Method1
select
ax.sn, ax.site, ax.cond,
sum(ax.revisedVal) as revisedTotal
from
(select distinct
a.sn, a.site, a.cond, a.val, t.one, m.revisedVal
from
@t1 a
outer apply
(select *
from
(select *, 1 as one
from @t1 b
where b.cond = 'Y' or b.cond = 'X') x
where a.site = x.site) t
outer apply
(values (case when t.one = 1 then null else a.val end)) m(revisedVal))ax
group by
ax.sn, ax.site, ax.cond
order by
ax.site, ax.sn
Method 2
SELECT a.sn,
a.site,
a.cond,
Sum(CASE
WHEN a.site = x.site THEN a.val
ELSE NULL
END) AS revisedVal
FROM @t1 a
OUTER apply (SELECT b.site
FROM (SELECT site
FROM @t1
WHERE cond <> 'X'
OR cond <> 'Y'
EXCEPT
SELECT site
FROM @t1
WHERE cond = 'X'
OR cond = 'Y') b
WHERE a.site = b.site) x
GROUP BY a.site,
a.sn,
a.cond
I was wondering if there is any better way of achieving this.
Edit
Desired Result
| sn | site | cond | revisedTotal |
|----|-------|------|--------------|
| 1 | site1 | X | NULL |
| 2 | site1 | Y | NULL |
| 3 | site1 | Z | NULL |
| 1 | site2 | A | 100 |
| 2 | site2 | B | 200 |
| 3 | site2 | C | 300 |
| 1 | site3 | X | NULL |
| 2 | site3 | P | NULL |
| 3 | site3 | Q | NULL |
| 1 | site4 | A | NULL |
| 2 | site4 | Y | NULL |
| 3 | site4 | Q | NULL |
| 1 | site5 | E | 1100 |
| 2 | site5 | F | 200 |
| 3 | site5 | G | 300 |
Upvotes: 1
Views: 113
Reputation: 1269743
This sounds like a having
clause on an aggregation query:
select site, sum(val)
from @t t
group by site
having sum(case when cond = X or cond = Y then 1 else 0 end) = 0;
EDIT:
with agg as (
select site, sum(val) as val
from @t t
group by site
having sum(case when cond = X or cond = Y then 1 else 0 end) = 0
)
select site, val
from agg
union all
select site, val
from @t t
where not exists (select 1 from agg where agg.site = t.site);
Upvotes: 1
Reputation: 6788
… fiddle
select ax.sn, ax.site, ax.cond, sum(case when ax.one = 1 then null else ax.val end) as revisedTotal
from
(
select *, max(case when cond in ('Y', 'X') then 1 else 0 end) over(partition by site) as one
from @t1
) as ax
group by ax.sn, ax.site, ax.cond
order by ax.site, ax.sn;
Upvotes: 2
Reputation: 14920
This:
SELECT t1.site, SUM(t1.val)
from @t1 t1
left join @t1 t2 on t2.site=t1.site and t2.cond in ('X','Y')
where t2.site is null
group by t1.site;
Produces the sum for all values of val
, per site, where there does not exist a val
with the value 'X' or 'Y'.
see: DBFIDDLE
or, with the other columns added:
SELECT t1.sn, t1.site, t1.cond, SUM(t1.val)
from @t1 t1
left join @t1 t2 on t2.site=t1.site and t2.cond in ('X','Y')
where t2.site is null
group by t1.sn, t1.site, t1.cond;
Upvotes: 0