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
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
add a comment |
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
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 likepgpgsql
and missing;
indicate that's hand-knit dummy code. Please show what you actually tested. And have you considered runningANALYZE
on involved tables? Then you can work withpg_class.reltuples
...
– Erwin Brandstetter
11 hours ago
add a comment |
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
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
postgresql order-by postgresql-9.6 dynamic-sql plpgsql
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 likepgpgsql
and missing;
indicate that's hand-knit dummy code. Please show what you actually tested. And have you considered runningANALYZE
on involved tables? Then you can work withpg_class.reltuples
...
– Erwin Brandstetter
11 hours ago
add a comment |
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 likepgpgsql
and missing;
indicate that's hand-knit dummy code. Please show what you actually tested. And have you considered runningANALYZE
on involved tables? Then you can work withpg_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
add a comment |
1 Answer
1
active
oldest
votes
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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
add a comment |
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
add a comment |
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
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
edited 2 mins ago
answered 9 hours ago
Erwin BrandstetterErwin Brandstetter
93.2k9179292
93.2k9179292
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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 runningANALYZE
on involved tables? Then you can work withpg_class.reltuples
...– Erwin Brandstetter
11 hours ago