środa, 28 września 2016

MySQL PART IV: zapytania INSERT INTO oraz UPDATE



Hejo,

Pora pochłonąć kolejną dawkę przydatnej wiedzy!

Wcześniej poznaliśmy klauzulę wybierz z bazy, czyli zapytania wyszukujące proste oraz złożone:

SELECT FROM

Dzisiaj popracujemy z nową klauzulą, a mianowicie

INSERT INTO

czyli wstaw do bazy.

Podmianka starej wartości na nową będzie zaś obrazowana klauzulą

UPDATE

Zapytania INSERT używamy np. podczas rejestracji nowych użytkowników forum internetowego, sklepu internetowego, konta bankowego etc.

UPDATE używamy np. podczas edycji profilu danego użytkownika w danym serwisie internetowym :) Do dzieła!

########################

Jak napisać zapytanie, które zaktualizuje nazwisko jednej z klientek księgarni internetowej?

UPDATE klienci (nazwa naszej tabeli) SET (z ang. ustaw, btw. wiecie, że słowo "set" posiada 430 znaczeń? Słowo "set" to najdłuższy wpis w słowniku, złożony z 60.000 słów i jest to oficjalny rekord księgi Guinnessa w ilości znaczeń pojedyńczego słowa w j. angielskim) nazwisko="Psikuta" (tak, zmieniamy właśnie na to nazwisko) WHERE idklienta=4

Gotowy kod będzie wyglądać w taki sposób (pozwoliłem sobie też zmienić imię, bo czemu nie? przy okazji widzicie, że aktualizować można więcej niż jedno pole w jednej linii kodu):




I teraz uwaga! Pamiętajmy o klauzuli WHERE! Jeśli nie wyszczególnimy rekordu, możemy utracić nazwiska wszystkie w kolumnie! Nieważne ile rekordów będzie w kolumnie (może być ich nawet milion - w moment wszystkie pójdą w cholerę, jeśli nie określimy dokładnie, co chcemy zmienić). Wyobraź sobie, że usuwasz teraz milion maili miliona użytkowników, przez które logują się oni do Twojej bazy.. Czaisz te straty? WNIOSEK? Z ZAPYTANIAMI UPDATE NALEŻY UWAŻAĆ! No i robić dumpa bazy przed każdą operacją aktualizacji ; )

Okay, pora na proste zadanka z aktualizowania.

Zmieniamy id klienta nr. 3 na wartość 1:

UPDATE klienci SET idklienta=1 WHERE idklienta=3 (????????)

Prawda, że proste? Niestety, MySQL nie przepuści tych danych ponieważ właśnie chcieliśmy namieszać w tabeli, która jest PRIMARY KEYEM, z auto inkrementacją oraz niepowtarzającymi się rekordami (duplikatami wartości pól). Tabela utraciłaby spójność, gdybyśmy mieli dwa klucze z nr. 1 i sam ten fakt jest nielogiczny: )

Właśnie zapoznaliśmy się z mechanizmem ochrony klucza podstawowego : ) To zapytanie zadziałałoby tylko wtedy, gdyby w bazie nie znajdował się żaden rekord o ID klienta równym 1 : ) Tylko i tylko wtedy :) 

Kolejne polecenie:

Zwiększ cenę wszystkich książek znajdujących się w bazie o 10% : ) 

Lecimy z zadankiem:

UPDATE ksiazki SET cena=cena+cena*0,1

lub

UPDATE ksiazki SET cena=cena*1,1 

Należy jednak zwrócić uwagę na to, że nowo powstałe ceny będą posiadać trzy miejsca po przecinku, a przecież grosz wyrażamy jako 1/100, prawda? Na szczęście w MySQL jest odpowiednia komenda o nazwie

ROUND()

Bardzo podobna występuję również w PHP : ) Zatem:

UPDATE ksiazki SET cena=ROUND(cena*1.1) 

Taki zapis zaokrągli nam domyślnie do liczby całkowitej, a my przy walucie chcemy przecież mieć dwa miejsca po przecinku :) Zatem dodajemy do kodu jeszcze coś.

Składnia:

ROUND(co_zaokrąglamy, do_ilu_miejsc)

zatem:

UPDATE ksiazki SET cena=ROUND(cena*1.1,2) 

TADAM!~!

Kolejne zapytanie brzmi już ciężej: Mamy zmniejszyć cenę najdroższej książki o 10 zł : )

Logicznie zaczynamy od:

UPDATE ksiazki SET cena=cena-10 

i teraz dodajemy znaną nam już komendę, która wyszuka nam interesującą nas książkę:

UPDATE ksiazki SET cena=cena-10 ORDER BY cena DESC LIMIT 1 

Weź pod uwagę, że ograniczyliśmy się tylko do jednego wyboru (LIMIT 1), gdybyśmy wpisali tam 3 to wszystkie 3 najwyższe ceny poszłyby w dół, każda o 10 zł. Jeśli powtórzylibyśmy to pytanie ponownie to logicznie rzecz biorąc zmieni się już ceną innej książki, która pewnie będzie teraz najwyższa. Magia.



A teraz zmieńmy imię i nazwisko klientki Anny Kareniny (idklienta=10) na wartość: Joanna Dostojewska. Jedziemy z kodem:

UPDATE klienci SET imie="Joanna", nazwisko="Dostojewska" WHERE idklienta=10


Zmień status zamówień nr 4 i 5 na status "wyslano". No to jedziemy z tym koksem:

UPDATE zamowienia SET status="wyslano" WHERE idzamowienia="4" OR idzamowienia="5"

lub

UPDATE zamowienia SET status="wyslano" WHERE idzamowienia BETWEEN 4 AND 5

####################

Pora na INSERT INTO : )

W naszym serwisie rejestruje się nowy użytkownik. Co się musi stać z kodem, żeby jego dane były zapisane na serwerze?

Dodajemy klienta: Franciszek Janowski z Chorzowa

Zaczynamy:

INSTERT INTO (włóż do) klienci VALUES (wartości) (NULL*, "Franciszek", "Janowski", "Chorzów") - w nawiasie znajdują się kolejne wartości, jakie wpisze MySQL na podstawie naszego kodu do tabeli klienci. Ważnym i niezbędnym jest, aby dane były wypisane w odpowiedniej kolejności od lewej do prawej.

