Potrzeba rejestrowania błędnych wierszy podczas masowego importowania pojawiła się niemal natychmiast po wprowadzeniu automatycznych załadunków dużych ilości danych do baz danych. Tradycyjnie, każde naruszenie ograniczeń (np. naruszenia typów danych, constraints) prowadziło do przerwania całego procesu importu nawet z powodu jednego błędnego wiersza — w wyniku czego traciły się zarówno poprawne, jak i niepoprawne rekordy.
Problem polega na tym, aby nie tylko załadować maksymalną ilość poprawnych danych, ale także pozostawić audyt i szczegółowy opis błędów do dalszej ręcznej obróbki, a nie po prostu "cofnąć wszystko".
Rozwiązanie: Dla niektórych DBMS (np. PostgreSQL, SQL Server z SSIS, Oracle z narzędziami EXTERNAL TABLES) istnieją mechanizmy ładowania z podziałem na błędne wiersze. Dla uniwersalnego sposobu — wykorzystuje się tabele stagingowe i walidację po ładowaniu poprzez OUTER JOIN i NOT EXISTS, a także dołączone "tabele logów", do których ręcznie zapisuje się problemy.
Przykład kodu:
-- 1. Ładujemy wszystko do tymczasowej tabeli stagingowej BULK INSERT staging_payments FROM 'payments.csv' WITH (...) -- 2. Filtrujemy poprawne INSERT INTO payments (id, amount, ...) SELECT id, amount, ... FROM staging_payments WHERE amount > 0 AND status IN ('approved', 'pending'); -- 3. Logujemy błędne wiersze do osobnej tabeli INSERT INTO import_errors (row_data, error_desc) SELECT *, 'Niepoprawny status lub ujemna suma' FROM staging_payments WHERE amount <= 0 OR status NOT IN ('approved', 'pending');
Kluczowe cechy:
Czy można zrealizować wszystko przez ON ERROR RESUME NEXT wewnątrz SQL?
Standard SQL nie zawiera takiej konstrukcji dla masowego operatorowego importu. W większości przypadków raport o błędach generowany jest w zewnętrznych narzędziach lub w tabelach logów, jak opisano powyżej.
Czy można użyć transakcji do wycofania tylko błędnych wierszy?
Wycofanie transakcji powoduje wycofanie wszystkich wierszy naraz (atomiczność). Częściowe zapisywanie możliwe jest tylko podczas ładowania najpierw do tabeli stagingowej, po czym ręcznie robi się commit udanych i loguje nieudane wiersze.
Dlaczego nieefektywne jest łapanie każdego błędu INSERT przez TRY/CATCH w pętli dla każdego wiersza?
Sekwencyjne przetwarzanie milionów wierszy poprzez pojedyncze INSERT + TRY/CATCH prowadzi do katastrofalnego spadku wydajności w porównaniu do zbiorowego lub BULK INSERT + weryfikacja po załadowaniu.
Firma ładowała dziesiątki tysięcy wierszy przez skrypt INSERT, a przy błędzie klucza unikalnego wycofywana była cała partia. Powodowało to przestoje i utratę danych.
Plusy:
Wykorzystanie tabeli stagingowej, logowania błędów i podziału danych wejściowych na kategorie "walidne/nieważne" pozwoliło przyspieszyć import, przechowywać i automatycznie analizować odrzuty.
Plusy: