PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

O Postgres encontra todas as linhas nas tabelas do banco de dados que correspondem aos critérios em uma determinada coluna


Tirei um tempo para fazê-lo funcionar para você.

Para começar, algumas informações sobre o que está acontecendo dentro do código.

Explicação

  1. função recebe dois argumentos de entrada:nome da coluna e valor da coluna
  2. requer um tipo criado que retornará um conjunto de
  3. o primeiro loop identifica as tabelas que têm um nome de coluna especificado como argumento de entrada
  4. ele forma uma consulta que agrega todas as linhas que correspondem à condição de entrada dentro de cada tabela obtida da etapa 3 com comparação baseada em ILIKE - conforme seu exemplo
  5. função vai para o segundo loop somente se houver pelo menos uma linha na tabela visitada atualmente que corresponda à condição especificada (então a matriz não é nula)
  6. segundo loop desaninha o array de linhas que correspondem à condição e para cada elemento ele o coloca na saída da função com RETURN NEXT rec cláusula

Observações


  • Pesquisar com LIKE é ineficiente - sugiro adicionar outro argumento de entrada "tipo de coluna" e restringi-lo na pesquisa adicionando uma junção a pg_catalog.pg_type tabela.

  • O segundo loop existe para que, se mais de 1 linha for encontrada para uma tabela específica, todas as linhas sejam retornadas.

  • Se você estiver procurando por outra coisa, como precisar de pares de valores-chave, não apenas os valores, precisará estender a função. Você pode, por exemplo, criar o formato json a partir de linhas.

Agora, para o código.

Caso de teste

CREATE TABLE tbl1 (col1 int, id int); -- does contain values
CREATE TABLE tbl2 (col1 int, col2 int); -- doesn't contain column "id"
CREATE TABLE tbl3 (id int, col5 int); -- doesn't contain values

INSERT INTO tbl1 (col1, id)
  VALUES (1, 5), (1, 33), (1, 25);

A tabela armazena dados:
postgres=# select * From tbl1;

 col1 | id
------+----
    1 |  5
    1 | 33
    1 | 25
(3 rows)

Criando tipo

CREATE TYPE sometype AS ( schemaname text, tablename text, colname text, entirerow text );

Código de função

CREATE OR REPLACE FUNCTION search_tables_for_column (
    v_column_name text
  , v_column_value text
)
RETURNS SETOF sometype
LANGUAGE plpgsql
STABLE
AS
$$
DECLARE
  rec           sometype%rowtype;
  v_row_array   text[];
  rec2          record;
  arr_el        text;
BEGIN
FOR rec IN
  SELECT 
      nam.nspname AS schemaname
    , cls.relname AS tablename
    , att.attname AS colname
    , null::text AS entirerow
  FROM 
    pg_attribute att
    JOIN pg_class cls ON att.attrelid = cls.oid 
    JOIN pg_namespace nam ON cls.relnamespace = nam.oid 
  WHERE 
    cls.relkind = 'r'
    AND att.attname = v_column_name
LOOP
  EXECUTE format('SELECT ARRAY_AGG(row(tablename.*)::text) FROM %I.%I AS tablename WHERE %I::text ILIKE %s',
    rec.schemaname, rec.tablename, rec.colname, quote_literal(concat('%',v_column_value,'%'))) INTO v_row_array;
  IF v_row_array is not null THEN
    FOR rec2 IN
      SELECT unnest(v_row_array) AS one_row
    LOOP
      rec.entirerow := rec2.one_row;
      RETURN NEXT rec;
    END LOOP;
  END IF;
END LOOP;
END
$$;

Chamada e saída exemplares

postgres=# select * from search_tables_for_column('id','5');

 schemaname | tablename | colname | entirerow
------------+-----------+---------+-----------
 public     | tbl1      | id      | (1,5)
 public     | tbl1      | id      | (1,25)
(2 rows)