Reputation: 107
I have a massive, horribly constructed database and I am running a query through it to find a particular piece of data and let me know its table and column. Is there a way to make the query return data each time it finds something instead of at the end?
below is the query for those interested
CREATE OR REPLACE FUNCTION search_columns(
needle text,
haystack_tables name[] default '{}',
haystack_schema name[] default '{public}'
)
RETURNS table(schemaname text, tablename text, columnname text, rowctid text)
AS $$
begin
FOR schemaname,tablename,columnname IN
SELECT c.table_schema,c.table_name,c.column_name
FROM information_schema.columns c
JOIN information_schema.tables t ON
(t.table_name=c.table_name AND t.table_schema=c.table_schema)
WHERE (c.table_name=ANY(haystack_tables) OR haystack_tables='{}')
AND c.table_schema=ANY(haystack_schema)
AND t.table_type='BASE TABLE'
LOOP
EXECUTE format('SELECT ctid FROM %I.%I WHERE cast(%I as text)=%L',
schemaname,
tablename,
columnname,
needle
) INTO rowctid;
IF rowctid is not null THEN
RETURN NEXT;
END IF;
END LOOP;
END;
$$ language plpgsql;
--Search in all tables within public schema:
select * from search_columns('E0801');
Search in a specific table:
select * from search_columns('foobar','{w}');
Search in a subset of tables obtained from a select:
select * from
grep_columns('foobar', array(select table_name::name from information_schema.tables where table_name like 's%'), array['public']);
Get a result row with the corresponding base table and and ctid:
select * from public.w where ctid='(0,2)';
Upvotes: 1
Views: 142
Reputation: 22952
You can declare a CURSOR and FETCH using that. It will need to be inside an explicit transaction.
BEGIN;
DECLARE CURSOR mycurs FOR SELECT * FROM search_columns(...);
FETCH FORWARD 5 FROM mycurs;
-- repeat as needed
ROLLBACK;
If you are happy to modify the function you can have it return a REFCURSOR. Doing this can allow PostgreSQL to alter your plan to return some rows early (although this can make the overall cost of the query higher). For your particular example this seems unlikely to happen.
Upvotes: 0
Reputation: 121794
You can use RAISE NOTICE
provided that your client program shows notices asynchronously.
Insert RAISE NOTICE
before RETURN NEXT
and try it in psql:
...
IF rowctid is not null THEN
RAISE NOTICE '% % % %', schemaname, tablename, columnname, rowctid;
RETURN NEXT;
END IF;
...
Upvotes: 1