1

Temat: psql i zmiana separatora pól w pliku wynikowym [+ostatni problem]

PostgreSQL 8.3 na WindowsXP:

Muszę wyciągnąć pewne dane z bazy i wrzucić je do pliku html.
Html jak to html - powinien mieć nagłówek.
Cała reszta poza nagłówkiem raczej nie sprawi problemu (chyba wink)

Ten nagłówek 'robię' zwykłym selectem:
select 'tekst1', 'tekst2',''tekst3'+pole_z_bazy+'tekst4' ,'tekst5' from tabela where id=1

Polecenie zapisane jest w pliku plik.sql, a wywoływane:
psql.exe -h host -f plik.sql -t -F "jakiś_separator" baza user > "plik.html"

Parametr -F według dokumentacji odpowiada za zmianę znaku separatora pól, defaultowo jest znak "|".
Jednak czegokolwiek tam nie wpiszę, to zawsze w wyniku dostaję tekst przedzielony owym "|".
Oczywiście strona w przeglądarce jest wówczas tymi znakami upstrzona...
Co robię źle?
Co wpisać jako wartość -F, aby dostać znak końca wiersza? Albo przynajmniej spację?

Ostatnio edytowany przez grzechu (2012-09-17 15:38:39)

2

Odp: psql i zmiana separatora pól w pliku wynikowym [+ostatni problem]

Są co najmniej trzy sposoby:
1 z PgAdmina zrób szybki raport - plik->Szybki raport... i wyeksportuj do xhtml-a i dalej obrób plik w edytorze

2 Utworz sobie do bazy źródło danych ODBC (wymagany sterownik) i załaduj dane do Excel-a menu Dane->Importuj dane zewnętrzne->Nowa kwerenda bazy danych... następnie zapisz plik jako html

3 Jeśli zależy ci tylko by zapisać dane do tabeli html-a wykonaj swój select analogicznie jak poniższy, najlepiej z PgAdmina następnie wyeksportuj go bez nagłówków i znaków cudzysłowia do pliku tekstowego

select table_txt from (
select '<table>'
|| '<tr>'||'<td>'||'naglowek tabela'||'</td>'
||'<td>'||'naglowek schemat'||'</td>'||'</tr>' as table_txt,1 as kolejnosc
,'' as kol_1,'' as kol_2
union all
SELECT
'<tr>'||'<td>'||tablename||'</td>'
||'<td>'||tableowner||'</td>'||'</tr>' as table_txt,2 as kolejnosc
,tablename as kol_1,tableowner as kol_2
FROM pg_tables
union all
select '</table>' as table_txt,3 as kolejnosc
,'' as kol_1,'' as kol_2
) d
order by kolejnosc ,kol_2,kol_1

Ostatnio edytowany przez c_michal (2012-09-12 22:18:29)

3

Odp: psql i zmiana separatora pól w pliku wynikowym [+ostatni problem]

Dziękuję c_michal za zainteresowanie.

Po Twojej odpowiedzi widzę, że chyba niedostatecznie jasno opisałem swój problem (a wczoraj opis wydawał mi się jasny i przejrzysty wink).

Rzecz polega na tym, że plik html ma być tworzony cyklicznie i automatycznie poprzez zadanie wywoływane za pomocą systemowego Harmonogramu.
Podane w moim poście wyrażenia 'tekst1'--'tekst5' są wartościami stałymi: to linie zawierające wyrażenia typu '<head>', '<title>', '<meta ...>' itp.
Właśnie w znacznikach meta mają być wkomponowane informacje o godzinie aktualizacji i użytkowniku - to nie problem.

Więc sposób 1. odpada, podobnie jak sposób 2 - ze względu na konieczność manualnych kombinacji.

Ale sposób 3. to jest to - zapomniałem na śmierć o operatorze złączenia || hmm
Tak to jest, jak coś robi się raz na ruski rok...
A dodając za każdą linią 'stałego' tekstu złączenie z wartością chr(10) i innych znaków sterujących wychodzi nawet elegancko sformatowany źródłowy plik html smile

Dziękuję!

4

Odp: psql i zmiana separatora pól w pliku wynikowym [+ostatni problem]

id_stanowiska, stanowisko, firma
1, Kierowca, TRANSPORT SAMOCHODOWY
2, Kelner, GRASTRONOMIA U ZENKA

5

Odp: psql i zmiana separatora pól w pliku wynikowym [+ostatni problem]

nie trać wiary twoje zapytanie powinno wyglądać tak (znaczki html dodasz sobie sam):

