Reputation: 23
I have a DB where certain records are tagged with an ID and I want create a view that contains the Average of all those records with the same ID, EXCLUDING the current record. For example, if my data looks like this:
ROW - ID - Value
1 1 20
2 1 30
3 1 40
4 2 60
5 2 80
6 2 40
7 3 50
8 3 20
9 3 40
My view needs to calculate the average of every row with the same ID, EXCLUDING the row it's on, so my output would look something like this:
ROW - ID - Value AVG
1 1 20 35
2 1 30 30
3 1 40 25
4 2 60 60
5 2 80 50
6 2 40 70
7 3 50 30
8 3 20 55
9 3 40 35
So, in the case of row 3, it's extracted rows 1 and 2, as they have the same ID and given me the avg of their values - 25.
I'm gone round the houses on this for a while now, but can't seem to nail it. Any help would be appreciated.
Upvotes: 2
Views: 3158
Reputation: 81970
One Option if you have window functions
Declare @YourTable table (ROW int,ID int,Value int)
Insert Into @YourTable values
(1, 1, 20),
(2, 1, 30),
(3, 1, 40),
(4, 2, 60),
(5, 2, 80),
(6, 2, 40),
(7, 3, 50),
(8, 3, 20),
(9, 3, 40)
Select *
,Avg = (sum(value) over (Partition By ID)-Value)/NullIf((sum(1) over (Partition By ID)-1),0)
From @YourTable
Another Option is a OUTER APPLY
Select A.*
,B.*
From @YourTable A
Outer Apply (Select Avg=avg(value)
From @YourTable
where ID=A.ID and Row<>A.Row
) B
Both Return
Upvotes: 4
Reputation: 83
This query works for me:
select t1.row, t1.id, t1.value, (select avg(value) from test_table as t2 where t1.id = t2.id and t1.row != t2.row) as avg from test_table as t1;
Data in table created by me (i assume is simmilar to Yours):
mysql> select * from test_table;
+-----+------+-------+
| row | id | value |
+-----+------+-------+
| 1 | 1 | 20 |
| 2 | 1 | 30 |
| 3 | 1 | 40 |
| 4 | 2 | 60 |
| 5 | 2 | 80 |
| 6 | 2 | 40 |
| 7 | 3 | 50 |
| 8 | 3 | 20 |
| 9 | 3 | 40 |
+-----+------+-------+
Result of query:
+-----+------+-------+---------+
| row | id | value | avg |
+-----+------+-------+---------+
| 1 | 1 | 20 | 35.0000 |
| 2 | 1 | 30 | 30.0000 |
| 3 | 1 | 40 | 25.0000 |
| 4 | 2 | 60 | 60.0000 |
| 5 | 2 | 80 | 50.0000 |
| 6 | 2 | 40 | 70.0000 |
| 7 | 3 | 50 | 30.0000 |
| 8 | 3 | 20 | 45.0000 |
| 9 | 3 | 40 | 35.0000 |
+-----+------+-------+---------+
Upvotes: 1
Reputation: 680
SELECT t1.gid, AVG(t2.value)
FROM table1 as t1 INNER JOIN
table1 as t2 ON (t1.gid != t2.gid)
GROUP BY t1.gid;
Basically, join the table to itself on your condition and then group the results based on the first table's key.
This solution should work regardless of what database system you are usimg; there may be minor syntax details to change.
A table like this:
ID | Value
1 | 4
2 | 6
3 | 5
Becomes (when joined):
t1.ID | t2.ID | t1.Value | t2.Value
1 | 2 | 4 | 6
1 | 3 | 4 | 5
2 | 1 | 6 | 4
2 | 3 | 6 | 5
3 | 1 | 5 | 4
3 | 2 | 5 | 6
And, then the aggregate of the grouped rows yields the wanted values.
Upvotes: 1