Доброго времени суток. Задавал эти вопросы в forum.postgresqlrussia.org, но внятного ответа так и не дождался.
Надеюсь, что здесь есть кто-нибудь, кто сталкивался с подобного рода ситуациями.
Проблема в следующем. Есть 4 таблицы:
CREATE TABLE "employees" ( "emp_uid" SERIAL, "emp_fam" TEXT DEFAULT 'н е и з в е с т н о'::text NOT NULL, "emp_name" TEXT DEFAULT 'н е и з в е с т н о'::text NOT NULL, "emp_otch" TEXT DEFAULT 'н е и з в е с т н о'::text NOT NULL, "emp_was_born" DATE, "emp_email" TEXT, "emp_icq_num" VARCHAR(9), "emp_sex" CHAR(1), CONSTRAINT "employees_pkey" PRIMARY KEY("emp_uid") ) WITH OIDS; CREATE TABLE "organization" ( "organization_uid" SERIAL, "organization_name" TEXT NOT NULL, "organization_www_site" TEXT, "organization_email" TEXT, "organization_phone" VARCHAR(7), "organization_fax" VARCHAR(7), CONSTRAINT "organization_pkey" PRIMARY KEY("organization_uid") ) WITH OIDS; CREATE TABLE "employees_post" ( "post_uid" SERIAL, "post_name" TEXT NOT NULL, "post_short_name" TEXT, CONSTRAINT "employees_post_pkey" PRIMARY KEY("post_uid") ) WITH OIDS; CREATE TABLE "organization_employees" ( "organization_uid" INTEGER NOT NULL, "emp_uid" INTEGER NOT NULL, "org_boss" BOOLEAN DEFAULT false NOT NULL, "post_uid" INTEGER, CONSTRAINT "organization_employees_pkey" PRIMARY KEY("organization_uid", "emp_uid"), CONSTRAINT "organization_employees_post_fk" FOREIGN KEY ("post_uid") REFERENCES "employees_post"("post_uid") ON DELETE CASCADE ON UPDATE CASCADE NOT DEFERRABLE, CONSTRAINT "organization_employees_to_employees_fk" FOREIGN KEY ("emp_uid") REFERENCES "employees"("emp_uid") ON DELETE CASCADE ON UPDATE CASCADE NOT DEFERRABLE, CONSTRAINT "organization_employees_to_organization_fk" FOREIGN KEY ("organization_uid") REFERENCES "organization"("organization_uid") ON DELETE CASCADE ON UPDATE CASCADE NOT DEFERRABLE ) WITH OIDS;
Создаю представление:
CREATE VIEW "view1" ( emp_uid, emp_fam, emp_name, emp_otch, emp_was_born, emp_email, emp_icq_num, emp_sex, organization_uid, organization_name, org_boss, post_uid, post_name) AS SELECT employees.emp_uid, employees.emp_fam, employees.emp_name, employees.emp_otch, employees.emp_was_born, employees.emp_email, employees.emp_icq_num, employees.emp_sex, organization_employees.organization_uid, organization.organization_name, organization_employees.org_boss, organization_employees.post_uid, employees_post.post_name FROM employees LEFT JOIN organization_employees ON employees.emp_uid = organization_employees.emp_uid LEFT JOIN organization ON organization_employees.organization_uid = organization.organization_uid LEFT JOIN employees_post ON organization_employees.post_uid = employees_post.post_uid;
Теперь создаю правило на UPDATE:
CREATE RULE "view1_update_rl" AS ON UPDATE TO "view1" DO INSTEAD ( UPDATE employees SET (emp_fam, emp_name, emp_otch, emp_was_born, emp_email, emp_icq_num, emp_sex)= (NEW.emp_fam, NEW.emp_name, NEW.emp_otch, NEW.emp_was_born, NEW.emp_email, NEW.emp_icq_num, NEW.emp_sex) WHERE emp_uid=NEW.emp_uid RETURNING employees.*; UPDATE organization_employees SET (org_boss, post_uid)= (NEW.org_boss, NEW.post_uid) WHERE organization_uid=NEW.organization_uid AND emp_uid=NEW.emp_uid RETURNING organization_employees.*, (SELECT organization_name FROM organization WHERE organization.organization_uid=organization_employees.organization_uid), (SELECT post_name FROM employees_post WHERE employees_post.post_uid = organization_employees.post_uid); );
При компиляции выдаёт: ERROR: RETURNING list has too few entries
правило на INSERT:
CREATE RULE "view1_insert_rl" AS ON INSERT TO "view1" DO INSTEAD ( INSERT INTO employees (emp_uid, emp_fam, emp_name, emp_otch, emp_was_born, emp_email, emp_icq_num, emp_sex) VALUES (NEW.emp_uid, NEW.emp_fam, NEW.emp_name, NEW.emp_otch, NEW.emp_was_born, NEW.emp_email, NEW.emp_icq_num, NEW.emp_sex) RETURNING employees.*; INSERT INTO organization_employees (organization_uid, emp_uid, org_boss, post_uid) VALUES (NEW.organization_uid, NEW.emp_uid, NEW.org_boss, NEW.post_uid) RETURNING organization_employees.*, (SELECT organization.organization_name FROM organization WHERE organization.organization_uid = organization_employees.organization_uid), (SELECT employees_post.post_name FROM employees_post WHERE employees_post.post_uid = organization_employees.post_uid); );
Выдаёт: ERROR: RETURNING list has too few entries
Вопрос!!! Что не так? Почему мало вхождений? А главный вопрос - что такое "RETURNING list"?
И где его можно посмотреть или как вычислить. В мануале по этому поводу я ничего не нашёл.
А если правило создаю так:
CREATE RULE "view1_update_rl" AS ON UPDATE TO "view1" DO INSTEAD ( UPDATE employees SET (emp_fam, emp_name, emp_otc, emp_was_born, emp_email, emp_icq_num, emp_sex)= (NEW.emp_fam, NEW.emp_name, NEW.emp_otch, NEW.emp_was_born, NEW.emp_email, NEW.emp_icq_num, NEW.emp_sex) WHERE emp_uid=NEW.emp_uid RETURNING employees.emp_fam, employees.emp_name, employees.emp_otch, employees.emp_was_born, employees.emp_email, employees.emp_icq_num, employees.emp_sex; UPDATE organization_employees SET (org_boss, post_uid)= (NEW.org_boss, NEW.post_uid) WHERE organization_uid=NEW.organization_uid AND emp_uid=NEW.emp_uid RETURNING organization_employees.org_boss, organization_employees.post_uid,organization_employees.organization_uid,organization_employees.emp_uid, (SELECT organization_name FROM organization WHERE organization.organization_uid=organization_employees.organization_uid), (SELECT post_name FROM employees_post WHERE employees_post.post_uid = organization_employees.post_uid); );
то выдаёт: ERROR: RETURNING list's entry 1 has different type from column "emp_uid"
объясните мне пожалуйста, что я делаю не так. А если всё не правильно, то рад буду выслушать предложения по альтернативной реализации задуманного. Надеюсь, что смысл понятен без лишних объяснений.
Сразу оговорюсь, что смысл конструкций WHERE organization_uid=NEW.organization_uid AND emp_uid=NEW.emp_uid вместо WHERE organization_uid=OLD.organization_uid AND emp_uid=OLD.emp_uid в том чтобы "безусловно" выполнить UPDATE на VIEW1, указав столбцы и значения.
По ходу дела возник ещё один вопрос: почему, если вставка или обновление осуществляется через представление, то дефолтные значения полей не подставляются? Вместо этого пытается вставить NULL и на полях с NOT NULL CONSTRAINT, естественно, выдаёт ошибку!
Вот пример (для вышеуказанных таблиц):
CREATE VIEW "public"."employees_view" ( emp_uid, emp_fam, emp_name, emp_otch, emp_was_born, emp_email, emp_icq_num, emp_sex) AS SELECT employees.emp_uid, employees.emp_fam, employees.emp_name, employees.emp_otch, employees.emp_was_born, employees.emp_email, employees.emp_icq_num, employees.emp_sex FROM employees; CREATE RULE "employees_view_ins" AS ON INSERT TO "public"."employees_view" DO INSTEAD ( INSERT INTO employees (emp_fam, emp_name, emp_otch, emp_was_born, emp_email, emp_icq_num, emp_sex) VALUES (new.emp_fam, new.emp_name, new.emp_otch, new.emp_was_born, new.emp_email, new.emp_icq_num, new.emp_sex) RETURNING employees.emp_uid, employees.emp_fam, employees.emp_name, employees.emp_otch, employees.emp_was_born, employees.emp_email, employees.emp_icq_num, employees.emp_sex; );
Теперь:
INSERT INTO public.employees (emp_fam,emp_name,emp_otch) VALUES ('Иванов',DEFAULT,DEFAULT), (DEFAULT,DEFAULT,DEFAULT) RETURNING *;
emp_uid | emp_fam | emp_name | emp_otch | emp_was_born | emp_email | emp_icq_num | emp_sex
5 | Иванов | н е и з в е с т н о | н е и з в е с т н о | null | null | null | null
6 | н е и з в е с т н о | н е и з в е с т н о | н е и з в е с т н о | null | null | null | null
Пробуем тоже самое на представлении:
INSERT INTO public.employees_view (emp_fam,emp_name,emp_otch) VALUES ('Иванов',DEFAULT,DEFAULT), (DEFAULT,DEFAULT,DEFAULT) RETURNING *;
ERROR: null value in column "emp_name" violates not-null constraint
Объясните мне пожалуйста, почему так? Что происходит в системе правила. Что-то я вообще не догоняю как с ней работать. А ведь, судя по мануалу, это очень полезная и мощная вещь. Хотелось бы овладеть ею в совершенстве. Может это всё недоработки или ошибки разработчиков.
Использую версию 8.3.3 под windows. Буду очень признателен за доходчивые объяснения.
с первым вашим
с первым вашим вопросом все элементарно:
ERROR: RETURNING list has too few entries - список в предложении RETURNING имеет слишком мало полей.
Посмотрите сами - ваше представление имеет 13 полей, а вы возвращаете 6 - из второго update.
ошибку RETURNING list's entry 1 has different type from column "emp_uid" вы, наверное, уже поняли сами.
По поводу дефолта: на сколько я понимаю документацию, дефолтные значения подставляются только в случае отсутствия поля в инструкции на вставку. У вас фактическая вставка происходит в правиле и там присутствуют все поля, поэтому подставляется NULL. Здесь можно выкрутиться триггером.
msr, спасибо за ответ. Разобрался.
Подведу итог на счет правил на INSERT, UPDATE и DELETE, поскольку в мануале этот вопрос почти не освещён, а кому-то это может пригодиться.
Итак, для определения правила на изменение представления (VIEW), объединяющего несколько таблиц, секция RETURNING определяется в завершающей команде (действии) правила и должна содержать ВСЕ поля определённые для этого представления и ИМЕННО В ТОМ ПОРЯДКЕ, в котором они ПЕРЕЧИСЛЕНЫ ДЛЯ ПРЕДСТАВЛЕНИЯ.
Таким образом для примеров, приведенных выше это будет:
Именно в таком порядке всё работает нормально.
А вот по поводу ДЕФОЛТНЫХ значений позволю себе усомниться в предположениях msr'а. В мануале сказано:
5.2. Default Values
A column can be assigned a default value. When a new row is created and no values are specified for some of the columns, those columns will be filled with their respective default values. A data manipulation command can also request explicitly that a column be set to its default value, without having to know what that value is.
Т.е. можно явно задать значение DEFAULT в команде и для указанной колонки оно должно быть подставлено в соответствии со значением определённым для поля по умолчанию. А у меня именно такой случай. Я указываю для вставки или обновления значения DEFAULT, но после обработки в правилах представления, они почему-то становятся NULL.
Буду рад услышать ваши мысли по этому поводу. Или ткните носом в мануал в то место где про это сказано.
Заранее благодарен.
Проблема с DEFAULT для VIEW решена.
Помог gold с форума forum.postgresqlrussia.org. Вот как:
Чтобы сделать дефаулт значение для вьюшки:
после создание вьюшки воспользуемся командой
ALTER TABLE name_view ALTER COLUMN name_col SET DEFAULT ...
Этот способ успешно работает, я сам проверил. Всем спасибо, тема закрыта.
Это я не
Это я не знал.
Самое странное, это значение можно увидеть только в pgAdmin в свойствах конкретного поля представления, другие программы ни под каким видом не отображают это значение.