//DEVGURU

Author's entries:

Powtórki z SQL’a – Część II – GROUP_CONCAT i HAVING

Thursday, December 27th, 2007

Zaledwie wczoraj pisałem o GROUP_CONCAT() w SQL, o możliwości dodatkowej filtracji zwracanych rekordów przez HAVING aby stwierdzić, że odwoływanie się do konkretnej kolumny zamiast do wyniku funkcji agregacyjnej w HAVING (co jest możliwe w MySQL ale nie do końca zgodne ze specyfikacją SQL) nie działa tak jak powinno.

Wracając do przykładu z poprzedniego wpisu:

SELECT entries.*, channels.channel_name AS chname,
           GROUP_CONCAT(channels.channel_name) AS channel_names
FROM entry_channel
INNER JOIN entries ON entry_channel.entry_id = entries.entry_id
INNER JOIN channels ON entry_channel.channel_id = channels.channel_id
GROUP BY entry_channel.entry_id
HAVING chname = 'krzaki'
ORDER BY entries.created_at DESC
LIMIT 25

Wynik:

entry_id body chname channel_names
1 jakiś fajny wpisik krzaki krzaki,swieta

Otrzymaliśmy 1 rekord gdyż wiersz zawierający string ‘krzaki’ pochodził z ostatniego wiersza podlegającego agregacji za pomocą GROUP BY, gdyby w zapytaniu zamiast HAVING chname = ‘krzaki’ znalazło się HAVING chname = ’swieta’ otrzymalibyśmy pusty wynik (pomimo, że taka wartość występuje w odpowiedniej kolumnie jednego z agregowanych wierszy).

Czyli jak skutecznie przefiltrować wyniki odnosząc się do wartości uzyskiwanej przez GROUP_CONCAT()?

…..HAVING jest jak najbardziej przydatne (jest wykonywane jako jedna z ostatnich procedur przez zwróceniem wyniku) ale kluczowe jest użycie funkcji FIND_IN_SET()

Oto zmodyfikowane zapytanie:

SELECT entries.*,
           GROUP_CONCAT(channels.channel_name) AS channel_names,
           FIND_IN_SET('swieta', GROUP_CONCAT(channels.channel_name)) AS found
FROM entry_channel
INNER JOIN entries ON entry_channel.entry_id = entries.entry_id
INNER JOIN channels ON entry_channel.channel_id = channels.channel_id
GROUP BY entry_channel.entry_id
HAVING found != 0
ORDER BY entries.created_at DESC
LIMIT 25

Zmiany:
usunąłem: “channels.channel_name AS chname” – nie ma żadnego sensu – jako kryterium dla HAVING – jeśli agregacji podlega więcej niż 1 wiersz

dodałem: “FIND_IN_SET(’szukana_wartość_w_agregowanej_kolumnie’, GROUP_CONCAT(agregowana_kolumna)) AS found”
oraz
“HAVING found != 0″

FIND_IN_SET() zwraca 0 jeśli szukana fraza nie znajduje się w zestawie.

Powtórki z SQL’a… GROUP_CONCAT

Tuesday, December 25th, 2007

Święta to idealny czas na szukanie idealnych rozwiązań również w zakresie webdevelopmentu :)

Między tabelami “entries”, “channels” istnieje relacja wiele-do-wielu definiowana przez tabelę “entry_channel”.

Zadanie 1: Jak w jednym zapytaniu SQL wybrać rekordy z tabeli “entries” z przypisanymi kilkoma rekordami z “channels”… tak aby otrzymać unikalne rekordy “entries”?

Rozwiązanie 1: Rozwiązanie jest całkiem oczywiste – należy użyć grupowania po PK tabeli “entries”.

Zadanie 2: Jak w tym samym zapytaniu SQL otrzymać informacje na temat unikalnych komórek rekordów, które zostały zgrupowane (scalone)?

Rozwiązanie 2: Należy użyć funkcji GROUP_CONCAT(), która utworzy nam dodatkową kolumnę z danymi, które potrzebujemy (dane są domyślnie oddzielone “,”).

Prototyp GROUP_CONCAT()


GROUP_CONCAT([DISTINCT] expr [,expr ...]
             [ORDER BY {unsigned_integer | col_name | expr}
                 [ASC | DESC] [,col_name ...]]
             [SEPARATOR str_val])

Korzystając z HAVING możemy przefiltrować dane zachowując pełną informację z GROUP_CONCAT()

Przykładowe zapytanie MySQL*

SELECT entries.*, channels.channel_name AS chname,
           GROUP_CONCAT(channels.channel_name) AS channel_names
FROM entry_channel
INNER JOIN entries ON entry_channel.entry_id = entries.entry_id
INNER JOIN channels ON entry_channel.channel_id = channels.channel_id
GROUP BY entry_channel.entry_id
HAVING chname = 'krzaki'
ORDER BY entries.created_at DESC
LIMIT 25

Wynik:

entry_id body chname channel_names
1 jakiś fajny wpisik krzaki krzaki,swieta

*) – odwołanie w HAVING do kolumny zamiast do wyniku funkcji agregacyjnej nie jest do końca zgodne ze specyfikacją SQL, natomiast w MySQL jak najbardziej działa

UPDATE: GROUP_CONCAT zwraca wartości typu BLOB jeśli listowane są wartości liczbowe. Aby otrzymać string należy użyć funkcji CAST()……konkretnie: GROUP_CONCAT(CAST(MyID as CHAR)) AS MyIDs

netguru friday talks… javascript

Saturday, November 24th, 2007

Co piątek, w okolicach godziny 14, przerywamy pracę nad projektami aby ugruntować swoją wiedzę związaną z programowaniem.

Dzisiejszy epizod “netguru friday talks” został poświęcony ugruntowaniu wiedzy na temat JavaScript. Rozmawialiśmy o nowoczesnym tworzeniu kodu, separacji JS i HTML, zasięgu, kontekście, operacjach na DOM, JS Closures, jQuery, pluginach do jQuery (jak tworzyć własne i z których istniejących warto korzystać).

Za tydzień o dobrych praktykach w serwisach /społecznościowych/ opowie Kuba. Znany Blogger, znany Designer i trzon netguru. Na pewno będzie ciekawie.

Ładowanie Google Maps na żądanie

Wednesday, November 7th, 2007

Dość długo zastanawiałem się jak załadować GoogleMaps na żadanie ( i chyba nie tylko ja….. Lazy loading of Google Maps API Javascript) w końcu development Google zmiłował się i na przełomie pażdziernika/listopada wraz z GM API 2.92 wypuścił taką możliwość

Do “tradycyjnego” wywołania (czyli nie via AJAX LOADER) należy dodać “&v=2.x&async=2&callback=loadMap”gdzie loadMap to nazwa naszej funkcji konfigurującej i inicjującej mapę (wcześniej jej wywołanie musieliśmy przypisać do zdarzenia onload).

Przykład

Generowanie plików PDF i sprawa polska

Sunday, October 7th, 2007

Myślałem, że biblioteka wchodząca w skład Zend Framework zmieni trochę obecną sytuację – niestety wciąż generowanie pliku PDF ze znakami Unicode z poziomu PHP jest potężnym wyzwaniem.

Osobiście korzystam z biblioteki TCPDF. Nic innego nie udało mi się znaleźć.

kilka słów o… SimplePie

Wednesday, October 3rd, 2007

logo_simplepie_horizontal1.png

Co jakiś czas będę pisał o dojrzałych php’owych bibliotekach, które warto wykorzystywać w swoich projektach…

W tym poście będzie trochę o SimplePie:

SimplePie to bardzo dobra biblioteka do parsowania źródeł XML (RSS, Atom), która nadrabia braki Magpie RSS.

