Aug 20 2008

Małe a cieszy - czyli do czego może się przydać COUNT(DISTINCT …)

Tag: MySQLbirkin @ 01:14

O rety.. Przeszedłem długą drogę, JOIN.. GROUP BY.. FROM (SELECT …) i oczywiście i tak nie chciało działać.. A potrzebowałem pewnej prostej rzeczy, którą opiszę na prostym przykładzie: w bazie trzymam n-zamówień, zaś każde zamówienie może być podzielone na x-części, przy czym każda ta część ma swój status (np.: zgłoszone, zapłacone, wysłane…). Problem: w jaki sposób wyciągnąć jednym zapytaniem wszystkie zamówienia, przy czym chce również wiedzieć czy poszczególne zamówienia posiadają części o różnych statusach. Nic nie działało i tak o to trafiłem w tajemnicze COUNT(DISTINCT), i okazało się, że właśnie ta funkcja robi wszystkie skomplikowane rzeczy, które ja próbowałem tworzyć w ciągu pół godziny :)

Przykład zastosowania:


Jul 10 2008

Presja czasu czyli złośliwości timestampa w MySQL

Tag: MySQLmyszaq @ 09:07

Niedawno natrafiłem na dosyć osobliwy problem podczas definiowania kolumn w jednej z tabeli. Okazuje się, że wszystkim dobrze znany (mam taką nadzieję:)) typ TIMESTAMP rządzi się swoimi własnymi prawami i potrafi w pewnych sytuacjach namieszać dość konkretnie. O co chodzi? Wyobraźmy sobie, że chcemy stworzyć w tabeli ‘czasy’ 2 pola:

updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
edited_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP

Niby wszystko jest w porządku, jednak pojawia się komunikat:

Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause.

Niestety twórcy MySQL, chociaż opisali taką sytuację, nie raczyli napisać dlaczego tak się dzieje. Próba zastąpienia CURRENT_TIMESTAMP przez NOW() tudzież LOCALTIME() też nic nie daje, jako że są to wartości równoznaczne tej pierwszej. Warto przy tym wspomnieć, że typ TIMESTAMP daje dość duże możliwości, jeżeli chcemy dać polu wartość domyślną i/lub automatycznie uaktualniać przy użyciu nieszczęsnego CURRENT_TIMESTAMP. Możemy użyć go np. do czegoś takiego:
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
lub
updated_at TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP.

Wspaniale, tylko że dotyczy to pierwszej kolumny. Próba użycia CURRENT_TIMESTAMP w kolejnej kolumnie zakończy się powyższym błędem.
Co więc zrobić, gdy chcemy koniecznie mieć możliwość zdefiniowania defaultowej wartości dla obu takich pól czasowych (o aktualizacji nie wspominając)? Możemy zdefiniować pola następująco:

updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
edited_at TIMESTAMP NOT NULL DEFAULT '2008-01-01 00:00:00'

Zamiast jakiejś daty w polu DEFAULT możemy umieścić 0 lub nawet NULL, ale w tym ostatnim przypadku trzeba również pamiętać o zadeklarowaniu pola jako NULL. Takie pośrednie rozwiązania zapewne jednak nas nie satysfakcjonują - data w drugim polu stanie się szybko przestarzała a wartość zerowa do niczego się raczej nie przyda. Niestety tylko takie wyjście proponuje
manual.
Najlepiej jest zatem zapewnić samemu wstawianie odpowiednich wartości. I tu można się bardzo zdziwić - nie trzeba bowiem pisać
INSERT INTO czasy VALUES (NOW(), CURRENT_TIMESTAMP);

Jak to? Definiujemy tabelę ‘czasy’ w ten sposób:
create table czasy (
created_at timestamp NOT NULL default '0000-00-00 00:00:00',
updated_at timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
);

Następnie wykonujemy zapytanie
INSERT INTO czasy(created_at,updated_at) VALUES (NULL,NULL);

Jaki będzie efekt? Obie kolumny będą zawierać tą samą wartość - CURRENT_TIMESTAMP :) Dzieje się tak dlatego, że przypisanie kolumnie zdefiniowanej jako NOT NULL wartości NULL zamieni ją na aktualny czas.
A powiadają, że szczęśliwi czasu nie liczą…


Jun 19 2008

Wykorzystanie ceny brutto w rachunkach aplikacji

Tag: MySQL, PHPbirkin @ 01:24

W naszych serwisach bardzo często pojawia się zarządzanie cenami różnych produktów (wyliczanie cen, stawek VAT oraz innych skomplikowanych obliczeń). W większości przypadków podstawą jest cena netto, natomiast problem pojawia się, kiedy klient zażyczy aby podstawą była cena brutto!
Continue reading “Wykorzystanie ceny brutto w rachunkach aplikacji”


