خو که دواړه د عملي کولو هڅه وکړي CREATE TEMPORARY TABLE xنو دواړه به دا په نورمال ډول ترسره کړي، او هرڅوک به ترلاسه کړي ستاسو کاپي میزونه او د دوی تر مینځ به هیڅ شی مشترک نه وي.
"ځان ویجاړول" کله چې منحل کیږي
کله چې پیوستون وتړل شي، ټول لنډمهاله میزونه په اتوماتيک ډول حذف کیږي، نو په لاسي ډول DROP TABLE x هیڅ معنی نلري پرته ...
که تاسو له لارې کار کوئ pgbouncer د راکړې ورکړې په حالت کې، بیا ډیټابیس باور ته دوام ورکوي چې دا اړیکه لاهم فعاله ده ، او پدې کې دا لنډمهاله جدول لاهم شتون لري.
له همدې امله، د بیا جوړولو هڅه کول، د پی جی باونسر ته د مختلف ارتباط څخه، د تېروتنې پایله به وي. مګر دا د کارولو له لارې مخنیوی کیدی شي CREATE TEMPORARY TABLE IF NOT EXISTS x.
ریښتیا ، دا غوره ده چې دا په هرصورت ونه کړئ ، ځکه چې بیا تاسو کولی شئ هلته "ناڅاپه" د "مخکیني مالک" څخه پاتې ډیټا ومومئ. پرځای یې ، دا خورا ښه دی چې لارښود ولولئ او وګورئ چې د میز رامینځته کولو پرمهال دا اضافه کول ممکن دي ON COMMIT DROP - دا دی، کله چې معامله بشپړه شي، جدول به په اوتومات ډول حذف شي.
او اوس - په مرهم کې مچۍ. په حقیقت کی، په PostgreSQL کې ټول لیکونه دوه ځله پیښیږي - لومړی په WAL کې، بیا په جدول / شاخصونو کې. دا ټول د ACID مالتړ لپاره ترسره کیږي او تر منځ د معلوماتو لید سم کړي COMMITمغز او ROLLBACK'ناسمه راکړه ورکړه.
مګر موږ دې ته اړتیا نلرو! موږ ټوله پروسه لرو یا دا په بشپړ ډول بریالی و یا دا نه و.. دا مهمه نده چې څومره منځمهاله لیږدونه به وي - موږ د "مینځ څخه پروسې ته دوام ورکولو" سره علاقه نه لرو، په ځانګړې توګه کله چې دا روښانه نده چې دا چیرته وه.
په ON COMMIT DROP ما دمخه پورته لیکلي ، دا رامینځته کوي DROP TABLE، مګر سره ON COMMIT DELETE ROWS وضعیت ډیر په زړه پوری دی - دا دلته رامینځته شوی TRUNCATE TABLE.
CREATE TEMPORARY TABLE import_table(
LIKE target_table
);
له هغه ځایه چې تاسو کولی شئ پدې جدول کې ډیری ډیټا تولید کړئ ، نو د دې له لارې لټون به هیڅکله ګړندی نه وي. مګر د دې لپاره دودیز حل شتون لري - شاخصونه! او، هو، یو لنډمهاله جدول هم شاخصونه لري.
څرنګه چې، ډیری وختونه، اړین شاخصونه د هدف جدول شاخصونو سره سمون لري، تاسو کولی شئ په ساده ډول ولیکئ LIKE target_table INCLUDING INDEXES.
که تاسو هم اړتیا لرئ DEFAULT- ارزښتونه (د مثال په توګه، د لومړني کلیدي ارزښتونو ډکولو لپاره)، تاسو کولی شئ وکاروئ LIKE target_table INCLUDING DEFAULTS. یا په ساده ډول - LIKE target_table INCLUDING ALL - کاپي ډیفالټ، شاخصونه، خنډونه، ...
مګر دلته تاسو اړتیا لرئ پوه شئ چې که تاسو جوړ کړی د شاخصونو سره سمدلاسه جدول وارد کړئ ، بیا به ډیټا ډیر وخت ونیسيکه تاسو لومړی هرڅه ډک کړئ، او یوازې بیا شاخصونه پورته کړئ - وګورئ چې دا څنګه د مثال په توګه ترسره کوي pg_dump.
د سایمن ریګز څخه د WIP پیچ شتون درلود چې د جوړولو وړاندیز یې وکړ ALTER- د فایل په کچه د میز بدن بدلولو لپاره عملیات، پرته له دې چې احصایې او FK لمس کړي، مګر کورم راټول نه کړي.
ړنګول، تازه کول، داخلول
نو، موږ د دریو عملیاتو غیر بلاک کولو اختیار باندې بسنه کوو. نږدې درې ... دا څنګه په خورا اغیزمنه توګه ترسره کړئ؟
-- все делаем в рамках транзакции, чтобы никто не видел "промежуточных" состояний
BEGIN;
-- создаем временную таблицу с импортируемыми данными
CREATE TEMPORARY TABLE tmp(
LIKE dst INCLUDING INDEXES -- по образу и подобию, вместе с индексами
) ON COMMIT DROP; -- за рамками транзакции она нам не нужна
-- быстро-быстро вливаем новый образ через COPY
COPY tmp FROM STDIN;
-- ...
-- .
-- удаляем отсутствующие
DELETE FROM
dst D
USING
dst X
LEFT JOIN
tmp Y
USING(pk1, pk2) -- поля первичного ключа
WHERE
(D.pk1, D.pk2) = (X.pk1, X.pk2) AND
Y IS NOT DISTINCT FROM NULL; -- "антиджойн"
-- обновляем оставшиеся
UPDATE
dst D
SET
(f1, f2, f3) = (T.f1, T.f2, T.f3)
FROM
tmp T
WHERE
(D.pk1, D.pk2) = (T.pk1, T.pk2) AND
(D.f1, D.f2, D.f3) IS DISTINCT FROM (T.f1, T.f2, T.f3); -- незачем обновлять совпадающие
-- вставляем отсутствующие
INSERT INTO
dst
SELECT
T.*
FROM
tmp T
LEFT JOIN
dst D
USING(pk1, pk2)
WHERE
D IS NOT DISTINCT FROM NULL;
COMMIT;
3.2. د پروسس وروسته واردول
په ورته KLADR کې، ټول بدل شوي ریکارډونه باید اضافي د پوسټ پروسس کولو له لارې پرمخ وړل شي - نورمال شوي، کلیدي ټکي روښانه شوي، او اړین جوړښتونو ته کم شوي. مګر تاسو څنګه پوهیږئ - په حقیقت کې څه بدل شویپرته له دې چې د همغږي کوډ پیچلي کړي، په مثالي توګه پرته له دې چې دا په بشپړه توګه لمس کړي؟
-- целевые таблицы
CREATE TABLE kladr(...);
CREATE TABLE kladr_house(...);
-- таблицы с историей изменений
CREATE TABLE kladr$log(
ro kladr, -- тут лежат целые образы записей старой/новой
rn kladr
);
CREATE TABLE kladr_house$log(
ro kladr_house,
rn kladr_house
);
-- общая функция логирования изменений
CREATE OR REPLACE FUNCTION diff$log() RETURNS trigger AS $$
DECLARE
dst varchar = TG_TABLE_NAME || '$log';
stmt text = '';
BEGIN
-- проверяем необходимость логгирования при обновлении записи
IF TG_OP = 'UPDATE' THEN
IF NEW IS NOT DISTINCT FROM OLD THEN
RETURN NEW;
END IF;
END IF;
-- создаем запись лога
stmt = 'INSERT INTO ' || dst::text || '(ro,rn)VALUES(';
CASE TG_OP
WHEN 'INSERT' THEN
EXECUTE stmt || 'NULL,$1)' USING NEW;
WHEN 'UPDATE' THEN
EXECUTE stmt || '$1,$2)' USING OLD, NEW;
WHEN 'DELETE' THEN
EXECUTE stmt || '$1,NULL)' USING OLD;
END CASE;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER log
AFTER INSERT OR UPDATE OR DELETE
ON kladr
FOR EACH ROW
EXECUTE PROCEDURE diff$log();
CREATE TRIGGER log
AFTER INSERT OR UPDATE OR DELETE
ON kladr_house
FOR EACH ROW
EXECUTE PROCEDURE diff$log();
او بیا موږ په آرامۍ سره ټول هغه بدلونونه چې موږ ورته اړتیا لرو د لاګ جدولونو څخه استخراج کوو او د اضافي هینډلرونو له لارې یې چلوو.
CREATE TEMPORARY TABLE client_import AS
SELECT DISTINCT ON(client_inn)
-- можно просто SELECT DISTINCT, если данные заведомо непротиворечивы
client_inn inn
, client_name "name"
FROM
invoice_import;
د دې لپاره چې حسابونه په سمه توګه د پیرودونکي IDs سره شریک کړو، موږ باید لومړی دا پیژندونکي پیدا کړو یا پیدا کړو. راځئ چې د دوی لاندې ساحې اضافه کړو:
ALTER TABLE invoice_import ADD COLUMN client_id integer;
ALTER TABLE client_import ADD COLUMN client_id integer;
-- проставляем в таблице импорта ID уже существующих записей
UPDATE
client_import T
SET
client_id = D.client_id
FROM
client D
WHERE
T.inn = D.inn; -- unique key
-- вставляем отсутствовавшие записи и проставляем их ID
WITH ins AS (
INSERT INTO client(
inn
, name
)
SELECT
inn
, name
FROM
client_import
WHERE
client_id IS NULL -- если ID не проставился
RETURNING *
)
UPDATE
client_import T
SET
client_id = D.client_id
FROM
ins D
WHERE
T.inn = D.inn; -- unique key
-- проставляем ID клиентов у записей счетов
UPDATE
invoice_import T
SET
client_id = D.client_id
FROM
client_import D
WHERE
T.client_inn = D.inn; -- прикладной ключ
په حقیقت کې، هرڅه په کې دي invoice_import اوس موږ د تماس ساحه ډکه کړه client_id، د کوم سره چې موږ به انوائس داخل کړو.