Główne cechy Simplepie to:

  • obsługa wielu feedów w formacie RSS i ATOM (możemy parsować kilkanaście feedów – docelowa lista wpisów może być uszeregowana według daty wpisu lub źródła)
  • filtracja postów (m.in. z reklam, z atrybutów tagów HTML, całkowita filtracja z HTML)
  • caching
  • obsługa podcastów

agregator. raz na serwer proszę…

Wednesday, October 3rd, 2007

Agregacji nigdy dość (szczególnie kiedy popularność i obecność RSSów jest bardziej niż oczywista).

Dlatego piszemy uniwersalny agregator z kilkoma ciekawymi funkcjonalnościami.

Agregator będzie oparty o zmodyfikowany przez nas framework CodeIgniter i wykorzystywał szereg sprawdzonych bibliotek, m.in.:

  • SimplePie (parsowanie RSS,ATOM)
  • HTMLPurifier (filtrowanie importowanej treści)
  • biblioteki “webservices” wchodzące w skład Zend Framework 1.x

Główne cechy tego agreagatora to możliwość parsowania wielu źródeł RSS (z filtracją), możliwość dodania własnych postów, głosowania, tagowanie, kategoryzowanie (np. na podstawie zestawu tagów), bardzo rozbudowane preferencje wyświetlania… i przede wszystkim kojarzenie wpisów z miejscami, ludźmi, produktami… i jeszcze kilka funkcjonalności, o których z pewnością napiszemy kiedy będzie TEN moment.

Co najważniejsze… być może źródła będą udostępnione publicznie.

jQuery UI, jQuery 1.2 – najlepsze jest jeszcze lepsze!

Tuesday, September 11th, 2007

jQuery User Interface Library

To czego brakowało zwolennikom biblioteki jQuery to z pewnością brak akompaniującej biblioteki spełniającej zadania “prototype’owego” script.aculo.us’a. Biblioteka Interface – która pretendowała do tej roli – nie zyskała zbyt wielu sympatyków (powody: rozmiar, mała elastyczność, brak 100% kompatybilności z przeglądarkami). Twórca jQuery, John Resig, zapowiadał od kilku miesięcy, że jQuery dorobi się w końcu dopracowanej biblioteki obsługującej łebdwazerowe wodotryski. jQuery UI zapewni front-end developerom cały zestaw możliwości – drag&drop, zakładki (zapewne ze wsparciem dla przycisków nawigacji przeglądarki i zapamiętywaniem stanu via cookie), overlay i wiele innych… To wszystko już w niedzielę, 16. września. Nie mogę się doczekać!

Dla osłody dla wyczekujących jQuery Team wypuścił bibliotekę jQuery w odsłonie 1.2. Skok w numeracji wersji ma widoczne odzwierciedlenie w zmianach i nowych możliwościach. Wiele potrzebnych nowości, które powiększyły bibliotekę tylko o 5kB (biorąc pod uwagę wersję spakowaną p.a.c.k.e.r’em Deana Edwardsa, którą zapewne najczęściej się wykorzystuje w środowisku produkcyjnym).

Po pełną listę dodanych funkcjonalności odsyłam do WIKI jQuery. Moje faworyty to:

  • metoda offset(), która zapewnia dostęp do koordynatów elementu (top,left); oddzielna biblioteka dimensions będzie w wielu przypadkach zbędna
  • cross-domenowy JSON – od teraz nie trzeba tworzyć rozwiązań a’la proxy
  • poprawiona i rozbudowana serializacja wartości pól formularza – oddzielna biblioteka do obsługi formularzy będzie wielu w wypadkach zbędna
  • animacja stylu elementu w zakresie koloru, tła – wreszcie będziemy mogli tworzyć efektowne powiadomienia :-)
  • metoda triggerHandler() pozwalająca na wywołanie wszystkich event’ów przypisanych do konkretnego elementu DOM poza akcją domyślną
  • i ciekawa funkcja jak klonowanie fragmentu DOM wraz z przypisanymi do niego eventami.

Wielkie “jQuery’owe” święto