Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: Athlan, dodany: 29.04.2009 15:15, tagi: sql

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‘a w MySQL i ifa PHP jest to, że baza danych zwraca konkretną wartość z case’a, a nie wykonuje dowolnej ilości dowolnych akcji.

CASE Syntax:

Najprostsza struktura CASE’aprzedstawia się nastepująco:

CASE WHEN [conditions] THEN … ELSE … END

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.

Przykłady z życia.

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ą:

SELECT (CASE WHEN (auction_type = 'bidding' OR auction_price_bid > auction_price_buynow) THEN auction_price_bid ELSE auction_price_buynow END) AS auction_price

Stworzyliśmy pole auction_price, po którym można sortować aukcje od najtańszej do najdroższej i na odwrót.

Mam nadzieję, że krótki wpis przyda się początkującym. Nic więcej nie trzeba opisywać, temat wydaje się co najmniej trywialny.

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Diabl0, dodany: 25.04.2009 22:56, tagi: zend_framework

tree_7Początkowo jako następny artykuł miało się tutaj pojawić podsumowanie tematu drzew wraz z przykładami praktycznego zastosowania. Jednym z tematów miało być wykorzystanie drzewa i elementu dijit.Tree w formie własnego elementu Zend_Form. Niestety, podczas prac trafiłem na pewien problem który mnie zablokował i za bardzo nie wiem jak do niego podejść w miarę prosty sposób. Tak więc tym razem zamiast gotowego rozwiązania będzie bardziej pytanie i prośba o pomoc.

Uwaga - zawarte fragmenty kodu są wersjami roboczymi, zapewne zawierają sporo błędów i można je napisać znacznie ładniej i zgodniej z standardami. Znajdują się one tutaj aby lepiej zobrazować problem i stanowić tylko i  wyłącznie wskazówki i pomoc, tak więc proszę ich nie wykorzystywać bez zastanowienia i dopracowania, aby nie mieć później pretensji że coś nie działa lub co gorsza działa źle.

Kto interesuje się Dojo wie że w jego skład wchodzi widget dijit.Tree. Naturalna więc wydaje się próba ułatwienia sobie życia i próba stworzenia elementu formy który da użytkownikom możliwość szybkiego i wygodnego wyboru elementu za pomocą rozwijanego drzewa. Początkowo problem wydawał się banalny, i pierwszy “szkic” takiego elementu napisałem w około godzinkę.

Idea działania jest prosta - tworzymy zwykły ukryty element INPUT w którym będzie lądował identyfikator wybranego elementu drzewa. Do tego tworzymy element DIV który następnie zostanie przekształcony w element dijit.Tree.

/**
 * Tree form element
 *
 * @uses Mao_View_Helper_FormDiv
 */

class Mao_Form_Element_Tree extends Zend_Dojo_Form_Element_ComboBox {

    /**
     * Use FormTree view helper
     * @var string
     */
    public $helper = 'FormTree';
}
/**
 * Dojo Tree dijit
 *
 * @uses       Zend_Dojo_View_Helper_Dijit
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
  */
class Mao_View_Helper_FormTree extends Zend_Dojo_View_Helper_Dijit
{
    /**
     * Dijit being used
     * @var string
     */
    protected $_dijit  = 'dijit.Tree';

    /**
     * HTML element type
     * @var string
     */
    protected $_elementType = 'text';

    /**
     * Dojo module to use
     * @var string
     */
    protected $_module = 'dijit.Tree';

