Як додати стовпчик із обмеженням іноземного ключа до таблиці, яка вже існує?


11

У мене є такі таблиці,

CREATE TABLE users (id int PRIMARY KEY);

-- already exists with data
CREATE TABLE message ();

Як я можу змінити messagesтаблицю таким чином,

  1. senderдо нього додається новий стовпчик, що називається
  2. де senderзнаходиться зовнішній ключ, на який посилається usersтаблиця

Це не спрацювало

# ALTER TABLE message ADD FOREIGN KEY (sender) REFERENCES users;
ERROR:  column "sender" referenced in foreign key constraint does not exist

Чи не створює цей вислів і стовпець?


3
Потрібно створити стовпець, перш ніж посилатися на нього. Я також спробую прочитати тут документацію для ПІДХІДНОЇ ТАБЛИКИ і звернути дуже пильну увагу на приклади.
Кассандрі

Хассан, я прибрав це питання, щоб використовувати DDL, і я видалив речі, які не працювали. Перевірте, чи відповідає це питання: dba.stackexchange.com/a/202564/2639 . Не соромтеся відхилити будь-яку з цих змін, я просто хотів очистити це для нащадків.
Еван Керролл

Відповіді:


18

Що відносно просто - потрібно лише додати ще один крок.

FOREIGN KEYСтовпець повинен існувати для того , щоб зробити це FK. Я зробив наступне ( звідси і документація ):

CREATE TABLE x(t INT PRIMARY KEY);

CREATE TABLE y(s INT);

ALTER TABLE y ADD COLUMN z INT;    

ALTER TABLE y
  ADD CONSTRAINT y_x_fkey FOREIGN KEY (z)
      REFERENCES x (t)
      ON UPDATE CASCADE ON DELETE CASCADE;

Кілька пунктів, які слід зазначити:

ЗАВЖДИ дайте своїм іноземним ключам значущі імена. Сказання, що ключ "SYS_C00308108" порушується, не дуже корисно. Дивіться загадку тут про поведінку Oracle за цих обставин, ключове ім'я буде змінюватися від скрипки до загадки, але це якась довільна рядок, що починається з SYS _...)

Розглядаючи вашу заяву:

ALTER TABLE message ADD FOREIGN KEY (sender) REFERENCES users;

Було б "приємно мати", якщо RDBMS зможе автоматично створити потрібне поле із типом даних, що відповідає полюваному полю. Все, що я хотів би сказати, - це те, що зміна DDL - це операція, яка рідко використовується, а не те, що ви хочете робити регулярно. Це також ризикує додати до вже досить суттєвої документації.

Принаймні, PostgreSQL намагається зробити щось розумне - це поєднує ім'я таблиці, ім'я FOREIGN KEYполя _fkeyі навіть додає, DETAIL: Key (sender_id)=(56) is not present in table "user_".щоб дати щось, що може мати сенс для людини - дивіться тут скрипку .


2
Я ніколи не називаю свої закордонні ключі. Вони отримують автономію, і вони зазвичай дуже корисні. Наприклад, ім'я за замовчуванням у цьому контексті є "y_z_fkey". Я б стверджувати , що це краще , ніж ім'я , y_x_fkeyтому що ваше порушення не говорять вам , колонка ви вставка в це викликає помилку. Мене менше хвилює, куди це вказує. Як правило, вам НІКОЛИ не слід називати своїх фейків і не дозволяти PostgreSQL за замовчуванням обробляти це.
Еван Керролл

Крім того, ви, можливо, не захочете перевизначити параметри за замовчуванням ON UPDATE CASCADE ON DELETE CASCADE;у прикладі, особливо без причин. Це робить приклад складнішим, і ви не намагаєтеся пояснювати, що це таке. Я, як правило, не хочу видаляти видалення в каскад.
Еван Керролл

1
Я завжди називаю FK, відповідно до конвенції, яку ухвалила компанія / проект. Це не має великого значення, якщо він y_x_fkeyабо y_z_fkeyчи x__y_FK, якщо воно відповідає.
ypercubeᵀᴹ

Я б дуже погодився з цим, якщо ви укладаєте договори - виберіть конвенцію та дотримуйтесь її та / або переконайтесь, що ви відповідаєте конвенціям, які раніше / використовувались із системою.
Vérace

