<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Athlan • Piotr Pelczar • blog programisty &#187; SQL</title>
	<atom:link href="http://athlan.pl/kategoria/sql/feed/" rel="self" type="application/rss+xml" />
	<link>http://athlan.pl</link>
	<description>Napisać kod zrozumiały dla komputera potrafi byle głupek. Dobrzy programiści tworzą kod zrozumiały dla człowieka...</description>
	<lastBuildDate>Sat, 17 Jul 2010 18:54:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>MySQL DATE() dla pola DATETIME</title>
		<link>http://athlan.pl/mysql-date-function-datetime/</link>
		<comments>http://athlan.pl/mysql-date-function-datetime/#comments</comments>
		<pubDate>Sat, 17 Jul 2010 10:04:39 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Optymalizacja]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Przemyślenia]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=472</guid>
		<description><![CDATA[Oblicza MySQL nie są do końca znane przy tworzeniu aplikacji, a problemy optymalizacyjne stają się nie lada problemem przy funkcjonowaniu wersji produkcyjnej projektu. Nie sposób przewidzieć wszystkich możliwości użycia pól, założenia zarówno wspólnych, jak i pojedynczych indeksów posiadających zakładaną przez nas moc i zajętą pamięć na dysku. Ostatnimi czasy budowałem dość skomplikowany projekt, jeżeli chodzi [...]]]></description>
			<content:encoded><![CDATA[<p>Oblicza <strong>MySQL</strong> nie są do końca znane przy tworzeniu aplikacji, a problemy optymalizacyjne stają się nie lada problemem przy funkcjonowaniu wersji produkcyjnej projektu. Nie sposób przewidzieć wszystkich możliwości użycia pól, założenia zarówno wspólnych, jak i pojedynczych indeksów posiadających zakładaną przez nas moc i zajętą pamięć na dysku.</p>
<p>Ostatnimi czasy budowałem dość skomplikowany projekt, jeżeli chodzi o złożoność zapytań i wykonywanych przez nie operacje matematyczne. Pomimo tego, że aplikacja była doskonale przemyślana, a struktury bazy danych perfekcyjnie jej podporządkowane, gdzieś tkwił problem, bowiem jedno z zapytań generowało pozornie prosty (wizualnie) rezultat, baza reagowała na zapytanie dopiero po 2.5 sekundy dla 30k+ rekordów. Patrząc na strukturę kluczy i zapytania, zwłaszcza, że pola, na których operowałem były różnego rodzaju liczbami i datami zacząłem się poważnie martwić i rozkładać zapytanie na czynniki pierwsze, kończąc na warunkach. Wyobraźcie sobie moje zdziwienie, gdy doszedłem do tego, że całe obciążenie (ponad 2.3 sekundy) generował warunek:</p>

<div class="wp_syntax"><div class="code"><pre class="mysql" style="font-family:monospace;"><span style="color: #990099; font-weight: bold;">WHERE</span> <span style="color: #000099;">DATE</span><span style="color: #FF00FF;">&#40;</span>ticket_date<span style="color: #FF00FF;">&#41;</span> <span style="color: #CC0099;">&gt;=</span> <span style="color: #008000;">&quot; ... &quot;</span></pre></div></div>

<p>Gdzie ticket_date to pole typu <strong>DATETIME</strong>. Od razu doszedłem do wniosku, że w parze idzie złe przygotowanie danych przez PHP, a angażowana jest w to wszystko baza, na której forsuje się użycie funkcji <strong>DATE()</strong>. Przynajmniej dla 30k+ rekordów zindeksowanego pola. Prosty zabieg zamiany jednej linijki kodu na drugą przyniósł porządane efekty.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$aTerms</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'DATE(ticket_date) &gt;= &quot;'</span> <span style="color: #339933;">.</span> <span style="color: #000088;">$sDate</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'&quot;'</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$aTerms</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'ticket_date &gt;= &quot;'</span> <span style="color: #339933;">.</span> <span style="color: #990000;">date</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Y-m-d H:i:s'</span><span style="color: #339933;">,</span> <span style="color: #990000;">strtotime</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sDate</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'&quot;'</span></pre></div></div>

<p>Budując aplikację zwracam szczególną uwagę na strukturę bazy, indeksowanie pól, rysuję diagramy przewidujące wykorzystanie danych pod różne zapytania, ale&#8230; tak banalny błąd przy przeanalizowanej aplikacji rozłożył mnie na łopatki. Z drugiej strony, zapomniałem o jednej bardzo ważnej rzeczy: maksymalnym odciążeniu bazy danych przy preparowaniu argumentów warunków, skoro warunki te mogą być w odpowiedni i przede wszystkim szybki sposób spreparowane na poziomie modelu (abstrakcyjnie rzecz ujmując, pozbywam się pojęcia PHP), który przygotują zapytanie tylko do wykonania operacji na surowych danych, bez konieczności ich ewentualnego przeliczania. Oczywiście nie zawsze taki efekt da się uzyskać, ale należy to maksymalnie <strong>optymalizować</strong>.</p>
<p>Jedno jest wiadome: przeliczanie DATE() dla rekordów w warunku jest nieoptymalne dla pola DATETIME.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/mysql-date-function-datetime/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>MySQL: remove duplicate entries/rows</title>
		<link>http://athlan.pl/mysql-remove-duplicate/</link>
		<comments>http://athlan.pl/mysql-remove-duplicate/#comments</comments>
		<pubDate>Sun, 05 Jul 2009 08:02:04 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[delete]]></category>
		<category><![CDATA[duplicated]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[remove]]></category>
		<category><![CDATA[rows]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=332</guid>
		<description><![CDATA[Usuwając coś permanentnie z bazy danych musimy być bardzo ostrożni, bowiem przywrócenie danych jest bardzo trudne, czasem niemożliwe. Podstawową strukturę bazy danych powinno się budować na samym początku tworzenia aplikacji, z biegiem czasu rozbudowywać ją, ale unikać przebudowywania. Niestety są przypadki, gdzie trzeba przebudować jedną rzecz, co powoduje zmianę w wielu warstwach nie tyle aplikacji, [...]]]></description>
			<content:encoded><![CDATA[<p>Usuwając coś permanentnie z bazy danych musimy być bardzo ostrożni, bowiem przywrócenie danych jest bardzo trudne, czasem niemożliwe. Podstawową strukturę bazy danych powinno się budować na samym początku tworzenia aplikacji, z biegiem czasu rozbudowywać ją, ale unikać przebudowywania. Niestety są przypadki, gdzie trzeba przebudować jedną rzecz, co powoduje zmianę w wielu warstwach nie tyle aplikacji, co strukturze bazodanowej.</p>
<p>Dziś postaram się opisać, jakie kroki trzeba wykonać, aby bezpiecznie usunąć zdublowane rekordy z bazy danych nie tracąc żadnych danych:</p>
<ol>
<li>Tworzymy dwie <strong>kopie bazy danych</strong> lub tabel, na których będziemy pracowali. Najlepiej, aby pracować na drugiej kopii, nigdy na oryginale, a potem wdrożyć zmiany z drugiej kopii na oryginał. Przezorny zawsze ubezpieczony.</li>
<li>Analiza danych w tabeli. Musimy dokładnie wiedzieć jakie są relacje między tabelami, kiedy występują JOIN&#8217;y itp. Jeżeli rekordy są zdublowane, a posiadają ustalony ID, do których odwołuje się inny rekord z sąsiedniej tabeli, trzeba będzie w niej zmienić ID rekord zdublowanego na ID &#8220;substytuta&#8221;, bądź takiego rekordu, który nie spowoduje zmian w serwisie.</li>
<li>Wykonanie operacji <strong>usunięcia zdublowanych rekordów</strong>.</li>
</ol>
<p>Po wykonaniu kroku pierwszego zabieramy się za kolejny. Jest to najważniejszy moment naszych operacji. Aby ułatwić zrozumienie problemu, podam przykład z życia. Aplikacja posiadała poważny błąd, który umożliwiał zdublowanie użytkowników, ściślej: można było zdublować username. Za każdym razem, gdy użytkownik się logował i pisał komentarze, był ich właścicielem, ale comment_author posiadały różne ID tego samego użytkownika. Zaraz po skopiowaniu bazy danych spróbowałem przepisać ID autorów komentarzy na pierwszy rekord identyfikujący użytkownika, jaki istnieje w tabeli użytkowników. Skonstruowałem zapytanie:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">UPDATE</span> cms_comments
<span style="color: #993333; font-weight: bold;">JOIN</span> cms_members <span style="color: #993333; font-weight: bold;">AS</span> user_original <span style="color: #993333; font-weight: bold;">ON</span><span style="color: #66cc66;">&#40;</span>user_original<span style="color: #66cc66;">.</span>user_id <span style="color: #66cc66;">=</span> comment_author<span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">SET</span> comment_author <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#40;</span>
  <span style="color: #993333; font-weight: bold;">SELECT</span> user_first<span style="color: #66cc66;">.</span>user_id <span style="color: #993333; font-weight: bold;">FROM</span> cms_members <span style="color: #993333; font-weight: bold;">AS</span> user_first
  <span style="color: #993333; font-weight: bold;">WHERE</span> user_first<span style="color: #66cc66;">.</span>user_name <span style="color: #66cc66;">=</span> user_original<span style="color: #66cc66;">.</span>user_name
  <span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span> user_first<span style="color: #66cc66;">.</span>user_id <span style="color: #993333; font-weight: bold;">ASC</span> <span style="color: #993333; font-weight: bold;">LIMIT</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Usunięcie zdublowanych użytkowników było już tylko formalnością. Teraz się okaże, dlaczego zależało mi na wyciągnięciu dokładnie pierwszego rekordu reprezentującego &#8220;unikalnego&#8221; użytkownika: poniższe zapytanie (<strong>ALTER IGNORE TABLE ADD UNIQUE</strong>) usunie wszystkie kolejne rekordy oznaczone jako <strong>duplicated</strong>:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">ALTER</span> <span style="color: #993333; font-weight: bold;">IGNORE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> cms_members <span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #993333; font-weight: bold;">UNIQUE</span> <span style="color: #993333; font-weight: bold;">INDEX</span><span style="color: #66cc66;">&#40;</span>user_name<span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>Krótki komentarz z manuala do <strong>ALTER TABLE</strong>:</p>
<blockquote><p><strong>IGNORE</strong> is a <span style="text-decoration: underline;">MySQL extension to standard SQL</span>. It controls how ALTER TABLE works if there are duplicates on unique keys in the new table or if warnings occur when strict mode is enabled. If IGNORE is not specified, the copy is aborted and rolled back if duplicate-key errors occur. If IGNORE is specified, <span style="text-decoration: underline;">only the first row is used of rows with duplicates on a unique key</span>, The other conflicting rows are deleted. Incorrect values are truncated to the closest matching acceptable value.</p></blockquote>
<p>Pisząc ostatnie posty związane z bazami danych, mam nadzieję, że komuś się przydadzą.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/mysql-remove-duplicate/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MySQL: how to convert NULL to 0 number/int</title>
		<link>http://athlan.pl/mysq-convert-null-to-0/</link>
		<comments>http://athlan.pl/mysq-convert-null-to-0/#comments</comments>
		<pubDate>Wed, 01 Jul 2009 23:24:57 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[zero]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=321</guid>
		<description><![CDATA[Im więcej nietypowych rzeczy programuję, tym więcej nietypowych problemów musze pokonać. Co powiecie na sumę 2 liczb, z których jedna jest wartością NULL powstałą w wyniku działania SUM() lub pochodnych, gdzie nie odnaleziono żadnego rekordu. Badamy: SELECT 1+2+3 &#62;&#62; 6 SELECT 1+2+NULL &#62;&#62; NULL SELECT COALESCE( NULL, 0 ) &#62;&#62; 0 Zatem analogicznie do powyższego [...]]]></description>
			<content:encoded><![CDATA[<p>Im więcej nietypowych rzeczy programuję, tym więcej nietypowych problemów musze pokonać. Co powiecie na sumę 2 liczb, z których jedna jest wartością <strong>NULL</strong> powstałą w wyniku działania <strong>SUM()</strong> lub pochodnych, gdzie nie odnaleziono żadnego rekordu.</p>
<p>Badamy:</p>
<p><code>SELECT 1+2+3<br />
&gt;&gt; 6</code></p>
<p><code>SELECT 1+2+NULL<br />
&gt;&gt; NULL</code></p>
<p><code>SELECT COALESCE( NULL, 0 )<br />
&gt;&gt; 0</code></p>
<p>Zatem analogicznie do powyższego przykładu:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">UPDATE</span> users <span style="color: #993333; font-weight: bold;">SET</span> user_points <span style="color: #66cc66;">=</span> user_points <span style="color: #66cc66;">+</span> COALESCE<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #993333; font-weight: bold;">SELECT</span> SUM<span style="color: #66cc66;">&#40;</span> <span style="color: #66cc66;">...</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">WHERE</span> <span style="color: #66cc66;">...</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span></pre></div></div>

<p>Punkty użytkownika już zawsze będą się sumowały poprawnie :-)</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/mysq-convert-null-to-0/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>MySQL UPDATE JOIN</title>
		<link>http://athlan.pl/mysql-update-join/</link>
		<comments>http://athlan.pl/mysql-update-join/#comments</comments>
		<pubDate>Tue, 30 Jun 2009 09:46:27 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[join]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[update]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=317</guid>
		<description><![CDATA[Ostatnimi czasy potrzebowałem danych z sąsiedniej tabeli przy UPDATE jedngo z pól w bazie danych. Danych do przetworzenia było sporo, więc zwracałem uwagę na wydajność zapytania. Aby zebrać potrzebne informacje, można użyć jednego ze sposobów: Zebrać potrzebne dane za pomocą SELECT&#8216;a, co sprawiłoby, że zajęta zostanie niepotrzebna pamięć w środowisku PHP podczas przypisania rezultatu do [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnimi czasy potrzebowałem danych z sąsiedniej tabeli przy <strong>UPDATE</strong> jedngo z pól w bazie danych. Danych do przetworzenia było sporo, więc zwracałem uwagę na wydajność zapytania. Aby zebrać potrzebne informacje, można użyć jednego ze sposobów:</p>
<ol>
<li>Zebrać potrzebne dane za pomocą <strong>SELECT</strong>&#8216;a, co sprawiłoby, że zajęta zostanie niepotrzebna pamięć w środowisku PHP podczas przypisania rezultatu do zmiennej.</li>
<li>Wykonać <strong>SET z podzapytaniem</strong>, ale potrzebnych mi było kilka kolumn z sąsiedniej tabeli, podzapytanie może zwrócić tylko jedną określoną wartość.</li>
<li>Wykonać <strong>JOIN</strong> przy update, czego niestety wówczas nie potrafiłem zrobić.</li>
</ol>
<p>Kartkując <a href="http://dev.mysql.com/doc/refman/5.0/en/update.html">manual</a> nie natrafiłem się w standardowej dokumentacji na nic konkretnego, aż nie spojrzałem na bardzo przydatne <a href="http://dev.mysql.com/doc/refman/5.0/en/update.html#c5402">komentarze użytkowników</a>. Okazało się, że przy <strong>UPDATE</strong> można wykonywać dowolne <strong>JOIN</strong>&#8216;y, schemat jest następujący:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">UPDATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #993333; font-weight: bold;">JOIN</span> another_table <span style="color: #993333; font-weight: bold;">SET</span> <span style="color: #66cc66;">...</span></pre></div></div>

<p>W tym momencie mamy do dyspozycji wszystkie pola z dołączonej tabeli. Bardzo przydatne.</p>
<p><strong>Przykład z życia.</strong></p>
<p>Miałem za zadanie odznaczyć typy bukmacherskie na trafione, nietrafione, odwołane z przyczyn odwołania całego meczu piłkarskiego oraz te, które jeszcze nie mogą zostać oznaczone jako trafione lub nie, gdyż mecz się jeszcze nie odbył.</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">UPDATE</span> typer_tickets_items
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> typer_events <span style="color: #993333; font-weight: bold;">ON</span><span style="color: #66cc66;">&#40;</span>event_id <span style="color: #66cc66;">=</span> item_event<span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">SET</span> item_status <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#40;</span>
CASE
WHEN event_status <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span> THEN <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #808080; font-style: italic;"># mecz nie zostal rozegrany</span>
WHEN event_status <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span> THEN <span style="color: #66cc66;">-</span><span style="color: #cc66cc;">1</span> <span style="color: #808080; font-style: italic;"># mecz anulowany</span>
WHEN event_status <span style="color: #66cc66;">=</span> item_bet THEN <span style="color: #cc66cc;">1</span> <span style="color: #808080; font-style: italic;"># typ trafiony</span>
ELSE <span style="color: #cc66cc;">0</span> END <span style="color: #808080; font-style: italic;"># typ nietrafiony</span>
<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">WHERE</span> item_status <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span></pre></div></div>

<p>Mam nadzieję, że komuś się przyda&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/mysql-update-join/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Przypadki w MySQL &#8211; CASE WHEN THEN ELSE END</title>
		<link>http://athlan.pl/mysql-case-when-then-else-end/</link>
		<comments>http://athlan.pl/mysql-case-when-then-else-end/#comments</comments>
		<pubDate>Wed, 29 Apr 2009 13:15:07 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Planeta]]></category>
		<category><![CDATA[Publikacje]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Solutions]]></category>
		<category><![CDATA[Add new tag]]></category>
		<category><![CDATA[case]]></category>
		<category><![CDATA[conditions]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[syntax]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=299</guid>
		<description><![CDATA[Podobnie jak w PHP, baza danych MySQL ma odpowiednik if, czyli przypadków (inaczej serii warunków, instrukcji warunkowych). Różnicą między implementacją CASE&#8216;a w MySQL i ifa PHP jest to, że baza danych zwraca konkretną wartość z case&#8217;a, a nie wykonuje dowolnej ilości dowolnych akcji. CASE Syntax: Najprostsza struktura CASE&#8217;aprzedstawia się nastepująco: CASE WHEN [conditions] THEN ... ELSE [...]]]></description>
			<content:encoded><![CDATA[<p>Podobnie jak w PHP, baza danych MySQL ma odpowiednik <a href="http://pl2.php.net/manual/en/control-structures.if.php">if</a>, czyli przypadków (inaczej serii warunków, instrukcji warunkowych). Różnicą między implementacją <a href="http://dev.mysql.com/doc/refman/5.0/en/case-statement.html">CASE</a>&#8216;a w MySQL i ifa PHP jest to, że baza danych zwraca konkretną wartość z case&#8217;a, a nie wykonuje dowolnej ilości dowolnych akcji.</p>
<p><strong>CASE Syntax:</strong></p>
<p>Najprostsza struktura CASE&#8217;aprzedstawia się nastepująco:</p>
<p><code>CASE WHEN [conditions] THEN ... ELSE ... END</code></p>
<p>Składnia powinna rozpocząć się słowem kluczowym CASE, a zakończyć END. Pomiędzy znajdują się warunki WHEN oraz operacja zwrócenia odpowiedniej wartości, która po nich następuje THEN (mamy możliwość uwzględnić nieskończenie wiele warunków). Jeżeli żaden warunek nie zostanie spełniony możemy użyć opcjonalnie ELSE.</p>
<p><strong>Przykłady z życia.</strong></p>
<p>Wyobraźmy sobie, że mamy posortować listę aukcji przedmiotów na Allegro od najtańszych, do najdroższych. Należy założyć, że są 2 typy aukcji: kup teraz i licytacja. Pole licytacji w bazie danych zawiera największą zaproponowaną kwotę przez użytkowników w procesie licytacji, a cena kup teraz ustalana jest przez sprzedającego. Są to dwa różne pola w bazie danych, a jedno kryterium sortowania, dlatego trzeba scalić cenę w jedną, wybierając odpowiednią. Musimy przewidzieć sytuację, w której aukcja jest typu kup teraz oraz licytacji, wówczas jeżeli najwyższa oferta jest większa od ceny kup teraz, wówczas wybieramy pole z największa propozycją:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> <span style="color: #66cc66;">&#40;</span>
  CASE
    WHEN <span style="color: #66cc66;">&#40;</span>auction_type <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'bidding'</span> <span style="color: #993333; font-weight: bold;">OR</span> auction_price_bid <span style="color: #66cc66;">&gt;</span> auction_price_buynow<span style="color: #66cc66;">&#41;</span>
      THEN auction_price_bid
    ELSE auction_price_buynow
  END<span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> auction_price</pre></div></div>

<p>Stworzyliśmy pole auction_price, po którym można sortować aukcje od najtańszej do najdroższej i na odwrót.</p>
<p>Mam nadzieję, że krótki wpis przyda się początkującym. <span style="color: #c0c0c0;">Nic więcej nie trzeba opisywać, temat wydaje się co najmniej trywialny.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/mysql-case-when-then-else-end/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Nieprzeczytane fora/tematy/posty</title>
		<link>http://athlan.pl/nieprzeczytane-fora-tematy-posty/</link>
		<comments>http://athlan.pl/nieprzeczytane-fora-tematy-posty/#comments</comments>
		<pubDate>Mon, 09 Jun 2008 18:34:08 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Przemyślenia]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://athlan.pl/?p=115</guid>
		<description><![CDATA[Ostatnimi czasy pracuje nad dość dużym projektem. Jednym z punktów specyfikacji są fora dyskusyjne w grupach. Oczywiście pojawił się problem z nieprzeczytanymi postami. Jest kilka rozwiązań, każde ma swoje plusy i minusy: Sprawdzanie daty ostatniego postu na całym forum danej grupy. Pomysł zaczerpnięty z portalu nasza-klasa.pl, gdzie bok relacji użytkownik-&#62;forum zapisywana jest data ostatniego odwiedzenia [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnimi czasy pracuje nad dość dużym projektem. Jednym z punktów specyfikacji są fora dyskusyjne w grupach. Oczywiście pojawił się problem z nieprzeczytanymi postami. Jest kilka rozwiązań, każde ma swoje plusy i minusy:</p>
<ol>
<li>Sprawdzanie daty ostatniego postu na całym forum danej grupy. Pomysł zaczerpnięty z portalu nasza-klasa.pl, gdzie bok relacji użytkownik-&gt;forum zapisywana jest data ostatniego odwiedzenia forum. Jeżeli na forum jest nowszy post niż zapisana data &#8211; forum jest oznaczone jako nieprzeczytane. Minusem tego rozwiązania jest to, że działa bardzo ogólnikowo (nie wiadomo które tematy są nieprzeczytane, które nie &#8211; oznaczane jest tylko forum, w dodatku jeden raz).</li>
<li>Korzystanie z historii przeglądarki przy użyciu stylu a:visited. Plus &#8211; łatwość implementacji, minusy &#8211; ogólnikowe, nie zawsze zadziała, amatorszczyzna (nie na taki projekt, rozumiem blog).</li>
<li>Sposób z PHPBB: stworzenie relacji user-&gt;temat, gdzie zapisana jest data ostatniego czytania tematu. Plusy: możemy stwierdzić ostatnią wizytę co do konkretnego posta. Minusy: dużo syfu w bazie danych, wypadałoby dodać limit, np czyszczenie nieprzeczytanych for po ilości wątków oraz limit czasowy, czyszczone cronem lub przy innej okazji.</li>
</ol>
<p>Po dłuższej analizie, zdecydowałem się na implementację trzeciego rozwiązania za pomocą tabeli:</p>
<ul>
<li>handle_user (id usera),</li>
<li>handle_group (id grupy),</li>
<li>handle_thread (id tematu),</li>
<li>handle_time (czas ostatniej wizyty w temacie, defaultowo 0).</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/nieprzeczytane-fora-tematy-posty/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Unikanie zdublowanych tytułów SEO friendly</title>
		<link>http://athlan.pl/unikanie-zdublowanych-tytulow-seo-friendly/</link>
		<comments>http://athlan.pl/unikanie-zdublowanych-tytulow-seo-friendly/#comments</comments>
		<pubDate>Sat, 01 Mar 2008 08:57:21 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SEO]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Vframe 2.x]]></category>

		<guid isPermaLink="false">http://athlan.vgroup.pl/unikanie-zdublowanych-tytulow-seo-friendly/</guid>
		<description><![CDATA[Często budujemy linki SEO friendly umieszczając tytuły newsów, kategorii, produktów etc. Problemem może być powtarzanie się tytułu (dajmy na to nazwy produktu) zawartego w URL: http://example.com/nazwa-produktu.html Oczywiście można to objeść podając ID produktu i kategorii w adresie: http://example.com/6521,nazwa-produktu.html Chcemy tego uniknąć. Jak zatem rozwiązać problem zdublowania? Przed rozpoczęciem działań stwórzmy sobie mały plan działania: Zamiana [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://img231.imageshack.us/img231/120/seoblocksho4.jpg" align="left" border="1" height="154" hspace="10" width="200" />Często budujemy linki <a href="http://pl.wikipedia.org/wiki/SEO#Etyczne_i_nieetyczne_techniki_pozycjonowania">SEO friendly</a> umieszczając tytuły newsów, kategorii, produktów etc. Problemem może być powtarzanie się tytułu (dajmy na to nazwy produktu) zawartego w URL:</p>
<p><em>http://example.com/nazwa-produktu.html </em></p>
<p>Oczywiście można to objeść podając ID produktu i kategorii w adresie:</p>
<p><em>http://example.com/6521,nazwa-produktu.html</em></p>
<p>Chcemy tego uniknąć. Jak zatem rozwiązać problem zdublowania? Przed rozpoczęciem działań stwórzmy sobie mały plan działania:</p>
<ul>
<li>Zamiana tytułu newsa ze zwykłego na SEO friendly.</li>
<li>Pobranie tytułów newsów pasujących do wzorca: LIKE &#8216;nasz-tytul%&#8217;.</li>
<li>Dodanie sufiksu do tytułu -2 (jeżeli istnieje -2 wówczas -3), tak aby powstał nasz-tytul-2, nasz-tytul-3 w przypadku powtórzeń.</li>
</ul>
<p><strong>Krok 1.</strong> <a href="http://athlan.vgroup.pl/code/seo_titles">Stworzenie tytułu SEO friendly</a> <em>(listing)</em>.</p>
<p><strong>Krok 2.</strong> <a href="http://athlan.vgroup.pl/code/seo_titles_related">Pobranie podobnych tytułów z bazy danych</a> <em>(listing)</em>.</p>
<p><strong>Krok 3.</strong> <a href="http://athlan.vgroup.pl/code/seo_titles_unique">Dodanie sufiksów do tytułów</a>, jeżeli istnieją podobne, które uniemożliwiają dodanie rekordu <em>(listing)</em>.</p>
<p>Teraz zmienna <em>$sRewrite</em> zawiera tytuł SEO, który możemy śmiało wpisać do bazy danych &#8211; na pewno sie nie powtórzy :)</p>
<p><em>Note: Przykłady zostały opisane na bazie mojego frameworka <a href="http://framework.vgroup.pl">Vframe</a> używając klasy <a href="http://framework.vgroup.pl/repository/expose-2ee19afa880c5f0bb9dec2633e60884b.htm">Vframe_Util_Rewrite</a> z której można skorzystać.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/unikanie-zdublowanych-tytulow-seo-friendly/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Optymalizacja zapytań do baz danych</title>
		<link>http://athlan.pl/optymalizacja-zapytan-do-baz-danych/</link>
		<comments>http://athlan.pl/optymalizacja-zapytan-do-baz-danych/#comments</comments>
		<pubDate>Tue, 08 Jan 2008 21:47:16 +0000</pubDate>
		<dc:creator>Athlan</dc:creator>
				<category><![CDATA[Databases]]></category>
		<category><![CDATA[Przemyślenia]]></category>
		<category><![CDATA[SQL]]></category>

		<guid isPermaLink="false">http://athlan.vgroup.pl/optymalizacja-zapytan-do-baz-danych/</guid>
		<description><![CDATA[Ostatnio rozmyślałem nad optymalizacją struktury i zapytań do baz danych. Moim zadaniem było (i nadal jest) wysłąnie powiadomień użytkownikowi, co dzieje się z jego profilem. Wysłanie prostego powiadomienia to zwykłe przypisanie wiadomości do jego ID, natomiast gdy wysyłamy powiadomienia np o dodanym przez naszego przyjaciela materiale, nie będziemy przecież wysyłać po 1000 rekordów tylko po [...]]]></description>
			<content:encoded><![CDATA[<p>Ostatnio rozmyślałem nad optymalizacją struktury i zapytań do baz danych. Moim zadaniem było (i nadal jest) wysłąnie powiadomień użytkownikowi, co dzieje się z jego profilem.</p>
<p>Wysłanie prostego powiadomienia to zwykłe przypisanie wiadomości do jego ID, natomiast gdy wysyłamy powiadomienia np o dodanym przez naszego przyjaciela materiale, nie będziemy przecież wysyłać po 1000 rekordów tylko po to, żeby każdy przyjaciel otrzymał informację. Robimy to w inny sposób: nadajemy ownera (notice_owner) powiadomienia na 0 i ustawiamy dodatkowe pole notice_self na 1. To oznacza, że powiadomienie tyczy się wszystkich użytkowników, którzy mają daną osobę w znajomych (stąd owner 0). Pole unotice_user informuje na temat kogo jest powiadomienie, a pole notice_type (int 2) nadaje numerek typu powiadomienia</p>
<p><a HREF="http://rafb.net/p/RWF9V478.html">[ struktura takiej bazy ]</a>.</p>
<p>Pora za zapytania. Najlepiej jakby wykorzystać wszystkie klucze zawarte w tabeli. Trzeba by było wykonać 2 zapytania, które zaznaczyłyby wszytskie rekordy. Z pomocą przychodzą nam unie <a HREF="http://rafb.net/p/n6pJJD98.html">[ zobacz zapytanie ]</a>.</p>
<p>Drugi sposób. Zamiast rozdzielania warunków na 2 zapytania możemy połączyć go w jeden operatorem OR. I tutaj jest problem. Jakiego bym klucza nie zrobił, żaden nie zostanie użyty <a HREF="http://rafb.net/p/zQnjow33.html">[ zobacz zapytanie ]</a>.</p>
<p>Zdania są podzielone co do używania obu sposobów. <a HREF="http://forum.php.pl/OR_w_warunku_czy_stworzenie_unii_t84385.html">Zadałem już pytanie</a> na forum.php.pl, jednak nikt nie pokusił się na nie odpowiedzieć.</p>
<p>No nic, problem będzie nękał mnie nadal, aż przejdę do testów na sztucznie stworzonej bazie danych.</p>
]]></content:encoded>
			<wfw:commentRss>http://athlan.pl/optymalizacja-zapytan-do-baz-danych/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