    /**
     * dijit.form.ComboBox
     *
     * @param  int $id
     * @param  mixed $value
     * @param  array $params  Parameters to use for dijit creation
     * @param  array $attribs HTML attributes
     * @param  array|null $options Select options
     * @return string
     */
    public function formTree($id, $value = null, array $params = array(), array $attribs = array(), array $options = null)
    {
        $html = '';
        if (!array_key_exists('id', $attribs)) {
            $attribs['id'] = $id;
        }
        if (array_key_exists('store', $params) && is_array($params['store'])) {
            // using dojo.data datastore
            if (false !== ($store = $this->_renderStore($params['store']))) {
                $params['store'] = $params['store']['store'];
                if (is_string($store)) {
                    $html .= $store;
                }
                $html .= $this->_createFormElement($id, $value, $params, $attribs);
                return $html;
            }
            unset($params['store']);
        } elseif (array_key_exists('store', $params)) {
            if (array_key_exists('storeType', $params)) {
                $storeParams = array(
                    'store' => $params['store'],
                    'type'  => $params['storeType'],
                );
                unset($params['storeType']);
                if (array_key_exists('storeParams', $params)) {
                    $storeParams['params'] = $params['storeParams'];
                    unset($params['storeParams']);
                }
                if (false !== ($store = $this->_renderStore($storeParams))) {
                    if (is_string($store)) {
                        $html .= $store;
                    }
                }
            }
            $html .= $this->_createFormElement($id, $value, $params, $attribs);
            return $html;
        }

        throw new Exception('No dojo.data store provided.');
    }

	/**
	 * Create HTML representation of a dijit form element
	 *
	 * @param  string $id
	 * @param  string $value
	 * @param  array $params
	 * @param  array $attribs
	 * @param  string|null $dijit
	 * @return string
	 */
	public function _createFormElement($id, $value, array $params, array $attribs, $dijit = null) {

		if (! array_key_exists ( 'id', $attribs )) {
			$attribs ['id'] = $id;
		}
		$attribs ['name'] = $id;
		$attribs ['value'] = ( string ) $value;
		$attribs ['type'] = $this->_elementType;

		$attribs ['id'] = '_' . $id . '_';
		$attribs = $this->_prepareDijit ( $attribs, $params, 'element', $dijit );
		$attribs ['id'] = $id;

		// atrybuty na potrzeby DIVa reprezentującego dijit.Tree
		$divAttribs = $attribs;

		// Ukrywamy element INPUT
		$attribs ['type'] = 'hidden';

        // Wyrzucamy ukryty input
        $html = '<input'
              . $this->_htmlAttribs($attribs)
              . $this->getClosingBracket();

		// Modyfikujemy atrybuty na potrzeby elementu DIV reprezentującego dijitTree
		$divAttribs ['id'] = '_' . $id . '_';
		$divAttribs ['name'] = '_' . $id . '_';
		unset ( $divAttribs ['name'], $divAttribs ['value'] );

        $html .= '<div '
            . $this->_htmlAttribs( $divAttribs )
            . $this->getClosingBracket()
            . '</div>';

		// Wyrzucamy kod JS odpowiadający za połączenie ukrytego inputa z wyświetlonym drzewkiem
		$this->_renderJsHelper ( $id, $params );

		return $html;
	}

    /**
     * Render data store element
     *
     * Renders to dojo view helper
     *
     * @param  array $params
     * @return string|false
     */
    protected function _renderStore(array $params)
    {
        if (!array_key_exists('store', $params) || !array_key_exists('type', $params)) {
            return false;
        }

        $this->dojo->requireModule($params['type']);

        $extraParams = array();
        $storeParams = array(
            'dojoType' => $params['type'],
            'jsId'     => $params['store'],
        );

        if (array_key_exists('params', $params)) {
            $storeParams = array_merge($storeParams, $params['params']);
            $extraParams = $params['params'];
        }

        if ($this->_useProgrammatic()) {
            if (!$this->_useProgrammaticNoScript()) {
                require_once 'Zend/Json.php';
                $js = 'var ' . $storeParams['jsId'] . ' = '
                    . 'new ' . $storeParams['dojoType'] . '('
                    .     Zend_Json::encode($extraParams)
                    . ");\n";
                $this->dojo->addJavascript($js);
            }
            return true;
        }

        return '<div' . $this->_htmlAttribs($storeParams) . '></div>';
    }

