I often find that I am adding expressions to a group by clause, which I am sure is unique. Sometimes it turns out that I'm wrong - because of an error in my SQL or an erroneous assumption, and this expression is really not unique.
There are many cases where I would really like for this to generate an SQL error, rather than expanding my result set silently, and sometimes very subtly.
I would like to do something like:
select product_id, unique description from product group by product_id
but obviously I can’t implement this myself, but something almost like compressed can be implemented using user-defined aggregates in some databases.
Would a special aggregate that allows only one unique input value in all versions of SQL be useful? If so, can such a thing be implemented now in most databases? null values should be considered like any other value - unlike the way the avg built-in aggregate works. (I added answers with implementation methods for postgres and Oracle.)
The following example is intended to show how an aggregate will be used, but this is a simple case when it is obvious which expressions should be unique. The real use is likely to be in large queries, where it is easier to err on the assumptions about uniqueness
tables:
product_id | description ------------+------------- 1 | anvil 2 | brick 3 | clay 4 | door sale_id | product_id | cost ---------+------------+--------- 1 | 1 | £100.00 2 | 1 | £101.00 3 | 1 | £102.00 4 | 2 | £3.00 5 | 2 | £3.00 6 | 2 | £3.00 7 | 3 | £24.00 8 | 3 | £25.00
inquiries:
> select * from product join sale using (product_id); product_id | description | sale_id | cost ------------+-------------+---------+--------- 1 | anvil | 1 | £100.00 1 | anvil | 2 | £101.00 1 | anvil | 3 | £102.00 2 | brick | 4 | £3.00 2 | brick | 5 | £3.00 2 | brick | 6 | £3.00 3 | clay | 7 | £24.00 3 | clay | 8 | £25.00 > select product_id, description, sum(cost) from product join sale using (product_id) group by product_id, description; product_id | description | sum ------------+-------------+--------- 2 | brick | £9.00 1 | anvil | £303.00 3 | clay | £49.00 > select product_id, solo(description), sum(cost) from product join sale using (product_id) group by product_id; product_id | solo | sum ------------+-------+--------- 1 | anvil | £303.00 3 | clay | £49.00 2 | brick | £9.00
error:
> select solo(description) from product; ERROR: This aggregate only allows one unique input