* - NULL oznacza wartość pustą. W tym przypadku dajemy wartość pustą, ponieważ pierwsza z kolumn o nazwie idklienta jest auto inkrementowana. Oznacza to, że nie musimy i wręcz nie powinniśmy ustalać ręcznie, jaki numer id ma dostać nowy klient. Silnik MySQL przypisze tą wartość automatycznie.

A teraz dodajemy do bazy nowe zamówienie:

Artur Rutkowski kupił książkę o nazwie "HTML5. Tworzenie witryn"

W tabeli klienci Rutkowski ma idklienta=7, w tabeli książki książka o nazwie "HTML5. Tworzenie witryn" ma idksiazki=3 : )

Zróbmy to jednak na odwrót, po hipstersku, w tej kolejności:

idzamowienia, data, status, idklienta, idksiazki

Tak,tylko po to, żeby pokazać, że jeśli się nam chce to możemy ręcznie ustawić wartości tak, by wkładać je nie od lewej do prawej, tylko np. od tyłu :)

INSTERT INTO zamowienia (idzamowienia, data, status, idklienta, idksiazki) ( tutaj właśnie podajemy kolejność z jaką będziemy wstawiać dane, oczywiście nazwy te muszą pokrywać się z nazwami kolumn w bazie) VALUES (NULL, - bo silnik MySQL sam przydzieli tą wartość na zasadzie autoinkrementacji, ,"2016-01-01", "oczekiwanie", 7, - bo Rutkowski ma takie ID w bazie, 3, - bo ta konkretna książka ma taki nr id w bazie)

Zapytanie bez mojego tłumaczenia wygląda tak:

INSERT INTO zamowienia (idzamowienia, data, status, idklienta, idksiazki) VALUES (NULL, "2016-01-01", "oczekiwanie", 7, 3)

Kolejne zapytanie to: Wstaw do bazy książkę o tytule: "Symfonia C++" autora o nazwisku "Grębosz" ale nie wstawiaj jeszcze imienia autora oraz ceny książki.

INSERT INTO ksiazki (idksiazki, nazwiskoautora, tytul) VALUES (NULL, "Grębosz", "Symfonia C++")




Jak widać język SQL jest elastyczny - możesz uzupełniać bazę o niepełne rekordy, możesz również zmieniać kolejność wstawianych danych.

Kolejne polecenie: Dodaj dwóch nowych klientów za pomocą JEDNEGO zapytania (zachowaj oryginalną kolejność kolumn oraz wstaw kompletny rekord):

INSERT INTO klienci VALUES (NULL, "Merlin", "Monroe", "Los Angeles"), (NULL, "John", "Wayne", "Los Angeles")

Tak, to wygląda tak prosto.. Używamy przecinka jako sygnalizującego maszynie o końcu wartości, bo przed klauzulą WHERE używamy przecinków, a tutaj na dobrą sprawę w ogóle jej nie ma : )

Ostatnie dzisiejsze zapytanie:

Wstaw nową osobę do bazy używając alternatywnego zapisu z klauzulą SET:

INSERT INTO klienci (początek bez zmian) SET idklienta=NULL, imie="Steve", nazwisko="McQueen", miejscowosc="Los Angeles" 

TADAM : ) Składnia równie skuteczna ale nieco mniej ładniejsza, niźli z klauzulą VALUES :) No i wolałbym kojarzyć SET tylko z klauzulą UPDATE'u. Co kto lubi : )

Dzięki! Jak zawsze polecam serdecznie lekcję Mirosława Zelenta:



F.

PS. Pod spodem zamieszczam jeszcze raz podsumowanie tego, co pisałem powyżej, wzięte bezpośrednio z lekcji Mirosława Zelenta :)



















wtorek, 27 września 2016

MySQL PART III: zadania dot. zaawansowanego wyszukiwania informacji



Hejo ponowie,

Tak, jak pisałem wcześniej, zrobiłem sobie zadanko domowe polegające na wyciąganiu informacji z bazy danych zbudowanej z trzech tabel powiązanych ze sobą dwiema relacjami. To, jak rozwiązałem każde z zadań opiszę poniżej. Enjoy!

Lista zadań oraz baza danych została stworzona przez wielokrotnie wspominanego tutaj Mirosława Zelenta.

Lista zadań wyglądała następująco:


A stworzona baza danych, zaimportowana już przeze mnie na mój zdalny serwer na localhost/phpmyadmin/ prezentowała się tak (wybaczcie tylko jeden shot, uznałem, że bez sensu będzie pokazywać zestaw trzech tabel, skoro sami możecie wykonać to ćwiczenie poprzez blog Mirosława :) ):



Okay, zadanie pierwsze i jego rozwiązanie wyglądało następująco: 


Interesowało nas imię i nazwisko klienta, którego numer przypisany przez system do tabeli klienci w bazie danych wynosił 4. Prosta sprawa, myślę, że tego kodu nie muszę tłumaczyć : )

Zadanie drugie i jego rozwiązanie to: 



 Interesowały nas wszelkie informacje zawarte w tabeli auta dot. samochodów z rocznika 2010. Prosta sprawa, jak wyżej :)

Zadanie trzecie i jego rozwiązanie to: 



Interesowały nas wszystkie dane z tabeli auta, które dotyczyły marki Ford. Prościej być nie mogło.

Zadanie czwarte i jego rozwiązanie to: 


Interesowały nasz wszystkie auta, których numer przypisany do tabeli auta (identyfication number) mieścił się w zakresie od 2 do 4. Prosta sprawa, jeśli zna się polecenie BETWEEN. Można było to również zapisać w taki sposób:

SELECT * FROM auta WHERE idauta>=2 AND idauta<=4 

Nadal, opcja BETWEEN jest bardziej seksi ;)

Zadanie piąte i jego rozwiązanie to:



Interesował nas wykaz imienia oraz nazwiska klienta/ów z Katowic mieszkających na ulicy Rolnej. Również fajna sprawa, jeśli pamiętało się o zastosowaniu polecenia LIKE oraz użyło się %% przy nazwie ulicy, które to mówią serwerowi o tym, że przed i po nazwie ulicy może być również tekst :)

Zadanie szóste i jego rozwiązanie to:



Interesowała nas marka, model oraz ubezpieczenie (tak, wiem, że nie ale chciałem poznać jego wartość, meh) auta, którego ubezpieczenie będzie najwyższe. Tutaj oczywiście kłania się sortowanie ORDER BY oraz ustawienie wartości malejącej DESC, jak i limitowanie wyświetlanych wyników do jednego rekordu (tego tłumaczyć już nie muszę, co?)

Zadanie siódme i jego rozwiązanie to:



