PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

PostgreSQL - wstawiaj wiersze na podstawie wyboru z innej tabeli i aktualizuj FK w tej tabeli za pomocą nowo wstawionych wierszy

Istnieje kilka sposobów rozwiązania tego problemu.

1. tymczasowo dodaj kolumnę

Jak wspomnieli inni, najprostszym sposobem jest tymczasowe dodanie kolumny reminder_id do dateset . Wypełnij go oryginalnymi IDs z reminder stół. Użyj go, aby dołączyć do reminder z dateset stół. Upuść kolumnę tymczasową.

2. kiedy start jest wyjątkowy

Jeśli wartości start kolumna jest unikalna, można to zrobić bez dodatkowej kolumny, łącząc reminder tabela z dateset tabela na start kolumna.

INSERT INTO dateset (start)
SELECT start FROM reminder;

WITH
CTE_Joined
AS
(
    SELECT
        reminder.id AS reminder_id
        ,reminder.dateset_id AS old_dateset_id
        ,dateset.id AS new_dateset_id
    FROM
        reminder
        INNER JOIN dateset ON dateset.start = reminder.start
)
UPDATE CTE_Joined
SET old_dateset_id = new_dateset_id
;

3. kiedy start nie jest wyjątkowy

Nawet w tym przypadku można to zrobić bez kolumny tymczasowej. Główna idea jest następująca. Spójrzmy na ten przykład:

Mamy dwa wiersze w reminder z tym samym start wartość i identyfikatory 3 i 7:

reminder
id    start         dateset_id
3     2015-01-01    NULL
7     2015-01-01    NULL

Po wstawieniu ich do dateset , zostaną wygenerowane nowe identyfikatory, na przykład 1 i 2:

dateset
id    start
1     2015-01-01
2     2015-01-01

Tak naprawdę nie ma znaczenia, jak połączymy te dwa wiersze. Efektem końcowym może być

reminder
id    start         dateset_id
3     2015-01-01    1
7     2015-01-01    2

lub

reminder
id    start         dateset_id
3     2015-01-01    2
7     2015-01-01    1

Oba te warianty są poprawne. Co prowadzi nas do następującego rozwiązania.

Po prostu wstaw najpierw wszystkie wiersze.

INSERT INTO dateset (start)
SELECT start FROM reminder;

Dopasuj/dołącz do dwóch stołów na start kolumna wiedząc, że nie jest unikalna. „Uczyń to” unikalnym, dodając ROW_NUMBER i łączenie dwiema kolumnami. Możliwe jest skrócenie zapytania, ale każdy krok wyraźnie opisałem:

WITH
CTE_reminder_rn
AS
(
    SELECT
        id
        ,start
        ,dateset_id
        ,ROW_NUMBER() OVER (PARTITION BY start ORDER BY id) AS rn
    FROM reminder
)
,CTE_dateset_rn
AS
(
    SELECT
        id
        ,start
        ,ROW_NUMBER() OVER (PARTITION BY start ORDER BY id) AS rn
    FROM dateset
)
,CTE_Joined
AS
(
    SELECT
        CTE_reminder_rn.id AS reminder_id
        ,CTE_reminder_rn.dateset_id AS old_dateset_id
        ,CTE_dateset_rn.id AS new_dateset_id
    FROM
        CTE_reminder_rn
        INNER JOIN CTE_dateset_rn ON 
            CTE_dateset_rn.start = CTE_reminder_rn.start AND
            CTE_dateset_rn.rn = CTE_reminder_rn.rn
)
UPDATE CTE_Joined
SET old_dateset_id = new_dateset_id
;

Mam nadzieję, że z kodu jasno wynika, co robi, zwłaszcza gdy porównasz ją z prostszą wersją bez ROW_NUMBER . Oczywiście złożone rozwiązanie będzie działać, nawet jeśli start jest wyjątkowy, ale nie jest tak wydajny, jak proste rozwiązanie.

To rozwiązanie zakłada, że ​​dateset jest pusty przed tym procesem.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak w prosty i efektywny sposób wyszukiwać zagnieżdżone relacje w SQL?

  2. Dołączanie (wypychanie) i usuwanie z tablicy JSON w PostgreSQL 9.5+

  3. Porównanie typów kolumn baz danych w MySQL, PostgreSQL i SQLite? (Mapowanie krzyżowe)

  4. Wybierz pierwszy rekord, jeśli żaden nie pasuje

  5. Nxlog im_dbi nie działa