14

I am quite new to the postgresql.

what is the best way to achieve this?

SELECT get_columns() 
  FROM table_name;

get_columns() will provide the column names for the query. I saw people advising to use EXECUTE statement but I couldn't got that working.

Lets say there is table Test with columns a,b,c and I want to run

SELECT a,b FROM Test;
SELECT a,c FROM Test;

with column names generated dynamically.

6
  • What's the point? If you don't know the columnnames, just use an * in your query. Maybe I'm missing something? Commented Mar 3, 2010 at 20:39
  • 1
    What he's saying is get_columns() would return either columns a and c or columns a and b. He doesn't want all columns, just procedurally generated ones. Commented Mar 3, 2010 at 20:41
  • 1
    The idea is the get_columns() will take some argument and accordingly will return proper columns to be used somewhere. This piece will be useful when one deals with COPY FROM command where I need to provide column names based on what csv file I am selecting from. Commented Mar 3, 2010 at 20:43
  • But if you know the arguments for your functions, why don't you know the columnnames? You can get the columnnames, no problem, but if you already know them (see the arguments) there is no need to get them again. Commented Mar 3, 2010 at 20:48
  • Let me talk about my usecase here. We run a project where embedded devices send files to our server. There are 3-4 types of devices with each type with multiple version numbers. Each device sends a csv file with around 150 entries per line with each device columns change slightly. We have table for each type of device(where I will extract the column names from). I need to import these files into one giant table( one for all the devices) useing COPY FROM I don't want list the 9 different COPY FROM commands for each type of device file. I need a cleaner way to do this entire thing. Commented Mar 3, 2010 at 20:56

5 Answers 5

10

In order to write a dynamic query you would have to do something like:

EXECUTE 'SELECT '|| get_columns()|| ' FROM table_name' INTO results

Please read the documentation: http://developer.postgresql.org/pgdocs/postgres/plpgsql-statements.html

Sign up to request clarification or add additional context in comments.

1 Comment

How can I query with dynamic table name ? Such as SELECT * FROM (select table_name from XXX where id = 1);
1

In such case I would use PL/pgSQL function using cursor.

Comments

1

You wont be able to use a function to generate a column list. And I really don't think this is the best way to approach the problem... That said, you can do it with 8.4 like so:

CREATE OR REPLACE FUNCTION dyn(p_name VARCHAR)
RETURNS SETOF RECORD AS
$$
  DECLARE
    p_sql  TEXT;
  BEGIN
   SELECT 'SELECT ' ||
     CASE p_name WHEN 'foo' THEN ' col1, col2, col3, col4 '
      WHEN 'bar' THEN 'col3, col4, col5, col6'
      WHEN 'baz' THEN 'col1, col3, col4, col6' END ||
   ' FROM mytest'
   INTO p_sql;
   RETURN QUERY EXECUTE p_sql;
  END
$$ LANGUAGE 'plpgsql';

Usage would be: SELECT * FROM dyn('foo') AS (one int, two int, three int, four int)

But honestly I'd suggest just making a view for each device.

2 Comments

@ChrisTravers: That line just concatenates the script into p_sql. It's executed further down.
Ah, I see. Any reason not to do just RETURN QUERY EXECUTE 'SELECT...'?
0

Since you are using COPY FROM to a known large table, CREATE a FUNCTION which returns SETOF bigtable and SELECTs all the columns from the specific type, use NULL AS fieldname for the fields which are not required in that specific case, something like:

# \d SMALL
     Table "public.small"
 Column |  Type   | Modifiers 
--------+---------+-----------
 a      | integer | 
 b      | integer | 
 c      | integer | 
 d      | integer | 

# \d LARGE
     Table "public.large"
 Column |  Type   | Modifiers 
--------+---------+-----------
 a      | integer | 
 b      | integer | 
 c      | integer | 
 d      | integer | 

# CREATE OR REPLACE FUNCTION myData()
 RETURNS SETOF large LANGUAGE SQL AS $$
SELECT a, 
       CASE WHEN a = 1 
            THEN b 
       ELSE 
            NULL 
END as b, 
       CASE WHEN a = 2 
            THEN c 
       ELSE 
            NULL
END AS c, 
d
FROM small;
$$;

# SELECT * FROM mydata();
# COPY (SELECT * FROM myData()) TO STDOUT;

Obviously SQL might not be the best language to use, so PL/PgSQL or PL/Perl (or whatever) may be appropriate.

1 Comment

this seems to be the wrong way round, feel free to ignore this answer
0

I think your biggest problem is that you need to return rows in a way that PostgreSQL can understand. This means basically, you can return a refcursor or you can return a consistent set of data types. I prefer the latter because it makes the system a bit more consistent from a programming perspective and there are some advanced directions you can take that but I can see the other way too.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.