In Postgres, this is simpler with DISTINCT ON
:
SELECT *
FROM (
SELECT DISTINCT ON (sec)
id, sec
FROM tbl
ORDER BY sec, id DESC
) sub
ORDER BY id DESC
LIMIT 4;
Detailed explanation in this related answer on SO:
For a big table and small LIMIT
, neither this nor @a_horse's solution are very efficient. The subquery will plough through the whole table, wasting a lot of time ...
Recursive CTE
I have tried and failed to solve similar problems with a recursive CTE in the past and resorted to a procedural solution with PL/pgSQL. Example:
Finally, here is a working rCTE:
WITH RECURSIVE cte AS (
( -- parentheses required
SELECT id, '{}'::int[] AS last_arr, ARRAY[sec] AS arr
FROM tbl
ORDER BY id DESC
LIMIT 1
)
UNION ALL
(
SELECT b.id, c.arr
, CASE WHEN b.sec = ANY (c.arr) THEN c.arr ELSE b.sec || c.arr END
FROM cte c
JOIN tbl b ON b.id < c.id
WHERE array_length(c.arr, 1) < 4
ORDER BY id DESC
LIMIT 1
)
)
SELECT id, arr[1] AS sec
FROM cte
WHERE last_arr <> arr;
It's not as fast or elegant as I had hoped for and not nearly as fast as the function below, but faster than the query above in my tests.
PL/pgSQL function
Fastest by far:
CREATE OR REPLACE FUNCTION f_first_uniq(_rows int)
RETURNS TABLE (id int, sec int) AS
$func$
DECLARE
_arr int[];
BEGIN
FOR id, sec IN
SELECT t.id, t.sec FROM tbl t ORDER BY t.id DESC
LOOP
IF sec = ANY (_arr) THEN
-- do nothing
ELSE
RETURN NEXT;
_arr := _arr || sec;
EXIT WHEN array_length(_arr, 1) >= _rows;
END IF;
END LOOP;
END
$func$ LANGUAGE plpgsql;
Call:
SELECT * FROM f_first_uniq(4);
SQL Fiddle demonstrating all three.
Could be made out to work for any table with table and column names as parameters and dynamic SQL with EXECUTE
...
Why bother?
In a test table with only 30k
rows the function ran 2000x faster than the above query (which already ran ~ 30% faster than a_horse's version). This difference grows with the size of the table. Performance of the function is about constant, while the query's performance gets progressively worse, since it tries to find distinct values in all of the table first. Try this in a table with a million rows ...
This will probably do what you want:
revoke create on schema public¹ from public²;
Note that the public² does not mean the schema public¹, but a group representation of all users of the database. So when you try to revoke your user from creating tables nothing happens because it probably does not have this permissions at start(except if you give it), but the group public² that your user belongs, is with this access by default - That's the default behavior for schema public.
Now you can give the create privilege for specific users:
grant create on schema public to specificuser;
Best Answer
Alas, no. You cannot parameterize views like that, you need a function to do it.
I rather hope someone proves me wrong, as I much prefer views to set-returning functions. But I doubt they will.