Reputation: 2761
Assume there is a simple table:
CREATE TABLE [dbo].[foo](
[foo_id] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[val1_id] [int] NULL,
[val1_amount] [int] NULL,
[val2_id] [int] NULL,
[val2_amount] [int] NULL,
[val3_id] [int] NULL,
[val3_amount] [int] NULL,
[val4_id] [int] NULL
[val4_amount] [int] NULL,
) ON [PRIMARY]
And there is some other table that is:
CREATE TABLE [dbo].[val](
[val_id] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[amount] [int] NOT NULL,
) ON [PRIMARY]
The user of the application will select an entry from the table val, and the application will place val_id and amount in val?_id and val?_amount in a non-deterministic manner (yes, I know this isn't good, but I have to deal with it).
Is there a way to produce output that will group by the val_id from the foo table and SUM the amount values from the foo table, given that the val_id/amount may be stored in any of the val?_id/val?_amount columns? Note that if val_id is stored in val1_id, the amount will always be stored in val1_amount within that row, but the same val_id may appear in a different val?_id in a different row (but the amount will be in the corresponding column)
Upvotes: 0
Views: 135
Reputation: 107776
If you have correctly stated that the value will only ever appear in one pair of (val_id, val_amount)
columns leaving the other 3 pairs blank, then this will work better than the currently accepted answer (@lamak's)
select id = coalesce(val1_id, val2_id, val3_id, val4_id),
val = sum(coalesce(val1_amount, val2_amount, val3_amount, val4_amount))
from foo
group by coalesce(val1_id, val2_id, val3_id, val4_id);
It is easy to understand and even though the COALESCE is repeated, it is really only evaluated once so there is no performance penalty. The query plan is estimated at 50% the cost of the other query.
The currently accepted answer may also produce a phantom NULL row, for example for the data in my SQL fiddle demo that does not contain anything in the 3rd pair (val3_amount).
Upvotes: 0
Reputation: 70668
Well, after you smacked the guy that designed this, you can try to UNPIVOT
your columns, and then simply SUM
the val_amount
resultant column. I'm not gonna actually use UNPIVOT
, but I'm doing the same with CROSS APPLY
:
SELECT x.Val_id, SUM(x.val_amount) Val_Amount
FROM dbo.foo t
CROSS APPLY
(
VALUES
(t.val1_id, t.val1_amount),
(t.val2_id, t.val2_amount),
(t.val3_id, t.val3_amount),
(t.val4_id, t.val4_amount)
) x (Val_id, val_amount)
GROUP BY x.Val_id;
Here is a sqlfiddle with a live demo for you to try.
Upvotes: 6
Reputation: 8919
Is there a way to produce output that will group by the val_id from the foo table and SUM the amount values from the foo table, given that the val_id/amount may be stored in any of the val?_id/val?_amount columns?
Hell is other people's data. You might do something like this:
create view FOO as
select foo.id, val1_id as valueid, val1_amount as amt from T
union all
select foo.id val2_id as valueid, val2_amount as amt from T
union all
select foo.id val3_id as valueid, val3_amount as amt from T
union all
select foo.id val4_id as valueid, val4_amount as amt from T
Upvotes: 0
Reputation: 3189
I did it using the COALESCE function. I'm not clear why I had to do a nested query, but I couldn't get it to take it otherwise:
select id, sum(amount)
FROM
(SELECT COALESCE(val1_id , val2_id , val3_id , val4_id) id,
COALESCE(val1_amount , val2_amount , val3_amount , val4_amount) amount
from foo) coalesced_data
GROUP BY ID
http://sqlfiddle.com/#!3/2ef35/6
Upvotes: 1