Interesowała nas informacja o numerze auta, jego modelu, marce oraz dacie wypożyczenia wg. dat. Kod jest logiczny, warto zaznaczyć, iż musieliśmy nakreślić tutaj maszynie pierwszą relację pomiędzy tabelami auta oraz wypozyczenia, a kolumną, jaka stanowiła relację w tych dwóch tabelach to oczywiście idauta :) Szeregowaliśmy otrzymane rekordy rosnąco :)

Zadanie ósme i jego rozwiązanie to:



Interesowali nas klienci z imienia i nazwiska, którzy wypożyczyli kiedykolwiek auto o numerze identyfikacyjnym 1. Warto zaznaczyć, iż 1 jako wartość cyfry stałej INT nie musiałem umieszczać w nawiasie :) Nawiązałem tutaj również dwie relacje, tak, aby maszyna nie zwróciła nam wyników z kosmosu. Jakie to relacje? Przeczytacie sobie z kodu, ruszyć mózgi! : )

Zadanie dziewiąte i jego rozwiązanie to:



Interesowała nas marka, model auta, które było wypożyczone przez klienta o numerze identyfikacyjnym 4. Sprawa ma się podobnie, jak wyżej, nakreślone są obydwie relacje pomiędzy tabelami klienci, a wypożyczenia oraz auta, a wypożyczenia. Prosty ale jakże efektowny kod ^_^

Zadanie dziesiąte, a zarazem ostatnie to:



Interesowała nas marka, model auta, które było wypożyczane kiedykolwiek przez klienta o nazwisku Pastewniak. Sprawa wyglądała podobnie, jak wyżej, ponownie nakreślaliśmy dwie relacje pomiędzy trzema tabelami danych ale uściśliliśmy wynik do tego jednego, konkretnego nazwiska, którego dane były przetrzymywane w tabeli o nazwie klienci :)

I to wszystko : )

Nie będę ukrywać, że obsługa MySQL wchodzi mi do głowy ultra szybko ale myślę, że wynika to ze specyfiki tego programu - komendy wpisuje się praktycznie tak, jakbyśmy pisali po angielsku, a jedyne, co musimy potrafić to dokładne i logiczne zastanowienie się nad stawianymi przez nas pytaniami odnośnie infa, jakie chcemy wyciągnąć : )

Polecam pobawić się samemu, uważam, że to fajny trening dla naszej głowy. W sam raz na tak chłodny wieczór, jak ten dzisiejszy. Kurde, chyba brzmię jak nerd, co nie?

Pozdrawiam cieplutko, kochane mys1e_pys1e <3

F.

MySQL PART II: i zapytania złożone...



Kolejna lekcja z zapytaniami złożonymi w "SIKUŁELU" za mną : )

Na początek kolejne fajne pojęcie związane z MySQLem, a bardzo przydatne podczas używania ORDER BY:

LIMIT 1* - *cyfra oznacza liczbę wyników do jakiej ograniczymy wyszukiwanie. Limity są szczególnie użyteczne, jeżeli układamy bazę danych np. ze względu na cenę i interesuje nas wykaz tylko jednej, najdroższej pozycji etc.

Okay, a teraz pojęcia i akcje związane z zapytaniami związanymi z łączeniem tabel, czyli dzisiejszego dania głównego:

Zapytanie złożone SELECT będzie mieć miejsce wtedy (jak się pewnie domyślasz), kiedy dane, jakie będziemy chcieli wyciągnąć z bazy znajdują się w więcej niż jednej tabeli. I to wcale nie będzie takie proste, ponieważ pomiędzy tabelami istnieją relacje.

Przy złożonych SELECTACH schemat wygląda następująco:

tabela.kolumna = czyli nazwatabeli.konkretnakolumna. przykład:

SELECT klienci.imie, klienci.nazwisko, zamowienia.idzamowienia, zamowienia.data (wybieramy konkretne dane z tabel klienci oraz z tabeli zamówienia, a z nich konkretne nazwy kolumn - kolejność dowolna, poszczególne zapytania oddzielamy zawsze przecinkiem) FROM klienci, zamówienia (tutaj określamy skąd te dane będą pochodzić - logicznie z tabel, z których wybieraliśmy konkretne informacje). Cały zapis bez tłumaczenia wygląda tak:



I teraz najważniejsze i trochę komplikujące sprawę info. Podczas tworzenia zapytań złożonych musisz dostarczyć listę wszystkich relacji, które zachodzą pomiędzy używanymi w tym zapytaniu tabelami!

Programista jest zobowiązany dostarczyć listę wszystkich relacji zachodzących pomiędzy używanymi w zapytaniu tabelami.

Tę listę należy umieścić po klauzuli WHERE..

Niestety.. Im więcej używamy w zapytaniu tabel, tym dłuższa będzie lista relacji :< Zapytania złożone, co nie?

Poprawmy zatem przykład z góry:



Raz jeszcze: po klauzuli WHERE musimy wypisać wszystkie relacje zachodzące pomiędzy używanymi przez nas w zapytaniu złożonym tabelami! Również wcale nie musi być tak, że po klauzuli WHERE kolumny, którym przypisujemy relacje muszą mieć takie same nazwy. Nie - nie muszą, bo i tak programista jest zobowiązany podać listę relacji. Konstrukcja tabela.kolumna jest opcjonalna! Jeżeli pośród wszystkich tabel występuje tylko jedna kolumna o nazwie 'x' to możemy ją zapisać jako "SELECT x" i wtedy MySQL domyśli się, że chodzi dokładnie o tę kolumnę. Gorzej, jeśli w paru tabelach występuje parę kolumn o tej samej nazwie - wtedy nie ma zmiłuj, piszesz schemat tabela.kolumna : )

I teraz trik. Zapytania złożone mają to do siebie, że mogą być długie. Szczęśliwie - możemy użyć tzw. "asliasów" (alias = przezwisko), by je skrócić. Np. zamiast pisać klienci.zamowienia można zapisać k.z (coś jak M jak Miłość).

Wystarczy te aliasy odpowiednio nadać i wtedy ten sam wpis będzie wyglądać w taki sposób:

SELECT k.imie, k.nazwisko, z.idzamowienia, z.data FROM klienci AS k, zamowienia AS z (tak, wlasnie tutaj nadalismy nasze aliasy) WHERE k.idklienta=z.idklienta