Apr 30 2008

MySQL i kolumny typu SET

Tag: MySQLbuka @ 11:25

Wszyscy znamy sql’owy SET jako np. określenie zestawu danych wrzucanych w odpowiednie kolumny. Ale SET jako typ kolumny, okazuje się nie wszystkim jest znany. Najprościej mówiąc jest to “trochę inny ENUM” :) A czym się różni i do czego go stosować możecie przeczytać dalej…
Continue reading “MySQL i kolumny typu SET”


Apr 23 2008

Commit MySQLowych transakcji

Tag: MySQLdooshek @ 12:54

Jak dobrze wiemy transakcje czasami się przydają. Wprawdzie używamy ich rzadko ale niekiedy są idealnym rozwiązaniem służącym głównie upraszczaniu kodu (nie musimy stosować wielu warunków) i zapewnienia integralności zapisywanych do bazy danych.

Kilkukrotnie jednak mieliśmy problem ze stwierdzeniem co dzieje się jeśli program zakończy swoje działanie po wykonaniu SQLa BEGIN (czy też START TRANSACTION). Przeprowadziłem mały inwestygejszyn i chciałbym to tutaj raz na zawsze wyjaśnić :)

Wygląda to tak, że dopóki nie wykonamy SQLa COMMIT dopóty zmiany nie zostaną zachowane w bazie. W praktyce nie trzeba nawet robić ROLLBACK - jeśli do końca danego połączenia nie wykonamy komita, to dane się nie zapiszą.

Poniżej przykład:

Wykonanie tego przykładu i zakończenie połączenia nie spowoduje wstawienia rekordu do tabeli sessions.

natomiast to jak najbardziej zadziała :) Być może są jakieś wyjątki od tych reguł - ja ich nie znalazłem.

Uwaga! W ramach tego samego połączenia - jeśli nie zrobimy ROLLBACK to dane będą “dostępne” czyli wykonanie:

spowoduje zwrócenie wstawionego wcześniej rekordu! Żeby tego uniknąć należy wykonać ROLLBACK (np. w przypadku kiedy jednak nie chcemy aby dane te zostały zapisane do bazy)

Uwaga! Zakończenie połączenia następuje również wtedy kiedy pojawi się jakiś błąd SQL (nasz framework w takim momencie kończy działanie z błędem lub pokazuje stosowny komunikat) więc w przypadku błędu SQL dane pomiędzy BEGIN…COMMIT nie zostaną zapisane (bo zabraknie COMMIT)


Apr 02 2008

Testowanie szybkości wykonywania SQLi

Tag: MySQLdooshek @ 09:12

MySQLZapewne większość wie, że MySQL posiada wbudowany mechanizm cacheowania SQLi. Sprawdza się w miarę dobrze i w większości przypadków jego wyłączenie nie jest zalecane.

My programiści, potrzebujemy jednak do testów prędkości wykonywania SQLi (szczególnie tych operujących na większej liczbie danych) realnych prędkości.

Continue reading “Testowanie szybkości wykonywania SQLi”


Mar 12 2008

Sposób na wyciągnięcie losowego rekordu z tablicy MySql

Tag: MySQLwoojo @ 12:09

Przeglądając z rana to co zaproponował mi
google alerts na temat MySqla natknąłem się na ciekawy
artykuł na temat wyciągania losowych rekordów z tablic tej właśnie bazy danych.
Nie będę przepisywał treści zawartej w tym artykule, chciałem tylko przedstawić swoje własne wyniki uzyskane podczas testowania tej metody. Badania przeprowadziłem na tablicy
InnoDB z 135k elementów. Wyciągając losowy element w ‘tradycyjny’ sposób, czyli:

zajęło to 60 sek. Wartość niedopuszczalna aby używać tego np. na stronie www.

Wykorzystując pomysł zaproponowany na tym blogu i wykonując zapytanie:

wynik otrzymuje już po około 30ms, a więc wzrost prędkości 1000 krotny!!!


Mar 10 2008

Krótko o funkcjach w MySQL

Tag: MySQLradmen @ 10:48

Podobnie jak PHP, C++, Java i masa innych języków programowania ma funkcje. Jak wiadomo mogą one posłużyć do wielu różnych rzeczy. W MySQL można je wykorzystać aby zwiększyć bezpieczeństwo. Zapisana funkcja/procedura może być bez problemu wywołana z poziomu PHP, ponieważ wystarczy wysłać zapytanie do bazy będące wywołaniem funkcji.
W dalszej części postaram się nieco opisać sposób tworzenia, oraz wykonywania funkcji.

Continue reading “Krótko o funkcjach w MySQL”