select s.stanowisko,s.firma,array_to_string(array_agg(w.rodzaj||' / '||w.opis||' / '||w.waga),',')
from stanowiska s
left join wymagania w on w.id_stanowiska=s.id_stanowiska
group by s.stanowisko,s.firma

O ile sprawdziłeś, że funkcja array_agg działa na 8.3 choć z dokumentacji wynika, że nie dlatego dołączam wersję dla WĄTPIĄCYCH

select s.stanowisko,s.firma
,array_to_string(array(select w.rodzaj||' / '||w.opis||' / '||w.waga from wymagania w where w.id_stanowiska=s.id_stanowiska),',')
from stanowiska s



PS
Wielka prośba jak prosisz o pomoc to dołączaj skrypty z danymi i tabelami tak jak poniżej to bardzo ułatwia napisanie odpowiedzi np.
CREATE TABLE stanowiska
(
   id_stanowiska serial primary key
  ,stanowisko varchar(255) NOT NULL
  ,firma varchar(255)
)
WITH (OIDS=FALSE);

INSERT INTO stanowiska(id_stanowiska, stanowisko, firma) VALUES
(1, 'Kierowca', 'TRANSPORT SAMOCHODOWY')
,(2, 'Kelner', 'GRASTRONOMIA U ZENKA')
,(3, 'Polityk', 'Sejm');
CREATE TABLE wymagania
(
   id_wymagania serial primary key
  ,id_stanowiska integer not null
  ,rodzaj varchar(255)
  ,opis varchar(255)
  ,waga varchar(255)
)
WITH (OIDS=FALSE);
INSERT INTO wymagania(id_wymagania, id_stanowiska, rodzaj, opis, waga) VALUES
(1, 1, 'prawo jazdy', 'kat. C', 'konieczne')
,(2, 1, 'prawo jazdy', 'kat. C+E', 'pożądane')
,(3, 1, 'badania', 'psychotesty', 'konieczne')
,(4, 2, 'język obcy', 'angielski', 'pożądane')
,(5, 2, 'badania', 'minimum sanitarne', 'konieczne');

6

Odp: psql i zmiana separatora pól w pliku wynikowym [+ostatni problem]

7

Odp: psql i zmiana separatora pól w pliku wynikowym [+ostatni problem]

8

Odp: psql i zmiana separatora pól w pliku wynikowym [+ostatni problem]

9

Odp: psql i zmiana separatora pól w pliku wynikowym [+ostatni problem]

Fajnie działa. Rozumiem, że generujesz z postgresql cały kod html strony, ile to się wykonuje?

A tak z ciekawości zapytam jaką masz wersję postgresa, że na górze piszesz cytuje "Z uwagi na ograniczenia wynikające z wykorzystywanej bazy danych strona kodowana jest w standardzie Windows-1250. Przepraszamy.".

Nie pamiętam dokładnie ale chyba wystarczy na czas wykonywanie tego skryptu zmienić kodowanie o ile pamiętam robi się to tak (musisz sobie zaeksperymentować):
SET CLIENT_ENCODING TO 'UTF8'; , powrót do ustawień pierwotnych to RESET CLIENT_ENCODING;

10

Odp: psql i zmiana separatora pól w pliku wynikowym [+ostatni problem]

psql -h localhost -f oferty.sql -t _baza_ _user_ > Ofertypracy.htm

11

Odp: psql i zmiana separatora pól w pliku wynikowym [+ostatni problem]

Ponieważ moje 'epokowe' wink dzieło działa, to w wolnych chwilach zabrałem się za... no, optymalizacja to za dużo powiedziane... za upiększenie kodu.

Problem 1:
Mamy pole numeric(9,2) o nazwie "staz"
Wartość w nim przechowywana zapisywana przed przecinkiem to lata (0-99), po przecinku to miesiące (0-11), np:
5,10 = 5 lat 10 miesięcy
2,00 = 2 lata
0,07 = 7 miesięcy
0,00 = wartość domyślna czyli użytkownik nic nie wpisał

Chciałbym wyświetlać te wartości 'opisowo' i bez wiodących zer, np.:
5,10 = "lat: 5, mies.: 10"
2,00 = "lat: 2"
0,07 = "mies.: 7"
0,00 = "-"

Celowo z 'lat' i 'mies.' przed wartościami, bo jak się przymierzyłem do odpowiedniego odmieniania (1 rok, 2 lata, 10 lat, 1 miesiąc, 2 miesiące, 10 miesięcy etc.) to się przeraziłem wink

Czy jest jakaś bardziej elegancka konstrukcja niż moje poniższe wypociny:

CASE
    WHEN    staz >= 1 AND MOD(staz,1) > 0
    THEN
        'lat: '
        || ltrim(split_part(to_char(staz::real,'00D00'), ',', 1), ' 0')
        ||
        ', mies.: '
        || ltrim(split_part(to_char(staz::real,'00D00'), ',', 2), ' 0')

    WHEN    staz >= 1 AND MOD(staz,1) = 0
    THEN
        'lat: '
        || ltrim(split_part(to_char(staz::real,'00D00'), ',', 1), ' 0')

    WHEN    staz > 0 AND staz < 1
    THEN
        'mies.: '
        || ltrim(split_part(to_char(staz::real,'00D00'), ',', 2), ' 0')

    ELSE
        '-'
END

???
Ponieważ są 4 pola tego typu i podobnego przeznaczenia, to ten przydługawy fragment kodu występuje w zapytaniu czterokrotnie - mało fajnie wygląda (ale działa!), może dałoby się go skrócić...?


Problem 2:
Mamy tabelę z adresami.
W niej są między innymi pola adres_opisowy, kod_pocztowy, poczta, miejscowosc, ulica, nr_domu, nr_lokalu.
Pole adres_opisowy to złączone i odpowiednio sformatowane przez aplikację wartości pozostałych pól.
Pola ulica, nr_domu i nr_lokalu są typu character varying, o długości odpowiednio 65, 10 i 10.

Aplikacja zezwala (to jest efekt zamierzony i poprawny), aby użytkownik wypełnił tylko pola kod_pocztowy, poczta i miejscowosc. Wówczas adres opisowy przyjmuje wartość np. "Berdyczów, 99-999 Berdyczów".
Wyświetlanie takiego adresu jako adresu do kontaktu jest bezsensowne, więc chciałbym to warunkowo pominąć.

Ale...
Jak wiadomo, są miejscowości bez ulic. Więc użytkownik wprowadza pola kod_pocztowy, poczta, miejscowosc i numer_domu (+ew. numer lokalu).
Wówczas adres opisowy przyjmuje wartość "Berdyczów 25, 99-999 Berdyczów" i jest jak najbardziej wartościowym adresem do kontaktu.

Mój warunek wygląda tak:

CASE
    WHEN
        (SELECT SAD.ulica
            FROM adres SAD
            WHERE 
            SAD.id = PSO.id
            AND
            relacja = 'xxxxxx') IS NOT NULL
        OR
        (SELECT SAD.nr_domu
            FROM sy_adres SAD
            WHERE 
            SAD.id = PSO.id
            AND
            relacja = 'xxxxxx') IS NOT NULL
        OR
        (SELECT SAD.nr_lokalu
            FROM sy_adres SAD
            WHERE 
            SAD.id = PSO.id
            AND
            relacja = 'xxxxxx') IS NOT NULL

    THEN
        ...pierwszy raz wykonujemy na początku podzapytania, aby sprawdzić w połączeniu z innymi warunkami dotyczącymi innych tabel czy tworzyć nowy wiersz
        ...drugi raz wykonujemy w dalszej części podzapytania, aby wyświetlić adres

    ELSE
        ''
END

Takich pól typu character varying związanych z adresem jest więcej: telefon, telefon komórkowy, fax, skrytka pocztowa (i chyba jeszcze coś...).
Aby obsłużyć je wszystkie,  to kod, na dodatek wywoływany dwukrotnie, zaczyna się monstrualnie rozrastać...
Da się to w jakoś bardziej 'zwarty' sposób napisać?

Uwaga: PostgreSQL 8.3, nie mogę wykonywać żadnych działań ingerujących w bazę danych i jej konfigurację!

12

Odp: psql i zmiana separatora pól w pliku wynikowym [+ostatni problem]

ad pola staz proponuje takie rozwiazanie
select
coalesce(nullif(coalesce('lat: '||nullif(trunc(staz),0)||' ','')||coalesce('mies.: '||nullif((staz-trunc(staz))*100,0)::int,''),''),'-') as staz2
from
(select 0.0::numeric(9,2) as staz union all
select 5::numeric(9,2) as staz union all
select 5.01::numeric(9,2) as staz union all
select 200.1::numeric(9,2) as staz union all
select 0.01::numeric(9,2) as staz union all
select null::numeric(9,2) as staz
) d

ad formatowanie adresu wykorzystaj funkcje coalesce i to, że postgresql zwraca null jeśli złączysz ciąg z null-em powinno to wyglądać tak:
coalesce (adres_pełny, adres_bez_ulicy_z_ kodem,adres_bez_ulicy_i_kodu,'') as adres

Ostatnio edytowany przez c_michal (2012-10-13 01:25:53)