PIĘKNY KOMPROMIS : ) Należy jednak pamiętać, by używać stale raz nadanych aliasów. Złapałem się na tym, że jeśli w jednej linii kodu będziemy używać aliasów na przemian z pełnymi nazwami to nasze zapytanie nie da żadnego wyniku i maszyna zgłupieje. Tak czy siak, to końcowa optymalizacja działającego zapytania.

Co najważniejsze w pracy z tabelami, a już teraz rzuca mi się w oczy to DOKŁADNOŚĆ oraz LOGICZNE ZROZUMIENIE ZADAWANYCH PYTAŃ. Posiadanie wiedzy i narzędzi to jedno, a logiczne zrozumienie danego polecenia to drugie. Warto odpowiadać na zadane pytanie po kolei realizując już zadawane pytanie w formie kodu MySQL. I tak:

Wyselektuj imiona i nazwiska osób, które zamówiły kiedykolwiek książkę nr 2?

Wiemy, że mamy tutaj styczność z dwiema tabelami - tabelą, która będzie zawierać dane o klientach oraz tabelą, która będzie zawierać dane o zamówieniach. Piszmy już kod czytając pytanie:

Wiemy, że na pewno będzie nam potrzebne imię oraz nazwisko klienta, które będzie logicznie zawierać się w tabeli klienci, także: 

SELECT klienci.imie, klienci.nazwisko FROM klienci 

teraz dodajmy do tego informację, iż potrzebujemy z drugiej tabeli informacjęo książce nr dwa, zatem dodajmy magię do naszego kodu:

SELECT klienci.imie, klienci.nazwisko FROM klienci, zamowienia WHERE zamowienia.idksiazki = 2

Mamy teraz opisany warunek, wg. którego imię i nazwisko z tabeli klienci ma się wyświetlić w wynikach. Musimy jednak zaprogramować też relację pomiędzy tymi tabelami, także do kodu dodajemy już warunek AND (po WHERE nigdy nie piszemy przecinków!)

SELECT klienci.imie, klienci.nazwisko FROM klienci, zamowienia WHERE zamowienia.idksiazki = 2 AND klienci.idklienta=zamowienia.idklienta

Teraz jeszcze zoptymalizujmy kod aliasami:

SELECT k.imie, k.nazwisko FROM klienci AS k, zamowienia AS z WHERE z.idksiazki = 2 AND k.idklienta=z.idklienta

TADAM~! :)

Kolejne pytanie to: Jakie książki (tytuł, autor) zamówiła osoba: Jan Nowak?

Okay, sprawa wygląda następująco - najpierw w tabeli zamówienia sprawdzam sobie nr id klienta odpowiadającego Janowi Nowakowi i jest to cyfra nr. 2. Skąd takie ułatwienie? Ano, jeżeli klient zaloguje się na panel klienta to serwer z automatu przypisze mu jego id z tabeli klienci : ) Jedziemy z kodem!

Potrzebujemy tytułu oraz autora książki, także:

SELECT ksiazki.tytul, ksiazki.imieautora, ksiazki.nazwiskoautora FROM ksiazki, zamowienia WHERE zamowienia.idklienta=2 AND zamowienia.idksiazki=ksiazki.idksiazki

Teraz przejdźmy to wytłumaczenia reszty kodu.

SELECTEM wybraliśmy informację, jakie ma nam zwrócić serwer - tytuł, imię i nazwisko autora z tabeli książki (która posiada informację o książkach). Dane pobieraliśmy z (FROM) tabel książki oraz zamówienia (no bo klient musi wiedzieć co zamawiał, a te informację zawierają się w tej tabeli) oraz określiliśmy parametr gdzie (WHERE) zamowienia.idklienta=2 (oznaczamy tutaj Jana Nowaka, któremu system przydzielił już taki nr ID w tabeli klienci ale również ta kolumna zawarta jest przecież w ID zamówienia na zasadzie relacji pomiędzy nimi - logiczne) oraz opisaliśmy relację pomiędzy id książki na zasadzie porównania ich z tabelami zawierającymi info o zamówieniach oraz książkach. Mam nadzieję, że mnie rozumiesz? Kod oczywiście można zoptymalizować aliasami, gdzie ostatecznie będzie wyglądać tak:

SELECT k.tytul, k.imieautora, k.nazwiskoautora FROM ksiazki AS k, zamowienia AS z WHERE z.idklienta=2 AND z.idksiazki=k.idksiazki

No!

To teraz najtrudniejsze zadanie, bo będzie ono bazować na informacjach zawartych w trzech tabelach, pomiędzy którymi występują dwie relacje.

Pytanie brzmi: Zamówienia dokonane przez osoby o nazwisku Rutkowski ułożone wg daty od najpóźniej dokonanych (imię i nazwisko osoby zamawiającej, id, datę i status zamówienia, tytuł zamówionej książki)

No to znowu zadajemy sobie pytanie jakich informacji będziemy potrzebować i na bieżąco wklepywać kod:

SELECT klienci.imie, klienci.nazwisko, zamowienia.idzamowienia, zamowienia.data, zamowienia.status, ksiazki.tytul (tutaj określamy jakie informacje ma nam zwrócić serwer, to jest zrozumiałe) FROM klienci, zamowienia, ksiazki (tutaj określamy z jakich tabel serwer ma czerpać informacje. w tym przypadku będą to trzy tabele, ponieważ informacje jakich potrzebujemy zawierają się po trochu w każdej) WHERE klienci.nazwisko="Rutkowski" (tutaj określamy warunek, iż interesują nas tylko te rekordy w których występuję nazwisko Rutkowski z tabeli klienci) AND zamowienia.idklienta=klienci.idklienta (tutaj określamy relację pomiędzy informacjami z tabeli zamówienia oraz z tabeli klienci. wspólną kolumną będzie oczywiście idklienta) AND ksiazki.idksiazki=zamowienia.idksiazki (tutaj określamy drugą relację analogicznie, pomiędzy zamówieniami książki - id książki oraz samą nazwą książki, która jest tą samą wartością ale w tabeli książki i jest tam oczywiście PRIMARY KEYEM) ORDER BY zamowienia.data DESC (tutaj już porządkujemy ciąg wyświetlonych nam rekordów wg. daty zamówienia malejąco).

Kod przed optymalizacją wyglądać będzie tak:



Nie chce mi się go optymalizować :P

W ramach treningu zrobię sobie wieczorem kolejne fajne zadania na bazach danych, tak, by przed spaniem mózg znowu mi wyparował. W ramach mojej nauki korzystałem z niezawodnego vloga Mirosława Zelenta  :)