	/**
	 * Render data store element
	 *
	 * Renders to dojo view helper
	 *
	 * @param  string $id
	 * @param  array $params
	 * @return string|false
	 */
	protected function _renderJsHelper($id, array $params) {

		if ($this->_useProgrammatic ()) {
			if (! $this->_useProgrammaticNoScript ()) {
				require_once 'Zend/Json.php';

				$js = '
 dojo.subscribe("_' . $id . '_", "execute", function( data ){
    dojo.byId("' . $id . '").value = ' . $params ['store'] . '.getIdentity( data.item );
 });
 ';
				$this->dojo->addJavascript ( $js );
			}
			return true;
		}

		return '<div' . $this->_htmlAttribs ( $storeParams ) . '></div>';
	}

}

Powyższe 2 klasy załatwiają nam utworzenie wspomnianych elementów INPUT i DIV. Dodatkowo w metodzie _renderJsHelper znajduje się prosty kod JS odpowiedzialny za nasłuch zdarzeń w utworzonym widgecie dijitTree i w po wybraniu jakiegoś elementu wstawienie jego identyfikatora do pola INPUT (to ten fragment z dojo.subscribe).

Od strony formy wykorzystanie tego elementu wygląda mniej więcej tak:

class default_forms_TreeTest extends Mao_Form {

    public function __construct($options = null) {
        parent::__construct ( $options );

        // Dojo-enable the form:
        Zend_Dojo::enableForm ( $this );

        $this->addElement ( 'Tree', 'tree_id',
           array (
              'label'             => 'Tree',
              'storeId'           => 'tstr',
              'storeType'         => 'dojo.data.ItemFileReadStore',
              'storeParams'       => array(
                'url'        => '/mag/categories/categoriesTreeJson.json',
              ),
              'dijitParams'       => array(
                    'labelAttr' => 'name',
              ),
              'value'             => 4,
              'style'   => 'height: 200px; overflow: auto;',
           )
        );

        $this->addElement ( 'SubmitButton', 'submit',
        array (
              'label' => 'Zapisz'
          )
        );

    }

}

Natomiast wynikowy kod HTML:

[sourcecode]
<!-- W części JS generowanej przez Zend_Dojo -->
<script type="text/javascript">
//<![CDATA[
    dojo.require("dijit.Tree");

var tstr = new dojo.data.ItemFileReadStore({"url":"\/mag\/categories\/categoriesTreeJson.json"});
    //

 dojo.subscribe("_tree_id_", "execute", function( data ){
    // console.log( tstr.getIdentity( data.item ) );
    dojo.byId("tree_id").value = tstr.getIdentity( data.item );
 });

//]]>
</script>

<!-- I część formy -->
<dt><label for="tree_id" class="optional">Tree</label></dt>
<dd>
<input style="height: 200px; overflow: auto;" id="tree_id" name="tree_id" value="4" type="hidden">
<div  style="height: 200px; overflow: auto;" id="_tree_id_" type="text"></div>
</dd>
[/sourcecode]

W sumie wszystko teoretycznie działa, brakuje jednak pewnej “małej” ale ważnej funkcjonalności - przy wyświetlaniu formy powinno nastąpić automatyczne zaznaczenie elementu drzewa którego identyfikator znajduje się w polu INPUT, oraz rozwinięcie odpowiedniej gałęzi drzewa. Niestety twórcy dijit.Tree z jakiegoś powodu nie zaimplementowali do tego odpowiednich metod przez co trzeba to zrobić samemu. I tutaj mamy 2 problemy:

  1. lazy loading
  2. znalezienie wybranego elementu, rozwinięcie gałęzi do której on należy i zaznaczenie go

Problem pierwszy wynika z tego że dane do drzewa ładowane są asynchronicznie po stworzeniu elementu. Na szczęście problem ten jest dość prosty do rozwiązania z wykorzystaniem interwałów:

var _tree_id_timer;
dojo.addOnLoad( function () {
    if ( dojo.byId("tree_id").value != "") {
	    _tree_id_timer = setInterval( function(){
	        if ( dijit.byId("_tree_id_").store._loadFinished ) {
                    // Dane do elementu zostały załadowane
	            clearInterval( _tree_id_timer );

	            // Czas znaleźć i zaznaczyć wybrany element

	        }
	    }, 100);
    }
});

