nowości w postgresie 8.2 – … aliasy w update/delete

to akurat poprawka malutka, ale jak dla mnie po prostu bogosławiona.

jak może wiecie polecenie update (a także delete) może aktualizować dane z pomocą innej tabeli. przykładowo:

# CREATE TABLE statusy (id serial PRIMARY KEY, kod TEXT);
NOTICE:  CREATE TABLE will CREATE implicit SEQUENCE "statusy_id_seq" FOR serial COLUMN "statusy.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will CREATE implicit INDEX "statusy_pkey" FOR TABLE "statusy"
CREATE TABLE
# INSERT INTO statusy (kod) VALUES ('new'), ('open'), ('resolved'), ('rejected');
INSERT 0 4
# CREATE TABLE zgloszenia (id serial, temat TEXT, status_id INT NOT NULL REFERENCES statusy (id));
NOTICE:  CREATE TABLE will CREATE implicit SEQUENCE "zgloszenia_id_seq" FOR serial COLUMN "zgloszenia.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will CREATE implicit INDEX "zgloszenia_pkey" FOR TABLE "zgloszenia"
CREATE TABLE
# INSERT INTO zgloszenia (temat, status_id) VALUES ('a', 1), ('b', 2), ('c', 3), ('d', 4);
INSERT 0 4
# ALTER TABLE zgloszenia ADD COLUMN STATUS TEXT;
ALTER TABLE
# UPDATE zgloszenia SET STATUS = s.kod FROM statusy s WHERE s.id = status_id;
UPDATE 4
# SELECT * FROM zgloszenia;
id temat status_id status

(4 rows)