Pozdrówki!

poniedziałek, 26 września 2016

MYSQL PART I: Moje pierwsze zapytania wyszukujące w bazach danych



Hejo,

Jestem zadowolony, MySQL okazuje się póki co ultra prostym i intuicyjnym systemem zarządzania bazami danych. Podzielę się szybko tym, co zanotowałem.

Bawiłem się na serwerze zdalnym, localhoście, przy pomocy programu opensource'owego XAMPP. Zbudowałem na nim swoją pierwszą bazę danych, skonfigurowałem serwer, a wszystko po to, by nauczyć się pierwszych komend wyszukowania w 'eskłelu'.

Oto, co udało mi się nauczyć i wydobyć. Wszystko jest ultra intuicyjnę, a w bonusie na końcu zamieszczę poradnik z którego przyszło mi się uczyć, a który serdecznie polecam.

Widok panelu administracyjnego mojego serwera bazy danych, gdzie tworzyłem swoją pierwsza bazę na zasadzie pytań egzaminacyjnych.

localhost/phpmyadmin okazał się rozwiązaniem na tyle intuicyjnym, że nie miałem z nim większych problemów : )

Nauczyłem się tworzyć tabelę, a w niej kolumny, rekordy, nadawać wartości poszczególnym polom, opisywać to, w jaki sposób te wartości będą opisywane etc.

Przed powstaniem pierwszego rekordu, misiaczki. 

Po tych krokach mogłem przejść bezpośrednio do zabawy wyszukiwania poszczególnych wartości, sortowania bazy danych, wyszukiwania zaawansowanego, a to wszystko za pomocą prostej linii kodu  )

Pozwoliłem zapisać sobie wszystkie najważniejsze imho informację.

DBMS = Database Management System lub po polskiemu - System zarządzania bazą danych = SZBD

klienci DBMS to: MySQL, PostgreSQL, Firebird oraz Oracle DATABASE.

SQL = S

Baza danych to uporządkowany zbiór danych (informacji) zazwyczaj zorganizowany jako zestaw tabel powiązanych relacjami.

Przykłady bazy danych to: książka telefoniczna, katalog bibliotek, użytkownicy FB itd.

Baza danych zawsze składa się z tabel! 

Tabele złożone są z wierszy oraz kolumn.

Tabele to nic innego, jak pojemnik na dane. Kolekcja powiązanych informacji, przedstawiana zwykle jako układ poziomych wierszy i pionowych kolumn. W jednej bazie danych może być ich bardzo wiele i wówczas występują między nimi powiązania logiczne (relacje) 

Rekord (krotka) to pojedynczy wiersz w tabeli, czyli zestaw pól w niej wystepujących Np. może być to zestaw cech danego auta.

Pole (atrybut) to część tabeli przechowująca jednostkowe dane np. nazwisko konkretnej osoby w tabeli

REKORD NIE MUSI ZAWIERAĆ WSZYSTKICH CECH OBIEKTU

Klucz podstawowy (PRIMARY KEY) lub też klucz główny to jedno lub więcej pól, których wartośc jednoznacznie identyfikuje każdy rekord w tabeli. Taka cecha klucza nazwana jest unikatowością.

W MySQL wykorzystuje się model relacyjny bazy danych. W modelu tym dzielimy dane w bazie na tabele i definiujemy w tabelach pola będące tzw. kluczami. Następnie określa się relacje istniejące pomiędzy tabelami, które łączą dane w logiczną całość, zrozumiała dla osób korzystających z bazy.

Relacja - powiązania logiczne wystepujące pomiędzy dwoma tabelami realizowane za pomocą klucza podstawowego i klucza obcego albo specjalnej tabeli (tabela łącząca). Każda relacja opisana jest przez typ relacji. Rozróżniamy następujące typy relacji: jeden-do-jednego, jeden-do-wielu, wiele-do-wielu : )

Typy danych - w każdej kolumnie tabeli w bazie przechowywane są dane jednakowego typu:

ZAPISY TYPU DANYCH w MYSQL : ) 

INT - liczba całkowita (zajmuje 4 bajty w pamięci RAM) z zakresu od -2.147.483.648 do 2.147.483.647 (liczba można komfortowo ze sobą porównywać)

CHAR[x] - pole przechowujące od 0 do max. 255 znaków

VARCHAR[x] - pole tekstowe o zmiennej długości

FLOAT - liczba rzeczywista ale zmiennoprzecinkowa (np. 3,14)

TEXT - napis (łańcuch znaków)

LONGTEXT - tekst o długim łancuchu znaków

DATE - przechowuje datę w formacie RRRR_MM_DD

TIME - format GG:MM:SS

A_I - AUTO INCEREMENT - automatyczna inkrementacja (++) - wygodna sprawa :) mysql sam policzy, który rekord wstawiamy do bazy : ) 

SQL = Structured Query Language - strukturalny język zapytań (kierowany do bazy danych ;) )

query = kwerenda* czyli zapytanie do bazy - czyli komendy do administrowani ich zawartością : ) 

Rodzaje kwerend: 

- wstawiające, 
- wyszukujące,
- zmieniające,
- usuwające,
- zmieniające strukturę tabel albo bazy,

Funkcja PHP mysql_query() umożliwia skryptowi PHP wysłanie kwerendy do bazy: mysql_query(ZAPYTANIE SQL);
Funkcja zdeprecjonowana od PHP w wersji 5.5.0 została zasąpiona mysqli_query lub PDO::query 

podstawowe zapytania wyszukujące

SELECT (wybierz) * (gwiazdka oznacza wybierz wszystko - w tym przypadku wszystkie kolumny z tabeli) FROM (z) pytania (nazwa mojej bazy danych) 

SELECT tresc FROM pytania - wybierz tylko kolumnę treść z całej tabeli zapytania.

Jeżeli chcemy wbierać kilka nazw kolumn, to analogicznie wybieramy wszystko po przecinku : ) 

czyli 

SELECT tresc, odpa, odpb (ostatnie bez przecinka) etc FROM pytania

Jeżeli chcemy wybrać konkretny rekord z określonym przez nas warunkiem (np. id - w tym przypadku będzie to nasz primary key z numerem 15) to sprawa jest prosta. 

