🔧 ETL & Tabele Zewnętrzne
SQL*Loader, Data Pump, ORGANIZATION EXTERNAL
- →ETL = Extract → Transform → Load. Najpierw pobierasz dane ze źródeł, potem czyścisz/przekształcasz, na końcu ładujesz do hurtowni. ELT (Cloud/Big Data) = odwrotna kolejność — załaduj surowe dane najpierw, przekształć potem w bazie.
- →Wykrywanie zmian (Change Detection): Snapshots = pełna kopia co N godzin (kosztowne). Activity Logs = czytaj redo log/binlog (efektywne, ale skomplikowane). Triggers/Difference Tables = trigger zapisuje zmiany do tabeli delta. Cooperative Sources = źródło ma kolumnę 'last_modified' lub flagę zmiany.
- →SQL*Loader dyrektywy ładowania:
APPEND= dołącz wiersze (tabela może być niepusta).REPLACE= usuń wszystko (DELETE) + wstaw nowe.TRUNCATE= szybsze niż REPLACE (TRUNCATE zamiast DELETE).INSERT= tabela MUSI być pusta, inaczej błąd. - →Pliki wyjściowe SQL*Loader:
.log= log całej operacji (ile załadowano, ile odrzucono)..bad= wiersze odrzucone przez błędy danych lub naruszenie constraintów..dsc(discard) = wiersze nie pasujące do żadnej klauzuli WHEN. - →ORACLE_LOADER = tylko SELECT (read-only). Plik CSV jest widoczny jako tabela, ale nie możesz INSERT/UPDATE/DELETE. ORACLE_DATAPUMP = możesz zarówno pisać (CTAS tworzy plik) jak i czytać. Format binarny Oracle — nieczytelny bez Oracle.
- →Plik tabeli zewnętrznej musi być na SERWERZE BAZY DANYCH, nie na komputerze klienta. DIRECTORY to ścieżka na serwerze. Jeśli pliku nie ma → ORA-29913 przy SELECT.
- →Data Pump wymaga obiektu DIRECTORY — nie możesz podać bezpośredniej ścieżki jako stringa. Najpierw:
CREATE DIRECTORY dump_dir AS '/ścieżka/', potemGRANT READ, WRITE ON DIRECTORY dump_dir TO użytkownik.
ETL — teoria
ETL = Extract → Transform → Load. Proces przenoszenia danych ze źródeł do hurtowni/docelowej bazy.
| Faza | Co robi | Kluczowe zagadnienia |
|---|---|---|
| Extract | Pobierz dane ze źródeł | Wybór źródeł, wykrywanie zmian |
| Transform | Oczyść, przekształć, wzbogać | Deduplikacja, ujednolicenie formatów, mapowanie semantyczne |
| Load | Załaduj do docelowej bazy | Pełne zastąpienie (full) vs przyrostowe (incremental) |
Extract — wykrywanie zmian (Change Detection)
| Metoda | Opis | Wady |
|---|---|---|
| Snapshots | Pełna kopia źródła — porównaj z poprzednią wersją | Kosztowne dla dużych tabel |
| Activity logs | Czytaj logi transakcyjne bazy (redo log, binlog) | Format specyficzny dla DBMS |
| Difference tables / triggers | Trigger zapisuje zmienione wiersze do tabeli delta | Narzut na DML; ingerencja w schemat źródła |
| Cooperative sources | Źródło samo informuje o zmianach (timestamp, flaga) | Wymaga współpracy z właścicielem źródła |
Transform — czyszczenie i przekształcanie
| Krok | Przykład |
|---|---|
| Deduplikacja | Usuń duplikaty wierszy (ROW_NUMBER + WHERE rn=1) |
| Normalizacja formatu | Ujednolicenie dat (DD-MM-YYYY → YYYY-MM-DD), kodowania |
| Mapowanie semantyczne | "M"/"F" → "Male"/"Female"; kod kraju → nazwa |
| Wzbogacanie | Lookup do tabeli referencyjnej, obliczenie pól pochodnych |
| Walidacja | Odrzucenie wierszy z brakującymi kluczami lub wartościami null |
Load — typy ładowania
| Typ | Opis | Kiedy |
|---|---|---|
| Full (pełne) | TRUNCATE + INSERT — całkowite zastąpienie zawartości tabeli | Mała tabela lub brak możliwości wykrycia zmian |
| Incremental (przyrostowe) | Dołącz tylko nowe/zmienione wiersze (INSERT/MERGE) | Duże tabele, znane daty zmian |
Porównanie narzędzi
| Narzędzie | Kierunek | Format danych | Użycie |
|---|---|---|---|
| SQL*Loader | Plik → Oracle | CSV, delimited, fixed-width | Masowe ładowanie z plików tekstowych |
| Data Pump EXPDP | Oracle → plik | Binarny Oracle (.dmp) | Eksport schematów/tabel/całej bazy |
| Data Pump IMPDP | Plik → Oracle | Binarny Oracle (.dmp) | Import z pliku EXPDP |
| Tabele zewnętrzne | Plik ↔ Oracle | CSV lub binarny Oracle | Czytaj/pisz pliki jak tabele SQL |
SQL*Loader — plik kontrolny
SQL*Loader ładuje dane z pliku tekstowego do tabeli Oracle. Konfiguracja w pliku .ctl.
LOAD DATA
INFILE 'pracownicy.csv' -- plik z danymi
APPEND -- dołącz do istniejących wierszy
INTO TABLE hr.employees_staging
FIELDS TERMINATED BY ',' -- separator pól
OPTIONALLY ENCLOSED BY '"' -- opcjonalne cudzysłowy
TRAILING NULLCOLS -- brakujące kolumny na końcu = NULL
(
employee_id INTEGER EXTERNAL,
first_name CHAR(50),
last_name CHAR(50),
email CHAR(100),
salary DECIMAL EXTERNAL
)Dyrektywy LOAD DATA
| Dyrektywa | Zachowanie |
|---|---|
INSERT | Tabela musi być pusta (domyślne) |
APPEND | Dołącz do istniejących danych |
REPLACE | DELETE FROM tabela, potem INSERT |
TRUNCATE | TRUNCATE TABLE, potem INSERT (szybsze niż REPLACE) |
SQL*Loader — ładowanie pozycyjne (stała szerokość kolumn)
Gdy plik nie ma separatorów — kolumny mają stałą pozycję (POSITION).
LOAD DATA
INFILE 'employees_fixed.dat'
BADFILE 'bad_rows.bad' -- wiersze odrzucone → ten plik
APPEND
INTO TABLE hr.employees_staging
(
employee_id POSITION(1:6) INTEGER EXTERNAL,
first_name POSITION(7:26) CHAR,
last_name POSITION(27:46) CHAR,
salary POSITION(47:54) DECIMAL EXTERNAL
)Rozszerzone opcje linii komend SQL*Loader
| Opcja | Opis |
|---|---|
control= | Plik kontrolny (.ctl) |
log= | Plik logu operacji |
bad= | Plik z wierszami odrzuconymi (błędy formatu/constrainty) |
data= | Nadpisuje INFILE z pliku kontrolnego |
discard= | Plik z wierszami nie pasującymi do żadnego WHEN |
discardmax= | Maks. liczba odrzuconych wierszy zanim zatrzyma się ładowanie |
skip= | Pomiń N pierwszych wierszy pliku (np. nagłówek) |
load= | Załaduj maksymalnie N wierszy |
rows= | Liczba wierszy na jeden COMMIT (domyślnie 64) |
direct=TRUE | Direct Path Load — szybszy, omija redo log |
Klauzula WHEN — ładowanie warunkowe
LOAD DATA
INFILE 'dane.csv'
INTO TABLE high_salary_emp WHEN (salary > '10000')
FIELDS TERMINATED BY ','
(employee_id, first_name, salary)
INTO TABLE low_salary_emp WHEN (salary <= '10000')
FIELDS TERMINATED BY ','
(employee_id, first_name, salary)Uruchomienie SQL*Loader z linii komend
sqlldr userid=hr/password@orcl control=load.ctl log=load.log bad=bad.txt
-- Najważniejsze parametry:
-- control= plik kontrolny
-- log= plik z logiem operacji
-- bad= wiersze odrzucone (błędy) → zapisane do pliku .bad
-- discard= wiersze nie pasujące do żadnej klauzuli WHEN → plik .dsc
-- rows= liczba wierszy na jeden COMMIT (domyślnie 64)
-- direct= TRUE = Direct Path Load (szybszy, omija redo log)SQL*Loader — tryby ładowania
| Tryb | Metoda | Szybkość | Constrainty |
|---|---|---|---|
| Conventional Path | Standardowy INSERT | Wolniejszy | Sprawdzane na bieżąco |
| Direct Path | Bezpośredni zapis na bloki | Szybszy | Sprawdzane po załadowaniu |
Data Pump — EXPDP / IMPDP
-- Eksport całego schematu HR:
expdp hr/password@orcl DIRECTORY=DATA_PUMP_DIR DUMPFILE=hr_backup.dmp LOGFILE=expdp_hr.log SCHEMAS=HR
-- Eksport konkretnych tabel:
expdp hr/password@orcl DIRECTORY=DATA_PUMP_DIR DUMPFILE=tables.dmp TABLES=HR.EMPLOYEES,HR.DEPARTMENTS
-- Eksport całej bazy (wymaga DBA):
expdp system/password FULL=Y DUMPFILE=full_backup.dmp DIRECTORY=DATA_PUMP_DIR-- Import schematu:
impdp hr/password@orcl DIRECTORY=DATA_PUMP_DIR DUMPFILE=hr_backup.dmp SCHEMAS=HR
-- Import z remapowaniem schematu (HR → HR_TEST):
impdp system/password DIRECTORY=DATA_PUMP_DIR DUMPFILE=hr_backup.dmp REMAP_SCHEMA=HR:HR_TEST
-- Import tylko wybranych tabel:
impdp hr/password DIRECTORY=DATA_PUMP_DIR DUMPFILE=hr_backup.dmp TABLES=HR.EMPLOYEESDIRECTORY — obiekt Oracle dla ścieżki
-- Data Pump wymaga obiektu DIRECTORY (nie bezpośredniej ścieżki):
CREATE DIRECTORY data_pump_dir AS '/oracle/backup/';
GRANT READ, WRITE ON DIRECTORY data_pump_dir TO hr;
-- Sprawdzenie istniejących direktorios:
SELECT directory_name, directory_path FROM dba_directories;Tabele zewnętrzne — ORACLE_LOADER
Pozwala czytać pliki CSV jak tabele Oracle — bez ładowania danych do bazy. Dane "wirtualne".
CREATE TABLE ext_employees (
employee_id NUMBER,
first_name VARCHAR2(50),
last_name VARCHAR2(50),
salary NUMBER
)
ORGANIZATION EXTERNAL (
TYPE ORACLE_LOADER -- sterownik: czytanie pliku tekstowego
DEFAULT DIRECTORY ext_data_dir -- katalog z plikiem
ACCESS PARAMETERS (
RECORDS DELIMITED BY NEWLINE
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
MISSING FIELD VALUES ARE NULL
(employee_id, first_name, last_name, salary)
)
LOCATION ('employees.csv') -- nazwa pliku (w katalogu DIRECTORY)
)
REJECT LIMIT UNLIMITED; -- nie przerywaj przy błędach w wierszachTabela zewnętrzna — PARALLEL i opcje logowania
CREATE TABLE ext_employees_parallel (
employee_id NUMBER,
first_name VARCHAR2(50),
last_name VARCHAR2(50),
salary NUMBER
)
ORGANIZATION EXTERNAL (
TYPE ORACLE_LOADER
DEFAULT DIRECTORY ext_data_dir
ACCESS PARAMETERS (
RECORDS DELIMITED BY NEWLINE
NOBADFILE -- nie twórz pliku .bad (domyślnie tworzony)
NOLOGFILE -- nie twórz pliku logu (domyślnie tworzony)
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
MISSING FIELD VALUES ARE NULL
(employee_id, first_name, last_name, salary)
)
LOCATION ('employees.csv')
)
PARALLEL 4 -- czytaj plik równolegle (4 procesy)
REJECT LIMIT UNLIMITED;ALTER TABLE — modyfikacja tabeli zewnętrznej
Tabelę zewnętrzną można modyfikować bez usuwania i tworzenia od nowa.
-- Zmiana ACCESS PARAMETERS (nowy separator):
ALTER TABLE ext_employees ACCESS PARAMETERS (
RECORDS DELIMITED BY NEWLINE
FIELDS TERMINATED BY ';'
MISSING FIELD VALUES ARE NULL
(employee_id, first_name, last_name, salary)
);
-- Zmiana domyślnego katalogu:
ALTER TABLE ext_employees DEFAULT DIRECTORY new_data_dir;
-- Zmiana pliku źródłowego:
ALTER TABLE ext_employees LOCATION ('employees_2024.csv');
-- Zmiana katalogu i pliku razem:
ALTER TABLE ext_employees DEFAULT DIRECTORY new_dir
LOCATION ('new_file.csv');
-- Dodanie kolumny (jak zwykła ALTER TABLE):
ALTER TABLE ext_employees ADD (department_id NUMBER);
-- Modyfikacja kolumny:
ALTER TABLE ext_employees MODIFY (first_name VARCHAR2(100));
-- Usunięcie kolumny:
ALTER TABLE ext_employees DROP COLUMN department_id;Nie można UPDATE/INSERT/DELETE — tabela zewnętrzna ORACLE_LOADER jest tylko do odczytu.
Plik musi być na serwerze bazy danych — nie na komputerze klienta.
Tabele zewnętrzne — ORACLE_DATAPUMP
Pozwala zapisywać wyniki zapytań do binarnych plików Oracle i czytać je jak tabelę. Przenaszalne między bazami.
-- Zapis do pliku binarnego:
CREATE TABLE ext_emp_dump
ORGANIZATION EXTERNAL (
TYPE ORACLE_DATAPUMP
DEFAULT DIRECTORY ext_data_dir
LOCATION ('emp_dump.dmp')
)
AS SELECT employee_id, first_name, last_name, salary
FROM hr.employees;
-- Odczyt z pliku:
SELECT * FROM ext_emp_dump WHERE salary > 5000;ORACLE_DATAPUMP — binarny format Oracle, można zarówno pisać (CTAS) jak i czytać
Tabele zewnętrzne są read-only dla zapytań SQL — nie możesz INSERT/UPDATE/DELETE do pliku przez ORACLE_LOADER.
Pytania egzaminacyjne
Do pliku .bad (BADFILE) w SQL*Loader trafiają wiersze...
Co się stanie gdy użyjesz SQL*Loader z dyrektywą INSERT a tabela ma już dane?
Tabela zewnętrzna z ORACLE_LOADER — które operacje są dozwolone?
Dlaczego Data Pump wymaga obiektu DIRECTORY zamiast bezpośredniej ścieżki?
INSERT INTO ext_employees (employee_id, first_name)
VALUES (999, 'Test');Ćwiczenia
Ćwiczenie 1 — Plik kontrolny SQL*Loader
Napisz plik kontrolny SQL*Loader do załadowania pliku departments.csv (pola: department_id, department_name, location_id oddzielone przecinkami) do tabeli departments_staging. Użyj APPEND, obsługę cudzysłowów i brakujących kolumn.
Ćwiczenie 2 — Tabela zewnętrzna ORACLE_LOADER
Utwórz tabelę zewnętrzną ext_departments odczytującą plik departments.csv (department_id NUMBER, department_name VARCHAR2(100), location_id NUMBER). Plik jest w katalogu EXT_DIR. Ustaw REJECT LIMIT UNLIMITED.
Ćwiczenie 3 — Data Pump: eksport i import schematu
Napisz polecenia: (1) utwórz obiekt DIRECTORY wskazujący na /oracle/dumps/, (2) wyeksportuj schemat HR do pliku hr_export.dmp, (3) zaimportuj go do schematu HR_BACKUP (remap).