@EvanCarroll - якщо умова PostgreSQL є проектом або попередньо зваженою системою, яка може бути не PostgreSQL, система, можливо, може почати працювати, скажімо, Oracle або іншою системою, яка може не мати умов PostgreSQL. Ви можете стверджувати, що x_y_z_fk може дати максимально можливу інформацію у випадку помилки! Виберіть щось і дотримуйтесь цього - мій девіз, але не дозволяйте жодному RDBMS (неважливо, наскільки добре) приймати рішення для вас!
Vérace

8

Я не впевнений, чому всі говорять вам, що ви повинні зробити це в два кроки. Насправді ви цього не робите . Ви спробували додати а, FOREIGN KEYякий передбачає, що, за задумом, стовпець є і видає цю помилку, якщо стовпця немає. Якщо ви додасте COLUMN, ви можете явно зробити його FOREIGN KEYстворенням REFERENCES,

ALTER TABLE message
  ADD COLUMN sender INT
  REFERENCES users;  -- or REFERENCES table(unique_column)

Буде добре працювати. Ви можете побачити тут синтаксис ALTER TABLE,

ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
action [, ... ]

З "діями" як,

ADD [ COLUMN ] [ IF NOT EXISTS ] column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ]

Ці приклади є навіть у документах,

ALTER TABLE distributors
  ADD CONSTRAINT distfk
  FOREIGN KEY (address)
  REFERENCES addresses (address);

ALTER TABLE distributors
  ADD CONSTRAINT distfk
  FOREIGN KEY (address)
  REFERENCES addresses (address)
  NOT VALID;

Але все це не потрібно, тому що ми можемо розраховувати на автоматичне позначення та роздільну здатність первинного ключа (якщо вказано лише ім’я таблиці, тоді ви посилаєтесь на первинний ключ).


0

CASE1: Якщо вам потрібно створити зовнішній ключ під час створення нової таблиці

CREATE TABLE table1(
id SERIAL PRIMARY KEY,
column1 varchar(n) NOT NULL,
table2_id SMALLINT REFERENCES table2(id)
); 

Вищезазначені команди створять таблицю з ім'ям 'table1' та трьома стовпцями з назвою 'id' (Первинний ключ), 'column1', 'table2_id' (зовнішній ключ таблиці1, на який посилається стовпець таблиці table2).

ДАТАТИП "серійний" зробить стовпець, який використовує цей тип даних як стовпчик, що автоматично генерується, при вставці значень у таблицю взагалі не потрібно згадувати цей стовпець, або ви можете вказати "за замовчуванням" без лапок у значенні місця.

Стовпчик первинного ключа завжди додається до індексу таблиці зі значенням 'tablename_pkey'.

Якщо зовнішній ключ доданий під час створення таблиці, додається CONSTRAINT з шаблоном '(present_table_name) _ (Foreign_key_id_name) _fkey'.

Додаючи закордонний ключ, ми повинні ввести ключове слово "СПРАВКИ" поруч із назвою стовпця, оскільки ми хочемо повідомити постграфам, що цей стовпець посилається на таблицю, а потім поряд із посиланнями ми повинні дати таблицю для ознайомлення та в дужках дати Назва стовпця посилається на таблицю, як правило, сторонні ключі задаються як стовпці первинного ключа.

СЛУЧАЙ 2: Якщо ви хочете отримати зовнішній ключ до існуючої таблиці в існуючому стовпці

ALTER TABLE table1
ADD CONSTRAINT table1_table2_id_id_fkey
FOREIGN KEY (table2_id) REFERENCES table2(id);

ПРИМІТКА: дужки "()" після ЗНОШЕНОГО КЛЮЧА та РЕФЕРЕНЦІЙ tabel2 є обов'язковими, інакше постгреси викличуть помилку.


0

Я знаю проблему. Назви стовпців різні. Можливо, в одному стовпчику є додатковий простір після назви стовпця, тому, будь ласка, уважно переконайтесь, що назви ваших стовпців названі точно однаково


1
ОП запитав: Чи також ця заява не створює стовпчик? Тож видно, що він очікував, що це станеться.
Лоренц Альбе
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.