Kategorie szkoleń | Egzaminy | Kontakt
  • 1
  • 1
  • 55

Mam chyba banalne pytanie:

Niech istnieje plik ze skryptem SQL:

DECLARE c1 CURSOR FOR
    SELECT col1, col2, ...., col30, ...., colN FROM tableA WHERE <conditions>;

LOAD FROM c1 OF CURSOR
    REPLACE INTO tableB;

COMMIT;

Skrypt  uruchamiam używając CLP (db2 -tvf <script_name>).

Jak napisać procedurę składowaną, która wykona tę samą pracę? 

Tomasz_Stereńczak
  • Zapytał
  • @ Tomasz_Stereńczak | 11.08.2016
    • lider
    • 3
    • 0
    • 0

Odpowiedź (1)

  • 3

Panie Tomaszu.

Banalne nie jest, ale rozwiązanie jest łatwiejsze niż w poprzednim problemie. ;-)
Polecenie LOAD nie jest instrukcją języka SQL tylko poleceniem administracyjnym DB2 (podobnie jak np. BACKUP).
W związku z tym, można go użyć w skrypcie dla CLP, ale nie można go użyć bezpośrednio w procedurze składowanej napisanej w SQL.
Rozwiązaniem jest wykorzystanie procedury administracyjnej: SYSPROC.ADMIN_CMD.
Jednakże jedynym parametrem przekazywanym do tej procedury jest łańcuch znakowy zawierający treść polecenia do wykonania. Nie da się w ten sposób przekazać nazwy wcześniej zadeklarowanego kursora. Szczęśliwie twórcy tego rozwiązania przewidzieli taką sytuację.
Sztuczka polega na tym, że składnia polecenia LOAD jest inna dla przypadku użycia w ADMIN_CMD niż w zwykłym poleceniu CLP. Ta składnia (dla ADMIN_CMD) dopuszcza umieszczenie polecenia SELECT definiującego kursor bezpośrednio w poleceniu LOAD, co nie jest dopuszczalne w składni LOAD dla CLP.
Przykład dla ADMIN_CMD:

LOAD FROM (SELECT * FROM T1) OF CURSOR INSERT INTO T2

Reasumując, przedstawiony problem można rozwiązać przez wywołanie w procedurze składowanej następującego polecenia:

CALL SYSPROC.ADMIN_CMD
('LOAD FROM
 (SELECT col1, col2, ...., col30, ...., colN FROM tableA WHERE <conditions>)
 OF CURSOR
 REPLACE INTO tableB');

Warto rozważyć użycie klauzuli NONRECOVERABLE, ale z zastrzeżeniami jej znaczenia i konsekwencjami użycia na pewno będzie skutkować najszybszym wykonaniem.

Można też rozdzielić usuwanie zawartości tabeli od jej załadowania. Zamiast klauzuli REPLACE użyć wcześniej osobno polecenia DELETE, a w LOAD wówczas będzie tylko INSERT.
Oczywiście wszystkie elementy działania "zwykłego" polecenia LOAD mają tutaj odpowiednie zastosowanie. Proszę pamiętać o ewentualnym BACKUP i RUNSTATS.

Dokumentacja do poczytania:

https://www.ibm.com/support/knowledgecenter/en/SSEPGG_10.5.0/com.ibm.db2.luw.sql.rtn.doc/doc/r0012547.html

https://www.ibm.com/support/knowledgecenter/en/SSEPGG_10.5.0/com.ibm.db2.luw.sql.rtn.doc/doc/r0023577.html

Pozdrawiam.
Marek Raczyński.

  • Odpowiedział
  • @ | 11.08.2016
  • TRENER MODERATOR ALTKOM AKADEMII