Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I want a select that returns all fields in a table that are of type = "character varying". It needs to run across multiple tables, so needs to be dynamic.

I was trying to use a subquery to first get the text columns, and then run the query:

SELECT (SELECT STRING_AGG(QUOTE_IDENT(column_name), ', ') FROM 
information_schema.columns WHERE table_name = foo 
AND data_type = 'character varying') FROM foo;

But that's not working, I just get a list of column names but not the values. Does anyone know how I can make it work or a better way to do it?

Thank you, Ben

share|improve this question
2  
you must generate the SQL in a 1st step and execute it in a 2nd step. A single SQL statement cannot generate itself during its own execution. –  Daniel Vérité Jan 22 '14 at 15:22

1 Answer 1

up vote 0 down vote accepted

You need Pl/PgSQL for this, as PostgreSQL doesn't support dynamic SQL in its plain SQL dialect.

CREATE OR REPLACE FUNCTION get_cols(target_table text) RETURNS SETOF record AS $$
DECLARE
    cols text;
BEGIN
    cols := (SELECT STRING_AGG(QUOTE_IDENT(column_name), ', ')
             FROM information_schema.columns 
             WHERE table_name = target_table 
             AND data_type = 'character varying');

    RETURN QUERY EXECUTE 'SELECT '||cols||' FROM '||quote_ident(target_table)||';';
END;
$$
LANGUAGE plpgsql;

However, you'll find this hard to call, as you need to know the result column list to be able to call it. That kind of defeats the point. You'll need to massage the result into a concrete type. I convert to hstore here, but you could return json or an array or whatever, really:

CREATE OR REPLACE FUNCTION get_cols(target_table text) RETURNS SETOF hstore AS $$
DECLARE
    cols text;
BEGIN
    cols := (SELECT STRING_AGG(QUOTE_IDENT(column_name), ', ')
             FROM information_schema.columns 
             WHERE table_name = target_table 
             AND data_type = 'character varying');

    RETURN QUERY EXECUTE 'SELECT hstore(ROW('||cols||')) FROM '||quote_ident(target_table)||';';
END;
$$
LANGUAGE plpgsql;

Dynamic SQL is a pain, consider doing this at the application level.

share|improve this answer
    
Thanks very much for the extensive answer, shame it's such a pain to do but it's interesting to know how. I'll try the app level instead. –  Ben Scott Jan 23 '14 at 10:28

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.