SELECT (WYBIERZ) * (WSZYSTKO) FROM (Z TABELI) pytania WHERE (SŁOWO KLUCZ w tym przypadku czyli "GDZIE) id=15 (nasze id równe jest 15) (tutaj ciekawostka - tutaj nadanie wartości wyrażane jest pojedynczym operatorem porównania "=", w C++ nadanie wartosci wyrażamy dwoma znakami równości "=="). 

Podobna sprawa z C++ w MySQL - wszystkie pola tekstowe w zapytaniach (te z warotścią text) umieszamy w cudzysłowiach, tak, aby maszyna wiedziała, kiedy tekst się kończy, a kiedy się zaczyna.

Dajmy na to, że szukamy tylko tylko rekordów, w których poprawną odpowiedzią będzie odpowiedź A. 

stąd logicznie

SELECT * FROM pytania WHERE answer="a" 

dla odmiany, jeśli będziemy wyszukiwać wartości, które są liczbamy całkowitymi (INT) albo też liczbami po przecinku (przyda się do budowania baz danych np. sklepów internetowych z cenami 12,99 zł) (FLOAT) nie musimy wstawiać w ramy cudzysłowiu ale również możemy - wartości podczas przypisywania zawsze będą odczytane przez maszynę w ramach "", aczkolwiek lepiej liczby całkowite lub nie zapisywać bez "" dla przejrzystości zapytań : ) 

spójniki logiczne są dwa: I oraz LUB (AND, OR) 

Jezeli dwa lub więcej warunków ma być spełnionych używamy and o zapisie "&&" - warunek1 && warunek2 to już wiemy z C++, w MySQL wystarczy zapisać to endem znanym z C++ (&&) lub po prostu komendą... "AND" :D (po co utrudniać sobie życie?)
Jeżeli jeden warunek z wielu ma być spełniony to używamy zapisu warunek1 || warunek2 albo słowo "OR" :) 

Reasumując - AND = część wspólna wyników (koniunkcja), a OR = suma (alternatywa) jeśli ktoś lubi porównania matematyczne : ) 

Jak zrobić sortowanie? : ) komendą ORDER BY (order - porządek by - według) 
Sortować możemy malejąco, bądź rosnąco i teraz:

ASC = ascending (rosnąco) i dodajemy tę komendę już po tym, jak wybierzemy daną wartość do posortowania np: 

SELECT * FROM pytania ORDER BY tresc ASC 

DESC = descending (malejąco) i reszta analogicznie, jak w przypadku ascending : )

Jeżeli nie uszczególnimy kierunku sortowania to domyślnie sortować będziemy rosnąco : ) 

Oczywiście możemy używać warunków matematycznych, jeśli chcielibyśmy wybrać tylko te dane bazy danych, których wartości PRIMARY KEY sa większe od 10 ale mniejsze od 15 to nic trudnego - zapiszemy to w ten sposób:

SELECT id, tresc FROM pytania WHERE id>=10 AND id<=15 TADAM!

Jest jednak specjalne słowo kluczowe dla przedziałów w MySQL! : ) i tak, również z angielskiego ta komenda to BETWEEN (pomiędzy), zapisujemy to wtedy tak:

SELECT id, tresc FROM pytania WHERE id BETWEEN 10 AND 15 TADAM2! - zadziała jak poprzednio ale taki zapis jest bardzej pro ^_^

Jeśli chcemy wyszukać po pierwszych słowach w treści to również nic trudnego! 

SELECT * FROM pytania WHERE tresc LIKE (podobny do, nie myl z lajkiem z fb) "Jak%" - symbol procenta oznacza to, że po treści Jak może znajdować się obojętnie jaka treść. Dlaczego nie używamy do tego gwiazdki "*"? Ano dlatego, że gwiazdka jest już zajeta na początku pierwszej linii przy SELECT :) 

Analogicznie, jeśli chcemy wyszukać wszystkich rekordów ze słowem C++ w bazie danych to użyjemy komendy: 

SELECT * FROM pytania WHERE tresc LIKE "%C++%" - polecenie znajdzie nam wszystkie spełniające kryteria rekordy ale tylko w treści. Jeśli chcemy to rozwinąć to komendę będziemy musieli rozpisać o dodatkowe kryteria i tak:

SELECT * FROM pytania WHERE tresc LIKE "%C++%" OR odpa LIKE "%C++%" OR odpb LIKE "%C++%" i analogicznie : ) 

Idąc tym tropem możemy używać zapytań bardziej ambitnie. Rozszyfrujcie sobie to polecenie: 

SELECT * FROM pytania WHERE (kategoria="programowanie" OR kategoria="systemy operacyjne i sieci") AND rok=2012 

Polecam serdecznie zapoznać się również z TUTORKIEM świetnego Pana M.Z. : )




Pozdrówki! 

F.

środa, 21 września 2016

Mój pierwszy raz z C++




Hejo!

Podobno pierwszy raz nie zawsze jest taki fajny, jak sobie go wyobrażamy. Mój pierwszy raz z C++ nie był tragiczny, aczkolwiek nie będę ukrywać, że wymagał ode mnie skupienia, dokładnego analizowania przekazywanej wiedzy oraz pewnego myślenia abstrakcyjnego.

Okay, żeby nie przedłużać - naukę rozpocząłem z opasłym tomiskiem Jerzego Grębosza "Symfonia C++ Standard". Pan Jerzy jest fizykiem, który dzięki swoim doświadczeniom z kraju, jak i zza granicy podjął się karkołomnego zadania nauki języka C++ zarówno dla początkujących amatorów, jak i doświadczonych programistów. 

Sama książka pisana jest językiem prostym ale wymaga pełnego zaangażowania oraz uwagi. Nie będę opisywać poszczególnych kroków, know-how etc. Podzielę się tym, czego się nauczyłem. Niesprawiedliwością byłoby pisać, że bazuję tylko na książce. Na YT jest mnóstwo fajnych tutoriali, kursów dla początkujących (zarówno po PL, jak i MASAAAA po angielsku). Nie wstawiam żadnych linków, wujek google pomoże Wam bezproblemowo znaleźć poszczególne kursy w ułamku sekundy - dla każdego coś dobrego. 

Okay. Nie wiem jeszcze, jakie będą formy moich postów ale raczej założyłem, że będą to luźne burze mózgów, które pomogą przede wszystkim mi powrócić oraz usystematyzować wiedzę, jaką nabywam. Nie traktuj tego, jako poradnika etc. bo sam jestem prawie tak samo zielony, jak Ty (zakładając, że nie jesteś nerdem).

Na każdej z lekcji wypisuję sobie w swoim słowniczku przydatne wg. mnie pojęcia. Pierwsza tura? Proszę bardzo.

