Sort output of plpgsql functionSQL injection in Postgres functions vs prepared queriesRecursive query using...

Why do neural networks need so many examples to perform?

Modern Algebraic Geometry and Analytic Number Theory

How do dictionaries source attestation?

Boss asked me to sign a resignation paper without a date on it along with my new contract

Was there a pre-determined arrangement for the division of Germany in case it surrendered before any Soviet forces entered its territory?

What are some ways of extending a description of a scenery?

How bad is a Computer Science course that doesn't teach Design Patterns?

Why is "rm -r" unable to delete this folder?

Does it take energy to move something in a circle?

Is there any danger of my neighbor having my wife's signature?

Is Screenshot Time-tracking Common?

Is there a way to pause a running process on Linux systems and resume later?

Is it really OK to use "because of"?

Illustrator to chemdraw

How can I prevent an oracle who can see into the past from knowing everything that has happened?

How much light is too much?

To be or not to be - Optional arguments inside definition of macro

Why did Luke use his left hand to shoot?

Crack the bank account's password!

How do you get out of your own psychology to write characters?

Single-row INSERT...SELECT much slower than separate SELECT

What is the draw frequency for 3 consecutive games (same players; amateur level)?

Is `Object` a function in javascript?

What does an unprocessed RAW file look like?



Sort output of plpgsql function


SQL injection in Postgres functions vs prepared queriesRecursive query using plpgsqlSlow fulltext search due to wildly inaccurate row estimatesHow to Insert records from remote database to local database using dblink in postgresql 9.3SELECT in trigger function in two tablesPostgreSQL 9.5, getting “cached plan must not change result type” errorPostgres full text search with better matchPostgres: query on huge (11gb ) index does not returnPostgresql: Insert trigger function from select query, plus static values pulled from the new.<record>Loop through slices of 2-dimensional array in plpgsql function?PLPGSQL function(multiple column output)--gives error













1















I'm creating a function in Postgres 9.6 that compares two schemas with the same tables. I want to find tables which are empty in one schema but populated in the other. I'm avoiding the reltuples attribute found in the information schema because it is not guaranteed to be correct.



So far I have this function:



CREATE OR REPLACE FUNCTION public.compare_schemas_by_table_emptiness(schema1 text, schema2 text) 
RETURNS TABLE(tablename text, schema1_ct integer, schema2_ct integer, match boolean) AS $$
DECLARE
schema1_tables CURSOR FOR
select pg_tables.tablename
from pg_tables
where schemaname ~ schema1
order by tablename;
schema1_ct int;
schema2_ct int;
BEGIN
FOR table_record IN schema1_tables LOOP
EXECUTE 'SELECT count(*) FROM ' || schema1 || '.' || table_record.tablename INTO schema1_ct
EXECUTE 'SELECT count(*) FROM ' || schema2 || '.' || table_record.tablename INTO schema2_ct
RETURN QUERY EXECUTE 'SELECT ''' || table_record.tablename || '''::text,' || schema1_ct || ',' || schema2_ct || ',' (schema1_ct >= 0) = (schema2_ct >= 0)
END LOOP
END; $$ LANGUAGE pgpgsql


But I'm really only interested in the cases where the output's match column is false, that is, one table is empty and one table is not empty. How I can I sort my output so that row where match = false are shown first?










share|improve this question

























  • How I can I sort my output so that row where match = False are shown first? order by match, ...

    – Akina
    Feb 12 at 19:30













  • Typos like pgpgsql and missing ; indicate that's hand-knit dummy code. Please show what you actually tested. And have you considered running ANALYZE on involved tables? Then you can work with pg_class.reltuples ...

    – Erwin Brandstetter
    11 hours ago
















1















I'm creating a function in Postgres 9.6 that compares two schemas with the same tables. I want to find tables which are empty in one schema but populated in the other. I'm avoiding the reltuples attribute found in the information schema because it is not guaranteed to be correct.



So far I have this function:



CREATE OR REPLACE FUNCTION public.compare_schemas_by_table_emptiness(schema1 text, schema2 text) 
RETURNS TABLE(tablename text, schema1_ct integer, schema2_ct integer, match boolean) AS $$
DECLARE
schema1_tables CURSOR FOR
select pg_tables.tablename
from pg_tables
where schemaname ~ schema1
order by tablename;
schema1_ct int;
schema2_ct int;
BEGIN
FOR table_record IN schema1_tables LOOP
EXECUTE 'SELECT count(*) FROM ' || schema1 || '.' || table_record.tablename INTO schema1_ct
EXECUTE 'SELECT count(*) FROM ' || schema2 || '.' || table_record.tablename INTO schema2_ct
RETURN QUERY EXECUTE 'SELECT ''' || table_record.tablename || '''::text,' || schema1_ct || ',' || schema2_ct || ',' (schema1_ct >= 0) = (schema2_ct >= 0)
END LOOP
END; $$ LANGUAGE pgpgsql


But I'm really only interested in the cases where the output's match column is false, that is, one table is empty and one table is not empty. How I can I sort my output so that row where match = false are shown first?










share|improve this question

























  • How I can I sort my output so that row where match = False are shown first? order by match, ...

    – Akina
    Feb 12 at 19:30













  • Typos like pgpgsql and missing ; indicate that's hand-knit dummy code. Please show what you actually tested. And have you considered running ANALYZE on involved tables? Then you can work with pg_class.reltuples ...

    – Erwin Brandstetter
    11 hours ago














1












1








1








I'm creating a function in Postgres 9.6 that compares two schemas with the same tables. I want to find tables which are empty in one schema but populated in the other. I'm avoiding the reltuples attribute found in the information schema because it is not guaranteed to be correct.



So far I have this function:



CREATE OR REPLACE FUNCTION public.compare_schemas_by_table_emptiness(schema1 text, schema2 text) 
RETURNS TABLE(tablename text, schema1_ct integer, schema2_ct integer, match boolean) AS $$
DECLARE
schema1_tables CURSOR FOR
select pg_tables.tablename
from pg_tables
where schemaname ~ schema1
order by tablename;
schema1_ct int;
schema2_ct int;
BEGIN
FOR table_record IN schema1_tables LOOP
EXECUTE 'SELECT count(*) FROM ' || schema1 || '.' || table_record.tablename INTO schema1_ct
EXECUTE 'SELECT count(*) FROM ' || schema2 || '.' || table_record.tablename INTO schema2_ct
RETURN QUERY EXECUTE 'SELECT ''' || table_record.tablename || '''::text,' || schema1_ct || ',' || schema2_ct || ',' (schema1_ct >= 0) = (schema2_ct >= 0)
END LOOP
END; $$ LANGUAGE pgpgsql


But I'm really only interested in the cases where the output's match column is false, that is, one table is empty and one table is not empty. How I can I sort my output so that row where match = false are shown first?










share|improve this question
















I'm creating a function in Postgres 9.6 that compares two schemas with the same tables. I want to find tables which are empty in one schema but populated in the other. I'm avoiding the reltuples attribute found in the information schema because it is not guaranteed to be correct.



So far I have this function:



CREATE OR REPLACE FUNCTION public.compare_schemas_by_table_emptiness(schema1 text, schema2 text) 
RETURNS TABLE(tablename text, schema1_ct integer, schema2_ct integer, match boolean) AS $$
DECLARE
schema1_tables CURSOR FOR
select pg_tables.tablename
from pg_tables
where schemaname ~ schema1
order by tablename;
schema1_ct int;
schema2_ct int;
BEGIN
FOR table_record IN schema1_tables LOOP
EXECUTE 'SELECT count(*) FROM ' || schema1 || '.' || table_record.tablename INTO schema1_ct
EXECUTE 'SELECT count(*) FROM ' || schema2 || '.' || table_record.tablename INTO schema2_ct
RETURN QUERY EXECUTE 'SELECT ''' || table_record.tablename || '''::text,' || schema1_ct || ',' || schema2_ct || ',' (schema1_ct >= 0) = (schema2_ct >= 0)
END LOOP
END; $$ LANGUAGE pgpgsql


But I'm really only interested in the cases where the output's match column is false, that is, one table is empty and one table is not empty. How I can I sort my output so that row where match = false are shown first?







postgresql order-by postgresql-9.6 dynamic-sql plpgsql






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 30 secs ago









Erwin Brandstetter

93.2k9179292




93.2k9179292










asked Feb 12 at 18:07









DerekDerek

83




83













  • How I can I sort my output so that row where match = False are shown first? order by match, ...

    – Akina
    Feb 12 at 19:30













  • Typos like pgpgsql and missing ; indicate that's hand-knit dummy code. Please show what you actually tested. And have you considered running ANALYZE on involved tables? Then you can work with pg_class.reltuples ...

    – Erwin Brandstetter
    11 hours ago



















  • How I can I sort my output so that row where match = False are shown first? order by match, ...

    – Akina
    Feb 12 at 19:30













  • Typos like pgpgsql and missing ; indicate that's hand-knit dummy code. Please show what you actually tested. And have you considered running ANALYZE on involved tables? Then you can work with pg_class.reltuples ...

    – Erwin Brandstetter
    11 hours ago

















How I can I sort my output so that row where match = False are shown first? order by match, ...

– Akina
Feb 12 at 19:30







How I can I sort my output so that row where match = False are shown first? order by match, ...

– Akina
Feb 12 at 19:30















Typos like pgpgsql and missing ; indicate that's hand-knit dummy code. Please show what you actually tested. And have you considered running ANALYZE on involved tables? Then you can work with pg_class.reltuples ...

– Erwin Brandstetter
11 hours ago





Typos like pgpgsql and missing ; indicate that's hand-knit dummy code. Please show what you actually tested. And have you considered running ANALYZE on involved tables? Then you can work with pg_class.reltuples ...

– Erwin Brandstetter
11 hours ago










1 Answer
1






active

oldest

votes


















0














While returning rows from a loop directly, the sort order is determined by the loop. PL/pgSQL builds up the result set and you can still raise an exception to prevent the function from returning anything until the last moment (There is a code example in the manual.) But there is no way to re-order the result set before finally returning. You would have to add ORDER BY to the function call for that:



SELECT * FROM public.compare_schemas_by_table_emptiness('foo', 'bar')
ORDER BY match;


FALSE sorts before TRUE, so non-matches come first.




But I'm really only interested in the cases where the output's "match" column is false




So don't do more work than required. This function does what you need, efficient and safe against SQL injection (unlike your original):



CREATE OR REPLACE FUNCTION public.compare_schemas_by_table_emptiness(_schema1 text, _schema2 text) 
RETURNS TABLE(tablename text, schema1_ct bigint, schema2_ct bigint)
LANGUAGE plpgsql AS
$func$
BEGIN
FOR tablename IN
SELECT quote_ident(t.tablename) -- must be table-qualified, due to dupe in OUT parameters!
FROM pg_catalog.pg_tables t
WHERE t.schemaname = _schema1
ORDER BY 1
LOOP
EXECUTE format(
'SELECT (SELECT count(*) FROM %1$I.%3$s)
, (SELECT count(*) FROM %2$I.%3$s)
WHERE EXISTS (SELECT FROM %1$I.%3$s)
<> EXISTS (SELECT FROM %2$I.%3$s)'
, _schema1, _schema2, tablename)
INTO schema1_ct, schema2_ct;

CONTINUE WHEN schema1_ct IS NULL; -- happens when both or none have values
RETURN NEXT;
END LOOP;
END
$func$;


Call:



SELECT * FROM public.compare_schemas_by_table_emptiness('foo', 'bar');


Counting can be expensive with big tables, so this function only counts when required.



Identifiers may or may not require double-quoting and have to be treated like user input to be safe. See:




  • SQL injection in Postgres functions vs prepared queries






share|improve this answer

























    Your Answer








    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "182"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f229534%2fsort-output-of-plpgsql-function%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    0














    While returning rows from a loop directly, the sort order is determined by the loop. PL/pgSQL builds up the result set and you can still raise an exception to prevent the function from returning anything until the last moment (There is a code example in the manual.) But there is no way to re-order the result set before finally returning. You would have to add ORDER BY to the function call for that:



    SELECT * FROM public.compare_schemas_by_table_emptiness('foo', 'bar')
    ORDER BY match;


    FALSE sorts before TRUE, so non-matches come first.




    But I'm really only interested in the cases where the output's "match" column is false




    So don't do more work than required. This function does what you need, efficient and safe against SQL injection (unlike your original):



    CREATE OR REPLACE FUNCTION public.compare_schemas_by_table_emptiness(_schema1 text, _schema2 text) 
    RETURNS TABLE(tablename text, schema1_ct bigint, schema2_ct bigint)
    LANGUAGE plpgsql AS
    $func$
    BEGIN
    FOR tablename IN
    SELECT quote_ident(t.tablename) -- must be table-qualified, due to dupe in OUT parameters!
    FROM pg_catalog.pg_tables t
    WHERE t.schemaname = _schema1
    ORDER BY 1
    LOOP
    EXECUTE format(
    'SELECT (SELECT count(*) FROM %1$I.%3$s)
    , (SELECT count(*) FROM %2$I.%3$s)
    WHERE EXISTS (SELECT FROM %1$I.%3$s)
    <> EXISTS (SELECT FROM %2$I.%3$s)'
    , _schema1, _schema2, tablename)
    INTO schema1_ct, schema2_ct;

    CONTINUE WHEN schema1_ct IS NULL; -- happens when both or none have values
    RETURN NEXT;
    END LOOP;
    END
    $func$;


    Call:



    SELECT * FROM public.compare_schemas_by_table_emptiness('foo', 'bar');


    Counting can be expensive with big tables, so this function only counts when required.



    Identifiers may or may not require double-quoting and have to be treated like user input to be safe. See:




    • SQL injection in Postgres functions vs prepared queries






    share|improve this answer






























      0














      While returning rows from a loop directly, the sort order is determined by the loop. PL/pgSQL builds up the result set and you can still raise an exception to prevent the function from returning anything until the last moment (There is a code example in the manual.) But there is no way to re-order the result set before finally returning. You would have to add ORDER BY to the function call for that:



      SELECT * FROM public.compare_schemas_by_table_emptiness('foo', 'bar')
      ORDER BY match;


      FALSE sorts before TRUE, so non-matches come first.




      But I'm really only interested in the cases where the output's "match" column is false




      So don't do more work than required. This function does what you need, efficient and safe against SQL injection (unlike your original):



      CREATE OR REPLACE FUNCTION public.compare_schemas_by_table_emptiness(_schema1 text, _schema2 text) 
      RETURNS TABLE(tablename text, schema1_ct bigint, schema2_ct bigint)
      LANGUAGE plpgsql AS
      $func$
      BEGIN
      FOR tablename IN
      SELECT quote_ident(t.tablename) -- must be table-qualified, due to dupe in OUT parameters!
      FROM pg_catalog.pg_tables t
      WHERE t.schemaname = _schema1
      ORDER BY 1
      LOOP
      EXECUTE format(
      'SELECT (SELECT count(*) FROM %1$I.%3$s)
      , (SELECT count(*) FROM %2$I.%3$s)
      WHERE EXISTS (SELECT FROM %1$I.%3$s)
      <> EXISTS (SELECT FROM %2$I.%3$s)'
      , _schema1, _schema2, tablename)
      INTO schema1_ct, schema2_ct;

      CONTINUE WHEN schema1_ct IS NULL; -- happens when both or none have values
      RETURN NEXT;
      END LOOP;
      END
      $func$;


      Call:



      SELECT * FROM public.compare_schemas_by_table_emptiness('foo', 'bar');


      Counting can be expensive with big tables, so this function only counts when required.



      Identifiers may or may not require double-quoting and have to be treated like user input to be safe. See:




      • SQL injection in Postgres functions vs prepared queries






      share|improve this answer




























        0












        0








        0







        While returning rows from a loop directly, the sort order is determined by the loop. PL/pgSQL builds up the result set and you can still raise an exception to prevent the function from returning anything until the last moment (There is a code example in the manual.) But there is no way to re-order the result set before finally returning. You would have to add ORDER BY to the function call for that:



        SELECT * FROM public.compare_schemas_by_table_emptiness('foo', 'bar')
        ORDER BY match;


        FALSE sorts before TRUE, so non-matches come first.




        But I'm really only interested in the cases where the output's "match" column is false




        So don't do more work than required. This function does what you need, efficient and safe against SQL injection (unlike your original):



        CREATE OR REPLACE FUNCTION public.compare_schemas_by_table_emptiness(_schema1 text, _schema2 text) 
        RETURNS TABLE(tablename text, schema1_ct bigint, schema2_ct bigint)
        LANGUAGE plpgsql AS
        $func$
        BEGIN
        FOR tablename IN
        SELECT quote_ident(t.tablename) -- must be table-qualified, due to dupe in OUT parameters!
        FROM pg_catalog.pg_tables t
        WHERE t.schemaname = _schema1
        ORDER BY 1
        LOOP
        EXECUTE format(
        'SELECT (SELECT count(*) FROM %1$I.%3$s)
        , (SELECT count(*) FROM %2$I.%3$s)
        WHERE EXISTS (SELECT FROM %1$I.%3$s)
        <> EXISTS (SELECT FROM %2$I.%3$s)'
        , _schema1, _schema2, tablename)
        INTO schema1_ct, schema2_ct;

        CONTINUE WHEN schema1_ct IS NULL; -- happens when both or none have values
        RETURN NEXT;
        END LOOP;
        END
        $func$;


        Call:



        SELECT * FROM public.compare_schemas_by_table_emptiness('foo', 'bar');


        Counting can be expensive with big tables, so this function only counts when required.



        Identifiers may or may not require double-quoting and have to be treated like user input to be safe. See:




        • SQL injection in Postgres functions vs prepared queries






        share|improve this answer















        While returning rows from a loop directly, the sort order is determined by the loop. PL/pgSQL builds up the result set and you can still raise an exception to prevent the function from returning anything until the last moment (There is a code example in the manual.) But there is no way to re-order the result set before finally returning. You would have to add ORDER BY to the function call for that:



        SELECT * FROM public.compare_schemas_by_table_emptiness('foo', 'bar')
        ORDER BY match;


        FALSE sorts before TRUE, so non-matches come first.




        But I'm really only interested in the cases where the output's "match" column is false




        So don't do more work than required. This function does what you need, efficient and safe against SQL injection (unlike your original):



        CREATE OR REPLACE FUNCTION public.compare_schemas_by_table_emptiness(_schema1 text, _schema2 text) 
        RETURNS TABLE(tablename text, schema1_ct bigint, schema2_ct bigint)
        LANGUAGE plpgsql AS
        $func$
        BEGIN
        FOR tablename IN
        SELECT quote_ident(t.tablename) -- must be table-qualified, due to dupe in OUT parameters!
        FROM pg_catalog.pg_tables t
        WHERE t.schemaname = _schema1
        ORDER BY 1
        LOOP
        EXECUTE format(
        'SELECT (SELECT count(*) FROM %1$I.%3$s)
        , (SELECT count(*) FROM %2$I.%3$s)
        WHERE EXISTS (SELECT FROM %1$I.%3$s)
        <> EXISTS (SELECT FROM %2$I.%3$s)'
        , _schema1, _schema2, tablename)
        INTO schema1_ct, schema2_ct;

        CONTINUE WHEN schema1_ct IS NULL; -- happens when both or none have values
        RETURN NEXT;
        END LOOP;
        END
        $func$;


        Call:



        SELECT * FROM public.compare_schemas_by_table_emptiness('foo', 'bar');


        Counting can be expensive with big tables, so this function only counts when required.



        Identifiers may or may not require double-quoting and have to be treated like user input to be safe. See:




        • SQL injection in Postgres functions vs prepared queries







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 2 mins ago

























        answered 9 hours ago









        Erwin BrandstetterErwin Brandstetter

        93.2k9179292




        93.2k9179292






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Database Administrators Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fdba.stackexchange.com%2fquestions%2f229534%2fsort-output-of-plpgsql-function%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Szabolcs (Ungheria) Altri progetti | Menu di navigazione48°10′14.56″N 21°29′33.14″E /...

            Discografia di Klaus Schulze Indice Album in studio | Album dal vivo | Singoli | Antologie | Colonne...

            How to make inet_server_addr() return localhost in spite of ::1/128RETURN NEXT in Postgres FunctionConnect to...