fajne. ale – jeśli nazwy kolumn się powtarzają (np. ja mam w każdej tabeli pole “id" będące primary key'em) to trzeba postgresowi powiedzieć o które pole dokładnie mi chodzi. póki używam id z tabel dołączanych to nie problem – w “FROM" mogę podać alias na tabelę (w przykładzie powyżej: “s"). ale już tabeli którą aktualizuję – nie mogłem aliasować.

teraz już mogę. dzięki czemu nawet przy aktualizowaniu tabeli o długiej nazwie i używaniu w warunkach jej pól nie będę miał kosmicznie długiego sql'a – trudnego do czytania i poprawiania.

wygląda to na przykład tak:

UPDATE wynagrodzenia_pracownikow s SET pensje = SUM(p.wynagrodzenie) FROM wynagrodzenia_pracownikow p WHERE p.przelozony_id = s.id;

ten sam mechanizm działa w przypadku delete'ów join-ujących tabele w celu stworzenia odpowiednich warunków.

nowości w postgresie 8.2 – … values

post zaległy od wczoraj 🙂

w czasie projektowania i proponowania nowości do postgresa 8.2 padła idea by zacząć obsługiwać inserty wstawiające wiele rekordów. tak jak ma np. mysql:

INSERT INTO `tabele` (`pole1`, `pole2`) VALUES (1,1),(2,4),(2,7);

jak zawsze – panowie z core-teamu stwierdzili, że skoro robią już coś takiego, to może to trochę podkręcić.

wyszło z tego zupełnie nowe polecenie sql'owe: VALUES.

dzięki temu mogli zachować kompatybilność z standardowymi sql'ami, ale także wykorzystać to dla innych zastosowań.

zacznijmy od podstaw:

# CREATE TABLE x (id serial PRIMARY KEY, p_a TEXT, p_b TEXT);
NOTICE:  CREATE TABLE will CREATE implicit SEQUENCE "x_id_seq" FOR serial COLUMN "x.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will CREATE implicit INDEX "x_pkey" FOR TABLE "x"
CREATE TABLE
# INSERT INTO x (p_a, p_b) VALUES ('standardowa', 'metoda');
INSERT 0 1
# INSERT INTO x (p_a, p_b) VALUES ('nowsza', 'metoda'), ('drugi', 'rekord'), ('następne', 'rekordy');
INSERT 0 3
# SELECT * FROM x;
id p_a p_b

(4 rows)

fajne. tylko po co? no cóż. zrobiłem mały test. zrobiłem tabelkę:

# CREATE TABLE x (id serial PRIMARY KEY, liczba INT4);

i wstawiałem do niej dane (100000 kolejnych liczb) na kilka sposobów:

  • copy x (liczba) from stdin;
  • 100000 insertów – każdy po jednym rekordzie
  • 100000 insertów – każdy po jednym rekordzie (ale z użyciem prepare i execute)
  • 10000 insertów – każdy po dziesięć rekordów
  • 10000 insertów – każdy po dziesięć rekordów (ale z użyciem prepare i execute)
  • 5000 insertów – każdy po dwadzieścia rekordów
  • 5000 insertów – każdy po dwadzieścia rekordów (ale z użyciem prepare i execute)

wyniki:

  • copy: 0m1.045s
  • insert (1): 1m5.473s
  • insert + prepare (1): 1m3.483s
  • insert (10): 0m8.500s
  • insert + prepare (10): 0m7.552s
  • insert (20): 0m4.065s
  • insert + prepare (20): 0m3.656s

dla chętnych do powtórzenia testów/obejrzenia – skrypty oczywiście są dostępne.

graficznie wygląda to jeszcze bardziej interesująco:

chart-values.pngjak widac przyspieszenie insertów jest znaczne. czy to wszystko? nie!

values można wykorzystać wszędzie tam gdzie potrzebujemy wielu rekordów. przykładowe zastosowanie – wyobraźmy sobie, że mamy pole typu int z zapisanymi statusami. statusów jest ledwie kilka. nie warto dla nich robić oddzielnej tabeli. ale jednak chcielibyśmy móc je w jakiś sposób odczytać z bazy … proszę:

# CREATE TABLE x (id serial PRIMARY KEY, liczba INT4);
NOTICE:  CREATE TABLE will CREATE implicit SEQUENCE "x_id_seq" FOR serial COLUMN "x.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will CREATE implicit INDEX "x_pkey" FOR TABLE "x"
CREATE TABLE
# INSERT INTO x (liczba) VALUES (1), (2), (3), (2);
INSERT 0 4
# SELECT
x.id, x.liczba, k.kod
FROM x
JOIN (VALUES (1, 'closed'), (2, 'new'), (3, 'open')) AS k (id, kod) ON x.liczba = k.id
;
id liczba kod

(4 rows)

oczywiście powyższy efekt można uzyskać używając (CASE WHEN … END), ale to rozwiązanie jest krótsze i mocno czytelniejsze.

zwracam też uwagę na to, że w oparciu o VALUES można zdefiniować widok:

# CREATE VIEW statusy AS SELECT * FROM (VALUES (1, 'closed'), (2, 'new'), (3, 'open')) AS k (id, kod);
CREATE VIEW
# SELECT * FROM statusy;
id kod

(3 rows)

co jeszcze można z tym zrobić? sporo. pobawcie się sami i zastanówcie do czego można tego użyć.

woda na marsie. niedawno!

to jest wiadomość mocno istotna – zdjęcia z “mars global survivor"‘a (obecnie już nie działającej sondy) wskazują, że na marsie była płynna, powierzchniowa woda. i to nie dawno – ledwie kilka lat temu. jak dla mnie jest to hit, bo wszystkie informacje o potencjalnym życiu na marsie są “niedawno, ledwie sprzed kilkunastu tysięcy lat" – a tu – proszę, kilka lat temu tam była woda.

oznacza to, że szanse na to, że mars jest zamieszkiwalny mocno rosną. a to może przyspieszyć program wysłania sondy załogowej. człowiek na innej planecie? YEAH!

komórki nie powodują raka

duńscy naukowcy przeprowadzili największe na świecie badania. w badaniu wzięło udział ponad 420000 osób. trwało – w niektórych przypadkach 20 lat!.

przeanalizowano ilość zapadnięć na raka (rozmaite rodzaje) wśród monitorowanej grupy. wyniki – ilośc zachorowań na raka była wręcz niższa niż można by się spodziewać.

oczywiście zwolennicy teorii spiskowych i tak będą wiedzieć lepiej czy powtarzać mity o ugotowaniu jajka przy pomocy komórki, ale może wynik tego badania uspokoi część ludzi którzy co prawda nie wierzyli w rakotwórczość, ale też nie mieli pewności czy wszystko jest ok 🙂

nowy chipset klasy home/game

zasadniczo pecety jako takie mało mnie wzruszają.

ale przeczytałem dziś o czymć naprawdę fajnym i mającym ciekawe zastosowania.

jakiś czas temu (miesiąc, coś koło tego), amd wypuścił serię procesorów 4×4 (quad-fx). bynajmniej nie sa to procesory 4-rdzeniowe. jest to układ dwu rdzeniowy (jeśli chodzi o cpu), ale z zintegrowanym procesorem graficznym (od, kupionego trochę wcześniej, ati).

całość jest podobno tak sobie wydajna, ale ma jakies tam swoje plusy.

teraz nvidia wypuściła chipset – takie coś na czym są oparte płyty główne – pod te procesory. i tu mi kopara opadła. wykaz funkcji chipsetu (to co będzie miała faktycznie płyta to pewnie tylko część z tego co chipset potrafi, bo w końcu nie wszystko jest każdemu potrzebne):

  • obsługa do 4 kart graficznych
  • do 8 monitorów
  • 12 połączeń sata, pracujących z prędkościa 3gbps
  • 4 niezależne interfejsy gigabit ethernet
  • 4 dyski ide
  • 20 portów usb
  • do 10 gniazd pci
  • system dźwiękowy 7.1
  • kontroler raid

potwór.

całość jest adresowana do graczy, ale muszę przyznać, że mimo, że nie gram to płyta mi się podoba. czemu? proste – obsługa 4 kart graficznych oznacza, że płyta ma 4 złącza pcie – a w nie można włożyć też coś innego – np. kontrolery raid 🙂

do tego – w standardzie 12 portów usb, oznacza, że bezproblemowo (no, prawie, jeszcze trzeba zasilacz) można podłączyć sporo dysków twardych i zrobić z tego ładnie działającego, mocno zintegrowanego potworka  dyskowego 🙂

ibm korumpuje rosyjski zus?

dowiedziałem się właśnie, że rosyjskie (moskiewskie) biura ibma zostały przeszukane przez uzbrojone oddziały milicji w związku z podejrzeniami o korupcję w związku z zakupami sprzętu przez ichniejszy zus.

“zus" kupił około 1000 serwerów i około 50000 pecetów.

podobno (taka jest wersja podana jako przyczyna nalotu) ibm celowo zawyżał faktury – po to by nadwyżki kasy oddać pod stołem decydentom.

zasadniczo news z tego żaden. u nas tak jest non stop. ale czy przy firmach wielkości ibm'a też?

może to jakiś idealizm, ale wydaje mi się, że firmy tej wielkości jak ibm (zwłaszcza firmy które wycofują się ze sprzedaży pecetów) nie muszą/nie chcą przekupywać klientów.

w związku z tym zastanawiam się czy chodzi tu o:

  • “kiedy wleziesz między wrony musisz krakać jak i one" – czyli – ibm w rosji dostosowuje sie do tamtejszych “standardów"?
  • jakaś gra mojego ulubionego kagiebisty putina?

wersja pierwsza jest mocno prawdopodobna, ale z drugiej strony (choć to może moja paranoja) nigdy nie wiadomo co strzeli do głowy batiuszce i jakie cele realizuje. hmm .. ciekawe co dalej z tego wyjdzie.

nowości w postgresie 8.2 – … returning

dziś pierwszy odcinek o zmianach w postgresie 8.2. tematem odcinka są zapytania “… returning".

do zapytań modyfikujących dane – INSERT INTO, UPDATE, DELETE FROM zostało dodane rozszerzenie “RETURNING".

składnia wygląda następująco:

  • INSERT INTO tabelka (pola) VALUES (costam) RETURNING wyrażenie;
  • UPDATE tabelka SET pole = X WHERE cośtam RETURNING wyrażenie;
  • DELETE FROM tabelka WHERE cośtam RETURNING wyrażenie;

przykłady użycia dla INSERT:

# CREATE TABLE x (id serial PRIMARY KEY, ble INT4);
NOTICE:  CREATE TABLE will CREATE implicit SEQUENCE "x_id_seq" FOR serial COLUMN "x.id"
NOTICE:  CREATE TABLE / PRIMARY KEY will CREATE implicit INDEX "x_pkey" FOR TABLE "x"
CREATE TABLE
# INSERT INTO x (ble) VALUES ('123') returning id;
id
----
1
(1 ROW)
INSERT 0 1
# INSERT INTO x (ble) VALUES ('123') returning id, ble + 123;
id | ?COLUMN?
----+----------
2 |      246
(1 ROW)
INSERT 0 1
# INSERT INTO x (ble) VALUES ('123') returning *;
id | ble
----+-----
3 | 123
(1 ROW)
INSERT 0 1
# INSERT INTO x (ble) VALUES ('123') returning *, now(), (SELECT COUNT(*) FROM pg_class);
id | ble |              now              | ?COLUMN?
----+-----+-------------------------------+----------
4 | 123 | 2006-12-07 22:52:24.573777+01 |      209
(1 ROW)
INSERT 0 1
# SELECT * FROM x;
id | ble
----+-----
1 | 123
2 | 123
3 | 123
4 | 123
(4 ROWS)
# INSERT INTO x (ble) SELECT ble + 2 FROM x returning *;
id | ble
----+-----
5 | 125
6 | 125
7 | 125
8 | 125
(4 ROWS)
INSERT 0 4

miłe, czyż nie? głównym celem jest możliwość automatycznego pobierania wartości typu id – nadawanych z sekwencji. ale zadziała to także zwracając dane modyfikowane przez triggery.

to co jest po “RETURNING" musi być zgodne formatowo z tym co jest w standardowym select'cie między SELECT a FROM.

przykłady użycia dla UPDATE:

# UPDATE x SET ble = ble * 2 WHERE id % 2 = 0 returning *;
id | ble
----+-----
2 | 246
4 | 246
6 | 250
8 | 250
(4 ROWS)
UPDATE 4

zwracam uwagę na to, że returning zwraca nowe wartości! czyli tak po triggerowemu mówiąc: retyrning * oznacza return NEW; a nie return OLD;!

przykłady użycia dla DELETE:

# DELETE FROM x WHERE id % 2 = 1 returning *;
id | ble
----+-----
1 | 123
3 | 123
5 | 125
7 | 125
(4 ROWS)
DELETE 4

jak widać składnia wszędzie jest podobna, miła łatwa i prosta. a do tego niesie sporo ułatwień. mnie osobiście cieszy INSERT … returning id; bo załatwia mi w piękny sposób odpowiadanie ludziom pytającym o id, i reagującym nerwowo na sugestie: select currval() : “ale czy jak dwa połączenia wstawią rekordy …" 🙂

problemy gastryczne przyczyna przymusowego lądowania.

wewnętrzny lot z dallas do waszyngtonu przymusowo lądował gdy kilkoro pasażerów zgłosiło załodze w czasie lotu, że czują zapach siarki.
pilot wylądował w nashville, pasażerowie zostali wyprowadzeni. i zaczęła się jazda 🙂 przeszukania, rewizje, psy szukające bomb. całość zajęła 3 godziny w czasie których ustalono, że zapach pochodził z zapalonej przez jedną z pasażerek zapałki.

pasażerka została w nashville, reszta pasażerów została spakowana z powrotem do samolotu i lot się dokończył.

jak o tym przeczytałem jedna rzecz mi nie pasowała – po co zapalać zapałkę? w samolotach raczej nie wolno palić.

i co się okazało? okazało się, że kobieta zapaliła zapałkę aby jej zapachem ukryć fakt iż puściła bąka. po prostu super.