Czy chcesz, aby plik wynikowy był na serwerze czy na kliencie?
Po stronie serwera
Jeśli chcesz czegoś łatwego do ponownego użycia lub zautomatyzowania, możesz użyć wbudowanego polecenia KOPIUJ w Postgresql. np.
Copy (Select * From foo) To '/tmp/test.csv' With CSV DELIMITER ',' HEADER;
To podejście działa w całości na zdalnym serwerze - nie może pisać na lokalnym komputerze. Musi być również uruchamiany jako "superużytkownik" Postgresa (zwykle nazywany "root"), ponieważ Postgres nie może powstrzymać go przed robieniem nieprzyjemnych rzeczy z lokalnym systemem plików tej maszyny.
W rzeczywistości nie oznacza to, że musisz być połączony jako superużytkownik (automatyzacja byłaby zagrożeniem bezpieczeństwa innego rodzaju), ponieważ możesz użyć SECURITY DEFINER
opcja CREATE FUNCTION
stworzyć funkcję, która działa tak, jakbyś był superużytkownikiem .
Kluczową częścią jest to, że twoja funkcja ma wykonywać dodatkowe sprawdzenia, a nie tylko omijać zabezpieczenia - więc możesz napisać funkcję, która eksportuje dokładnie te dane, których potrzebujesz, lub możesz napisać coś, co akceptuje różne opcje, o ile są one spotkać ścisłą białą listę. Musisz sprawdzić dwie rzeczy:
- Które pliki czy użytkownik powinien mieć możliwość odczytu/zapisu na dysku? Może to być na przykład konkretny katalog, a nazwa pliku może wymagać odpowiedniego przedrostka lub rozszerzenia.
- Które stoły czy użytkownik powinien mieć możliwość odczytu/zapisu w bazie danych? Zwykle jest to zdefiniowane przez
GRANT
s w bazie danych, ale funkcja działa teraz jako administrator, więc tabele, które normalnie byłyby „poza granicami”, będą w pełni dostępne. Prawdopodobnie nie chcesz, aby ktoś wywołał Twoją funkcję i dodał wiersze na końcu tabeli „użytkownicy”…
Napisałem post na blogu rozszerzający to podejście, w tym kilka przykładów funkcji, które eksportują (lub importują) pliki i tabele spełniające surowe warunki.
Strona klienta
Innym podejściem jest obsługa plików po stronie klienta , czyli w Twojej aplikacji lub skrypcie. Serwer Postgres nie musi wiedzieć, do jakiego pliku kopiujesz, po prostu wypluwa dane, a klient gdzieś je umieszcza.
Podstawową składnią tego jest COPY TO STDOUT
polecenie, a narzędzia graficzne, takie jak pgAdmin, opakują je w ładnym oknie dialogowym.
psql
klient wiersza poleceń ma specjalne „metapolecenie” o nazwie \copy
, który przyjmuje te same opcje, co "prawdziwa" COPY
, ale jest uruchamiany w kliencie:
\copy (Select * From foo) To '/tmp/test.csv' With CSV
Zauważ, że nie ma zakończenia ;
, ponieważ metapolecenia są kończone znakiem nowej linii, w przeciwieństwie do poleceń SQL.
Z dokumentów:
Nie myl COPY z instrukcją psql \copy. \copy wywołuje KOPIUJ Z STDIN lub KOPIUJ NA STDOUT, a następnie pobiera/przechowuje dane w pliku dostępnym dla klienta psql. Dlatego dostępność plików i prawa dostępu zależą od klienta, a nie od serwera, gdy używana jest \copy.
Twój język programowania aplikacji może obsługuje również wypychanie lub pobieranie danych, ale generalnie nie można użyć COPY FROM STDIN
/TO STDOUT
w ramach standardowej instrukcji SQL, ponieważ nie ma możliwości połączenia strumienia wejścia/wyjścia. Obsługa PostgreSQL w PHP (nie PDO) zawiera bardzo podstawowe pg_copy_from
i pg_copy_to
funkcje, które kopiują do/z tablicy PHP, co może nie być wydajne w przypadku dużych zestawów danych.