Добавить первичный ключ ко всем таблицам в базе данных, которые еще не имеют - PullRequest
2 голосов
/ 04 марта 2020

Исходный вопрос

В моей базе данных PostgreSQL у меня есть около 400 таблиц, в которых в настоящее время отсутствует PRIMARY KEY (что приводит к многочисленным проблемам в различных приложениях).

Я хочу исправить это сейчас. Я не хочу повторять следующие 400 раз:

ALTER TABLE table_schema.table_name ADD COLUMN ID SERIAL PRIMARY KEY;

Вместо этого я нашел способ найти все таблицы, в которых на данный момент нет PRIMARY KEY:

select tab.table_schema, tab.table_name
from information_schema.tables tab
left join information_schema.table_constraints tco 
          on tab.table_schema = tco.table_schema
          and tab.table_name = tco.table_name 
          and tco.constraint_type = 'PRIMARY KEY'
where tab.table_type = 'BASE TABLE'
      and tab.table_schema not in ('pg_catalog', 'information_schema')
      and tco.constraint_name is null
order by table_schema,
         table_name

В результате получается что-то вроде этого:

[table_schema]  [table_name]
"abc"           "grid_100m_20151127"
"abc"           "grid_100m_20190220"

... plus 400 more rows

Вопрос. Как объединить два запроса, чтобы результаты запроса SELECT использовались в * 1020? * query?

Полное решение

@ Ответ JimJones ниже привел к следующему решению:

DO $$
DECLARE row RECORD;
BEGIN
  FOR row IN 
    SELECT tab.table_schema, tab.table_name
    FROM information_schema.tables tab
    LEFT JOIN information_schema.table_constraints tco 
          ON tab.table_schema = tco.table_schema
          AND tab.table_name = tco.table_name 
          AND tco.constraint_type = 'PRIMARY KEY'
    WHERE tab.table_type = 'BASE TABLE'
          AND tab.table_schema not in ('pg_catalog', 'information_schema')
          AND tco.constraint_name is null
    ORDER BY table_schema, table_name 
    LOOP 
        EXECUTE 'ALTER TABLE "' || row.table_schema || '"."' || row.table_name  || '" ADD COLUMN PRIMARY_KEY SERIAL PRIMARY KEY';
    END LOOP;  
END;
$$;

Большое вам спасибо за помощь мне с этим !

1 Ответ

1 голос
/ 04 марта 2020

Вы пытались использовать LOOP внутри anonymous code block?

DO $$
DECLARE row RECORD;
BEGIN
  FOR row IN SELECT tab.table_schema, tab.table_name ... LOOP 
    EXECUTE 'ALTER TABLE "' || row.table_schema || '"."' || row.table_name  || '" ADD COLUMN PRIMARY_KEY SERIAL PRIMARY KEY';
  END LOOP;
END;
$$;

Поместите запрос между FOR row IN и LOOP.

Я имел дело с аналогичной проблемой в another answer.

EDIT : следующий синтаксис, предложенный @filiprem, выглядит также очень аккуратно (кажись комментарии):)

EXECUTE format('ALTER TABLE %I.%I ADD id serial PRIMARY KEY', table_schema, table_name);
...