Take the 2-minute tour ×
Database Administrators Stack Exchange is a question and answer site for database professionals who wish to improve their database skills and learn from others in the community. It's 100% free, no registration required.

I am trying to create a view to show the last value in the group. Looking for a more general purpose query.

CREATE TABLE a (
   id INTEGER,
   seq INTEGER,
   val VARCHAR2(16),
   PRIMARY KEY(id,seq)
);

-- View 1
CREATE VIEW v1 AS SELECT a.*
 FROM 
  a, 
  (SELECT id, MAX(seq) from a GROUP BY id) b
 WHERE a.id=b.id AND a.seq=b.seq

-- View 2
CREATE VIEW v2 AS SELECT a.*
 FROM 
  a 
 WHERE a.seq=(SELECT seq from a b WHERE a.id=b.id ORDER BY seq DESC LIMIT 1) 

View 1 perform better when I want to list all records.

View 2 perform better when I do SELECT * FROM v2 WHERE id=?

Because this view is to be given to outsiders I want this to be as general purpose as possible. Is there any way to tell PostgreSQL these two query is equivalent and let it pick them automagically?

share|improve this question
1  
Good question, and interesting problem. –  Craig Ringer Jan 14 at 2:36

1 Answer 1

up vote 2 down vote accepted

This form with DISTINCT ON is typically faster than either v1 or v2:

CREATE VIEW v3 AS
SELECT DISTINCT ON (id) a.*
FROM   a
ORDER  BY id, seq DESC NULLS LAST;

You get sorted output (by id) on top of it, which is typically a welcome side effect.
Minor difference: this form includes a row for ids with only NULL values in seq. This, too, would be a welcome effect, typically. And irrelevant if seq is defined NOT NULL.

If performance is essential I strongly suggest to create a matching (!) multicolumn index of the form:

CREATE INDEX a_id_seq_idx ON a (id, seq DESC NULLS LAST);

A lot more details and more alternatives under this related question on SO:
Select first row in each GROUP BY group?

Switch query depending on input

If you are interested in a switching technique per se, rather, you could create a table function instead of the view which takes an id as parameter.

CREATE OR REPLACE FUNCTION f_a(_id int DEFAULT NULL)
  RETURNS SETOF a AS
$func$
BEGIN

IF _id IS NULL THEN
    RETURN QUERY
    SELECT ... ;
ELSE
    RETURN QUERY
    SELECT ...
   WHERE  id = _id;
END IF;

END
$func$  LANGUAGE plpgsql;

Call:

SELECT * FROM f_a();     -- for the whole table
SELECT * FROM f_a(123);  -- for a particular id

Could be improved with more parameters.

This approach is perfect for simple calls. Even saves some planning overhead and is typically faster than raw SQL this way. Be advised, though, that a plpgsql function poses as optimization barrier. The body of the function cannot be inlined or optimized in the context of a bigger query (like a view or a simple SQL function could be). More in this related answer:
PostgreSQL Stored Procedure Performance

share|improve this answer
    
Never knew there is a DISTINCT ON clause. Thank you. –  J-16 SDiZ Jan 28 at 2:13

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.