W skrócie, jeśli w pole input zawiera jakąś wartość, to tworzymy interwał który co określony czas sprawdza czy źródło danych wykorzystywane przez dijit.Tree zakończyło wczytywanie danych (dijit.byId(”_tree_id_”).store._loadFinished). Jeśli skończyło to czyścimy interwał (już nam nie będzie potrzebny) i przystępujemy do problemu drugiego.

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Spawnm, dodany: 23.04.2009 16:11, tagi: php

Jak można zauważyć na wortalu pojawiły się przyjazne linki.
W przeciwieństwie to tych 'znanych' nie korzystają z mod_rewrite oraz
nie musimy pisać dodatkowych aplikacji.

Autor wpisu: Spawnm, dodany: 22.04.2009 13:07, tagi: php

Myślisz że twoje pliki są bezpieczne ?
Myślisz że póki ich nie zaincludujesz do głównego pliku nic nie zrobią ?
A może jednak ? Może ktoś bez twojej wiedzy właśnie przegląda twój admin panel?

Autor wpisu: thejw23, dodany: 20.04.2009 18:45, tagi: php

nowa wersja dostepna na SVN, zmiany, glownie zwiazane z laczeniem metod:
- dodane update(), tak dla porzadku skoro jest insert()
- dodane select() aby ograniczyc liczbe zwracanych pol (wczesniej zawsze *)
- dodane limit(), aby fetch_x mialo mniej parametrow
- uwaga: w zwiazku z powyzszym fetch zgubilo parametr $limit
- load() zwraca $this

dzieki temu mozna teraz w jednej linijce np. tak:
//pobranie 2 pol z limitem 3 rekordow
$users=Simple_Modeler::factory('auth_users')->select('username','email')->limit(3)->fetch_all();
//zaladowanie pojedynczego rekordu z bazy, username=janek
$user=Simple_Modeler::factory('auth_users')->load('janek','username');

Autor wpisu: Grzegorz (MajareQ) Karwaszewski, dodany: 20.04.2009 18:01, tagi: internet, sql

Spis Treści:

  1. Czym w zasadzie są transakcje?
  2. Jak działają?
  3. Transakcje w Transact-SQL.
  4. Transakcje w Oracle.
  5. Transakcje w MySQL.
  6. Transakcje w PostgreSQL.
  7. Lost update problem.
  8. Typy blokad.
  9. Cofanie transakcji.
  10. Podsumowanie i bibliografia.

1. Czym w zasadzie są transakcje?

Dla młodego programisty aplikacji internetowych dotąd zapytania SQL kojarzyły się jako odrębne zadania do wykonania.
Na przykład funkcja zliczająca unikalne wejścia na daną podstronę zarejestrowanych użytkowników wykonywała osobno (czysta teoria):

  • zapytanie sprawdzające czy wejście jest rzeczywiście unikalne (np. pobieranie IP z listy pamiętanych adresów w tabeli bazy danych)
  • zapytanie pobierające aktualną liczbę unikalnych wejść
  • zapytanie zmieniające stan wejścia na podstroną danego użytkownika w rekordzie tabeli użytkowników

Jednak gdy w przypadku np. awarii systemu, w trakcie wykonywania operacji modyfikacje odbyłyby się tylko w części, co doprowadziłoby do dalszych komplikacji.

Wyobraźmy sobie to na przykładzie: jest system zarządzający inwentarzem w hurtowni.
Gdy klient kupuje 75 sztuk długopisów, do bazy danych idą zapytania aktualizujące stan kasy, w której kupował oraz zmieniające liczbę długopisów w inwentarzu.
W przypadku gdy długopisów jest już bardzo mało, system automatycznie wysyła zamówienie do producenta długopisów na kolejne 2000 długopisów.
Gdyby w połowie wykonywania tych operacji system straciłby zasilanie to np. stan kasy zostałby poprawiony, ale stan długopisów nie zgadzałby się już z rzeczywistością. Mogłoby dojść potem do sytuacji, że kolejny klient chce zakupić 200 długopisów, a w inwentarzu brakuje 50, ponieważ nie było dostawy długopisów. Dlaczego? Ponieważ przez awarię system nie wykrył, że długopisów jest już mało i zamówienie nie zostało wysłane do producenta.