##############################

Mój słownik programistyczny + wolne myśli.

#iostream - załączamy ją na początku kodu, jest to oczywiście biblioteka standardowa zawierająca wiele użytecznych funkcji stosowanych w programach konsolowych. IOstream w nazwie to nic innego jak "intput" oraz "output" (wejście, wyjście), a stream to oczywiście "strumień" (dop. danych).

using namespace std; - biblioteka używa nazw przestrzeni standardowych (std::) - ta linia ułatwia nam znacznie pracę, nie wywierając na nas przymusu wpisywania komendy std:: przed każdą linią kodu (np. przez wyjściem danych na ekran w cout - console output).



IDE - Integrated Develepment Environment - zintegrowane środowisko programistyczne. Konkretnie jest to zestaw zawierający aplikację do edycji plików źródłowych (tekst źródłowy) oraz kompilator (ja rozumiem to jako "rusztowanie", które będzie potrafiło przetłumaczyć język źródłowy na język maszynowy czyt. procesor komputera, tak, by ten mógł go poprawnie zinterpretować i uruchomić (tak, to jest ten sławny kod "zero, jedynkowy"). Kompilator to najważniejszy element IDE! W programie CodeBlock kompilator nazywa się GNU "GCC" i jest podpięty już pod paczkę instalacyjną (przedrostek GNU oznacza licencje, na jakiej kompilator został wypuszczony w świat. Ta sama licencja, co jądro linuksa - ciekawostka.

Debugger - dosłownie, odpluskwiacz. Jest to funkcja, program, która pozwoli nam przetestować działanie naszego programu, który wcześniej zapisaliśmy w języku źródłowym (w tym przypadku w .cpp (C++).

#W samym języku C++ komenda "\n" (od ang. n- nen line!)w określonej funkcji będzie służyć jako wordowskie ENTER (albo komenda <br> w HTML5 ;))! 

#nawiasy klamrowe "{}" będą służyć nam do "spinania" określonej funkcji. Tzn. nawiasami klamrowymi opisujemy zadania dla danej funkcji. Każdą linię kodu zaś kończymy pośrednikiem ";", który jest zwany także teminatorem (i'll be back, hłehłe). 

#komentarze w tekście źródłowym (które będą pomijane przez kompilator) oznaczamy znakami \\ (dlaczego wszystko musi być tutaj w odwrocie do HTML5? :<). Warto stosować komentarze, ponieważ często pozwolą nam one cofnąć się do określonej linii kodu, pozwalając nam szybciej zapoznać się tym, co mieliśmy na myśli ją tworząc (wybaczcie składnie, piszę na gorąco).

#funkcja main to nic innego jak zestaw zadań w tej funkcji do wykonania w naszym programie. 

#zmienne w funkcji main, które właśnie poznaję to: "int" oraz "double". Zmienne te mogą mieć nadawane nazwy. W przykładzie z książki program, jaki będziemy pisać będzie programem, który przelicza wartości stóp angielskiech na metry. I tak w funkcji main () zmienne "int" oraz "double" to kolejno stopy oraz metry, tak, bym mógł łatwo zdefiniować zastosowanie tych zmiennych : ) Należy pamiętac, aby nazwa nie zaczynała się od cyfry! Mogą to być długie znaki oraz podkreślniki ("_"). Odradza się zaczynania nazw od "_" (kompilator może uznać ten znak za zupełnie inną komendę), nie używa się również litery "O", bo jest mylona z cyfrą "O" oraz małej litery "l", bo może być pomylona z cyfrą "1". Reasumując, nazwy, jakie nadajemy są wazne, bo będą odnościć się do naszych obiektów (operatorów = zmiennych oraz stałych). 

Należy pamiętać, że zmienne to nic innego, jak przechowywane dane. Zmienne nazywają się zmiennymi dlatego, że mogą być.. zmienne. Tzn. ich wartość (liczbowa, prawda/fałsz etc.) może się zmieniać wraz z postępującymi działaniami w poszczególnych liniach kodu.

W JĘZYKU C++ KAŻDA NAZWA MUSI ZOSTAĆ ZADEKLAROWANA ZANIM ZOSTANIE UŻYTA! DEKLARACJA MÓWI, JAKIEGO TYPU JEST TO, CO NAZWALIŚMY DANĄ NAZWĄ! a teraz napisz milion razy słowo ZADEKLAROWANA, zadeklarowana, zadeklarowana, zadeklarowana, zadeklarowana, zadeklaro... 

Nazwa zmiennej "int" (od angielskiego integer - liczba całkowita, integralna, niepodzielna) przechowuje wartości liczby rzeczywistej - inaczej liczby zmiennoprzecinkowej. Te zmienne w naszym programie są typu "double" - są to zmienne zmiennoprzecinkowe o podwójnej precyzji, stąd: 

w funkcji main ()

int stopy; - tak określamy typ danej zmiennej
double metry; - podobnie, jak poprzednio.

= - jest to operator przypisania,
== - jest to perator porównania (użyłem go w funkcji if, podczas ćwiczenia z symulatorem bankomatu)
!= - jest to operator mówiący o tym, że coś nie jest czemuś równe. Warto uprościć sobie naszą funkcję, gdzie zamiast kopiować ponownie operator, można użyć zaprzeczenia komendą "else".
&& - operator "i".
|| - spójnik logiczny LUB. bardzo ważny operator mówiący o tym, że jeden z warunków (X)(Y) może być spełniony. Nie mylić go z "&&" ponieważ naraz nie wpiszemy X oraz Y, prawda? 


################################

A teraz, żeby nie było, iż wiedza jest pogrążona w chaosie pozwolę sobie wrzucić printcreeny pierwszych programów, jakie napisałem w Code Blocksie. Są to banały i podstawy, których jednak nie chcę bagatelizować. Wychodzę z założenia, że lepiej gruntownie przelecieć przez podstawy, tak, by w bardziej skomplikowanych operacjach mieć mocny punkt odwołania i na tej podstawie samemu kombinować co jest pięć.

Pierwszy program, jaki napisałem (przy pomocy kursu YT) to proste wyjście informacji cout (console out) na ekran konsoli. Była to prosta wiadomość, która z założenia ma pomóc nam przywitać się ze światem za pomocą języka, którego używamy. 

Hell0_w0rld!


Kod źródłowy mojego pierwszego programu. Używam darmowego IDE - Code::Blocks - wygoogluj sobie. Pobierając pobierz wersję grubszą z kompilatorem!

Po kolei od góry do dołu, od lewej do prawej (w takiej kolejności kompilator przekłada język programistyczny na język maszynowy).

1. W pierwszym wierszu zainkludowaliśmy bibliotekę i(nput)o(utput)stream. Jest to podstawowa biblioteka, która pozwala na podstawowe operacje z kodem źródłowym. 


3. W trzecim wierszu użyłem komendy znacznie upraszczającej mi życie. Zakłada, iż każda z poniższych linii kodu będzie interpretowana przez kompilator jako std:: (pozwala to znacznie skrócić pracę). namespace std:: pozwala poinformować kompilator, że chcemy aby wszystkie funkcje, klasy i szablony należące do przestrzeni nazw nie wymagały przedrostka. Wyraz występujący po tych dwóch słowach kluczowych jest istniejącą nazwą przestrzeni. Dla standardowych bibliotek C++ jest to właśnie std::.

5. Piąty wiersz opisuje nam główną funkcję, jaką będzie wykonywać kompilator. Funkcja ta zwie się main (od ang. "główna"), a jej wartość będzie opisywana w cyfrach niepodzielnych, stałych dzięki operatorowi int. 

6 i 13. Wiersz to nic innego, jak klamry, dzięki którym opisane są "granice" funkcji głównej.

7. cout (consoleout) to nic innego, jak polecenie wyprowadzające informację na ekran, kod jest logiczny i da się go porządkować tak, by był maksymalnie przejrzysty. Do tego za ukośnikami // zamieściłem pomocne mi komentarze. Zwróćcie uwagę, że każde słowo, zdanie, wyraz, które będzie się pokazywać na ekranie konsoli zawiera się w nawiasie, a każdą linię kodu kończymy średnikiem ";". 

Nie mam zamiaru tłumaczyć kodu dalej. Myślę, że dojdziecie do tego sami, zwłaszcza, iż jest to banalnie prosty program, który skutkuje wyprowadzeniem prostej informacji na ekranie konsoli. 

Ach, konsole przypominają mi czasy dzieciństwa <3

Banał, co nie? Jestem po napisaniu paru prostych programów, które opiszę w kolejnych postach. Niemniej już teraz możecie zauważyć, że kod C++ jest bardzo logiczny i przejrzysty. 

W następnym poście pokażę Wam szybko prosty program matematyczny, jaki napisałem, symulator bankomatu, dostępu na serwer oraz jeszcze jeden z wykorzystaniem instrukcji warunkowej if oraz ..else : ) 

Trzymajcie się,

Ja wracam do nauki ^_^

F.



PS. Ach, mały PSIK. Gee - pozdrawiam Ciebie serdecznie, masz zaszczyt być bohaterką mojego pierwszego programu w C++. Meh. 

PSS. Gee, zostawiłaś mi talerz do wylizania? 


wtorek, 20 września 2016

Hejo, gołąbeczki!



Hejo,

Tak, wiem. Z początkiem zawsze jest najgorzej. Zrób pierwszy krok, potem jakoś pójdzie, pierwszy krok zawsze zrobić najtrudniej etc. Wcale nie! Zawsze można zacząć od środka, prawda? Ba! Można nawet zacząć od konkretów, dzięki czemu zaoszczędzimy zarówno Wasz, jak i mój czas : )

Po co mi blog? - do teraz zadaję sobie to pytanie, a zadawać pewnie będę je sobie jeszcze przez jakiś okres czasu. Meh. Blog ten ma mi służyć jako motywacja do zostania nerdem. Tak, zagadka rozwiązana! Chce zostać nerdem. Dlaczego? - zapytacie. Otóż jestem młodym człowiekiem, który troszkę przedłużył sobie studia ale nieuchronnymi krokami zbliża się do podjęcia ważnej, życiowej decyzji - cóż takiego MŁODY człowieku chciałbyś w życiu robić? Tak, mamo - chcę zostać nerdem.

Nie będę ukrywać, że jestem leniwy. Nie będę również ukrywać tego, że zawsze interesowały mnie nowe technologie, z dużym naciskiem na gamedev. Swego czasu nauczyłem się kodować w banalnym (bo przykładów mnóstwo, szablonów też, gotowych skryptów etc.) HTML5 oraz bootstrapie. Teraz, kiedy wiem, że WWW może zrobić każdy student informatyki za skrzynkę browarów wiem, że moja wiedza, doświadczenie oraz możliwości na tym poziomie są.. A to są w ogóle jakieś umiejętności, jakaś wiedza? Ano nie. Ale są CHĘCI.

Tak, będę tutaj spisywać sobie krok, po kroku kolejne szczeble, obejmujące moją naukę, doświadczenia, zmagania, wymagania i wszystko, co przyjdzie mi do głowy, a czym będę miał ochotę się podzielić. Trzymajcie kciuki, jak wspominałem wyżej - jestem leniwy.

Kilka słów o mnie, moi mili. Jestem Filip, miło mi, hej, hej. Jestem doktorantem na WB UAM, doktoryzuję się z ekologii ale nie jest to to, czym chciałbym się zająć w przyszłości. Mam kochającą rodzinę, fajnego brata, grupkę znajomych i fajny hipsterski sweter. Większość mojego życia przeleżałem, mniejszość pracowałem w pocie czoła, by osiągnąć to, gdzie teraz jestem. Tak! Zgadliście, moje mysie pysie - nie podoba mi się to, gdzie teraz jestem. Jestem osobą ambitną, zdolną. Posiadam parę nałogów, trochę pasji, jadaczka mi się nie zamyka, a ironia i sarkazm wrosły mi w głowę. Wiecie, może już teraz skończę, ponieważ palce zaczynają mi cierpnąć nad klawiaturą, a sam, gdybym zaczął pisać o sobie na poważnie, to musiałbym zmienić nazwę bloga 'jak zostać narcyzem do kwadratu'. W sumie.. czemu nie. Jak czas pozwoli, blogger nie ogranicza liczby posiadanych blogów. Mhyhy.

Zabrałabym się za kolejny wpis, traktujący o moim pierwszym kontakcie z C++ oraz frameworkowym Selenium ale muszę zapakować się w auto i oddać telefon znajomej. Tak jakoś się złożyło, że zostawiła go u mnie w aucie, a że mieszka 20 minut drogi stąd i jestem uczynnym chłopakiem (nie, żebym migał się od obowiązków).

Spodziewajcie się niedługo kolejnego wpisu!

Meow, koteczki.
F.