Jak uniknąć sytuacji tego typu i podobnych?
Rozwiązanie jest teoretycznie proste. Trzeba zastosować transakcje.

Transakcje grupują wyrażenia SQL, traktując tą grupę jako jedno.
Transakcja może składać się z jednego zapytania lub z wielu, to zależy od charakteru zadania do wykonania.
Charakteryzują je zasada ACID czyli, Atomicity, Consistency, Isolation, Durability - Atomowość, Spójność, Izolacja, Trwałość.
Oznacza to, że każda transakcja wykona się w całości, lub wcale. Podczas jej wykonywania  dwie równoległe transakcje nie widzą wprowadzanych przez siebie zmian (zależy od poziomu izolacji) do momentu zatwierdzenia transakcji. Zmiany nie są też widoczne dla pozostałych użytkowników tej bazy danych. Po jej wykonaniu nie zostaną naruszane zasady integralności bazy. A cały system udostępni nam nienaruszone dane po nagłej awarii systemu.

Transakcje można używać samodzielnie, ale ich zastosowanie najczęściej idzie w parze z zastosowaniem kursorów w procedurach składowych.
Procedury składowe są udoskonaleniem struktury języka SQL, są osobnymi programami przetwarzającymi dane na poziomie bazy danych.
Jednak by wgłębić się w tą tematykę polecam inną lekturę.

Zatem jakie mechanizmy pozwalają na właśnie takie działanie transakcji? Temat ten omówi kolejny rozdział.

2. Jak działają?

Zasada działania transakcji opiera się na trzech elementach, niejako fundamentach.

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Grzegorz (MajareQ) Karwaszewski, dodany: 19.04.2009 19:47, tagi: internet, sql

Transact-SQL traktuje KAŻDE wyrażenie SQL jako osobną transakcję. Co odróżnia go znacznie od Oracle.
Transact-SQL WYMAGA deklarowania każdej transakcji. Ku temu służą nam słowa kluczowe: BEGIN, COMMIT, SAVE i ROLLBACK.


Możemy wycofać transakcję do określonego punktu dzięki opcji nadawania nazw każdej transakcji i tworzenia tz.punktów pośrednich.
Nie ma jednak możliwość nadawania nazw transakcjom i punktom pośrednim znajdującym się wewnątrz zapętlonej transakcji.

BEGIN BEGIN {TRAN | TRANSACTION} [nazwa] Rozpoczynanie transakcji (można pisać w skrócie TRAN). Można nadawać nazwy.
SAVE SAVE {TRAN | TRANSACTION} nazwa_punktu Zapisuje stan bieżącej transakcji w określonym miejscu jako punkt pośredni. Dzięki temu można wycofywać podzbiory zapytań. Podanie nazwy jest konieczne.
COMMIT COMMIT {TRAN | TRANSACTION | WORK} [nazwa_transakcji] Kończy transakcję i zapisuje w bazie wszystkie zmiany wprowadzone przez zapytania zamykanej transakcji. Oznacza powrót do AUTOCOMMIT, trwający do momentu rozpoczęcia kolejnej transakcji. Wszystkie parametry w składni oprócz słowa kluczowego są parametrami opcjonalnymi. TRANS TRANSACTION i WORK sa synonimami. Nazwy transakcji nie trzeba podawać, lecz należy jeśli chcemy zakończyć całą zewnętrzną transakcję a nie najmłodszą w zapętleniu.
ROLLBACK ROLLBACK {TRAN | TRANSACTION | WORK} [nazwa_transakcji | nazwa punktu] Wycofuje wszystkie zmiany do ostatniego punktu pośredniego lub gdy go brak do początku transakcji, zależnie od tego czy podamy nazwę. Jeśli nie to nastąpi powrót do stanu przed rozpoczęciem transakcji. To samo tyczy się transakcji zagnieżdżonej.
Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.