Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

SQL - przecinek a kropka

SQL to naprawdę fajna rzecz. Przekonałem się o tym, pisząc małą aplikację webową. Miała się zająć ściąganiem danych z różnych stron internetowych i przetwarzanie ich w jedną zgrabną tabeleczkę.

Po mimo tego, że jestem samoukiem napisanie tego nie było wielkim wyzwaniem, ale nie pomyślałem o jednym... pobranie kilku stron internetowych, wykrojenie tego, co potrzebne i wyświetlenie tego może być trochę czasochłonne, i było. Tak to się dzieje jak się nie pomyśli naprzód. Najwięcej trwała obróbka danych, jeśli zrobiłem to raz na dobę i zapisałem do bazy oszczędzałem bardzo dużo czasu. Z pomocą przyszedł mi MySQL. Funkcje, które są dostępne poprzez odpowiednie rozszerzenia w php są cudowne (przynajmniej dla moich zastosowań), jednak coś nie grało. Dane nie chciały się zapisywać choć powinny i tutaj zaczyna się problem!!

SQL nienawidzi przecinka!

Nie jestem ekspertem w SQL w sumie to prócz "SELECT, UPDATE, INSERT i WHERE" nic więcej nie jest mi potrzebne i nawet nie wiem, czy coś jest :D Męczyłem się prawie godzinę. Dane były zbierane prawidłowo. Sprawdziłem, czy w ustawiłem w SQL dobry typ danych. No był float, bo potrzebowałem obsługi liczb zmiennoprzecinkowych. W końcu stwierdziłem, że wpiszę jakieś dane ręcznie i zobaczę czy działa. Wpisałem "1"... i działało. No to wpisałem "1,5"... i ku mojemu zdziwieniu nie działało. - "Co jest grane? Float, to float, dlaczego to ****** nie działa? A co mi tam, spróbuje tego." - wpisałem "1.5". Ku mojemu zdziwieniu wszystko działo poprawnie.

Jedna mała kropka doprowadziła mnie do szaleństwa!

Wszystkie dane jakie zbierał mój program były z naszym swojskim polskim przecinkiem. Rozwiązanie przyszło szybko i mam nadzieję, że ten artykuł, jaki i banalne rozwiązanie uchroni niedzielnych programistów przed wyrwaniem wszystkich włosów z głowy.

Przejdźmy do jednej linijki kodu, która podsumowała moja całogodzinną pracę:$var=str_replace(",",".",$var);

W ten sposób zmieniliśmy wartość z przecinkiem na wartość z kropką, która idealnie współpracuje z naszą bazą SQL. Prawdopodobnie mój problem zostałby wyśmiany przez doświadczonych programistów, ale człowiek się uczy całe życie i teraz wiem, że kropka a przecinek robi różnicę. Mam nadzieję, że Ci, którzy jeszcze nie wiedzieli, po przeczytaniu tego wpisu przejrzą na oczy i tak jak ja już więcej nie popełnią takiego błędu. 

internet programowanie hobby

Komentarze

0 nowych
gowain   18 #1 03.09.2012 19:15

Nie jest czasami tak, że we wszystkich językach programowania dziesiętne części są po kropce?...

  #2 03.09.2012 19:18

Hm... to str_replace wygląda dziwnie - wiedz, że po stronie php to $var jest traktowane jako... string.
Jeżeli i tam masz float to wiedz, że TEŻ musi być kropka.

Po prostu jest przyjęta wszędzie (tzn. z tego co wiem to np. C, C++, Java, PHP) notacja anglosaska, która zakłada, że to kropka jest separatorem pomiędzy częścią całkowitą a ułamkową. SQL nie jest tu wyjątkiem.

tfl   8 #3 03.09.2012 20:01

Oj, to nie jest dobry przyklad...

Po pierwsze, jak juz pisal lukasamd, wykorzystujesz fakt, ze php nie dba o typy zmiennych, wiec mozesz sobie wykonywac funkcje przeznaczone dla stringow na danych, ktore zakladasz, ze sa floatem.
Po drugie, jesli chcesz byc strict wobec typow zmiennych, do tego typu operacji jest funkcja number_format, ktora potrafi ustawic i rodzaj znaczka przed czescia dziesietna, ale takze ilosc liczb po przecinku i ewentualnie rozdzielenie tysiecy.
Po trzecie, warto rzutowac typy danych, dlatego $var = (float) str_replace(",",".", $var); powinno zadzialac, a na pewno zadziala $var = settype(str_replace(",",".",$var), "integer");

meron11   3 #4 04.09.2012 01:06

niech rzutuje wynik str replace...

Druedain   13 #5 04.09.2012 11:41

@gowain Nie spotkałem się jak dotąd z inną notacją, a wynika ona z tego, że większość języków programowania (dobra, całą informatyka w sumie) stoi na języku angielskim, a tam kropka, a nie przecinek oddziela części dziesiętne. I wydaje mi się, że tak się dzieje również w PHP. Ale podoba mi się ten wpis – rozwój samouka i ta radość z pokonywania trudności :)

PLI52KA   4 #6 04.09.2012 11:48

Ja również miałem taki podobny problem, na matmie się uczyło przecinku, w informatyce nauczyło się kropki.

Przypomniałem sobie o błędach, na które w Allegro narzekają, kropka a przecinek. http://biznes.gazetaprawna.pl/artykuly/440347,lowcy_pomylek_z_allegro.html

hausner15   5 #7 04.09.2012 12:52

@lukasamd, @tfl
Tyle że w tym konkretnym wypadku bardzo dobrze że użył str_replace :)
Zauważ że kolega odczytuje te dane z strony internetowej - czyli "wycina" je z stringa. Następnie wpisuje je do bazy zapytaniem które również jest stringiem. Dlatego w jakim celu konwertować stringa na floata, aby zmienić przecinek na kropkę i potem ponownie zmieniać to na stringa? :)

  #8 04.09.2012 12:56

U nas na zajęciach z C# zawsze były problemy ze stringiem wpisanym w oknie programu, a potem konwertowanego na float. Działało tylko z przecinkiem. Pewnie ustawienia systemu miały na to wpływ.

  #9 04.09.2012 15:27

@hausner15:
Widzę te informacje we wpisie, ale nie widzę kodu od tego. Możemy się tylko domyślać jak jest to realizowane... poza tym, przecież napisał, że w bazie ma typ float...

dominikc   5 #10 04.09.2012 15:27

@Anonim (niezalogowany)
Trzeba użyć CultureInfo.InvariantCulture przy konwertowaniu - np. Convert.ToDouble(string, CultureInfo.InvariantCulture);

elesoft   9 #11 04.09.2012 15:42

@Anonim (niezalogowany): jest dokładnie tak jak piszesz.
C# miał chyba rozwiązywać problem z przecinkami/kropkami i w zależności od ustawień systemowych, separatorem jest albo przecinek, albo kropka. Niestety, często można się na tym przejechać - np. testując aplikację z WP7 z angielskimi ustawieniami regionalnymi wszystko działa, a już po zmianie na PL aplikacja sypie wyjątkami. I kończy się to tak, że trzeba kontrolować dane nawet z wbudowanych kontrolek.

dominikc   5 #12 04.09.2012 16:09

@elesoft
Spróbuj użyć tego co napisałem wyżej. Zresztą da się sprawdzić w jakim formacie są dane.

elesoft   9 #13 04.09.2012 16:30

@dominikc: wiem, że trzeba konwertować w taki sposób, jak napisałeś.
Po porostu, MS miał dobre intencje wprowadzając taką obsługę ustawień językowych, a tymczasem wprowadził kolejną niespodziankę dla programistów :)

hausner15   5 #14 04.09.2012 17:09

@lukasamd
Ale co z tego że w bazie ma typ float skoro i tak samo zapytanie SQL jest stringiem?
Przykładowo: "UPDATE `tabela` SET `pole` = " . $float . " WHERE ..." - czymkolwiek by ta zmienna nie była, i tak tutaj PHP zrobi z tego stringa.

Nawet używając PDO i bindowania myślę że konwersja na floata i tak byłaby zbędna.

Zgadzam się co do tego, że musielibyśmy zobaczyć kod aby zdecydować czy takowe rozwiązanie ma sens :)

iluzion   5 #15 04.09.2012 19:08

@elesoft

Już niech z tymi udogodnieniami nie przesadzają. Wystarczą te spolszczone polecenia w Excelu. Zamiast ładnej, krótkiej funkcji ODD mamy ZAOKR.DO.NPARZ, zamiast funkcji TRIM jest USUŃ.ZBĘDNE.ODSTĘPY, INT przetłumaczono na ZAOKR.DO.CAŁK... itd, itp. Części nie przetłumaczono wcale. No ale tak to już jest z tym Microsoftem. O kodowaniu znaków w Windowsie i poszczególnych programach lepiej nie wspominać.

  #16 04.09.2012 22:00

Chyba oczywiste, że wszystkie popularne języki używają jako podstawy angielskiego więc jest KROPKA dziesiętna a nie przecinek. Szybko się do tego przyzwyczai każdy kto chwilę dłużej popisze :)

StawikPiast   10 #17 04.09.2012 22:23

@hausner15

To co opisales to jakis koszmar, ale moze w PHP tak jest. W C# zapis do bazy realizuje sie zupełnie innaczej i zdaje mi sie lepiej.

robisz to tak

insert tinto tabela values(@parametrA, @parametrB)

potem definiujesz te parametry nadajac im typ danych z SQL-a, czyli float, int, nvarchar itd itp. i zapisujesz jako porzadany typ.

soanvig   9 #18 04.09.2012 22:39

Oj StawikPiast to o czym ty piszesz to jest zupełnie co innego. My tu nie mówimy o jakiś skrótowych funkcjach C# (przykład który podałeś) lub o nietypowych bazach danych, tylko o języku SQL, w którym to wygląda tak, a nie inaczej.

StawikPiast   10 #19 04.09.2012 22:51

@soanvig

Jaki skrótowy zapis?
Przeciez zapis sie wydluza :) ale jest znacznie czytelniejszy a do tego nie ma wlasnie problemow z konwersja przecinkow i tak dalej. To po prostu dziala, no i do tego jest to zalecany sposob przekazywania zmiennych do polecen SQL-a, przekazanie jak podal hausner15

"UPDATE `tabela` SET `pole` = " . $float . " WHERE ..."

to zło i moze powodowac potem problemy z bezpieczenstwem, chodzi o bledy SQL injection.

iluzion   5 #20 04.09.2012 23:00

Teraz na topie jest NoSQL, np. http://www.mongodb.org/

tfl   8 #21 04.09.2012 23:03

@soanvig

To zdaje sie Ty nie za bardzo wiesz o czym mowa... :)
To co podal @hausner15 to defacto jedno z najprostszych sposów laczenia stringow w zapytanie do bazy danych. Do php na szczescie sa freamworki, ktore upraszaczaja bardzo robienie zapytan, sam nie pamietam kiedy ostatnio uzywalem czegos ala mysqli_query("zapytanie");

Jeszcze raz wyjasnie dlaczego dbanie o typy zmiennych nawet w php jest wazne. Zrobmy sobie takiego inserta:

insert into `new_table` (`string`, `float`, `int`) values (1, '1.5', 1.5);

przy czym kolumna string ma typ varchar(250), float ma float a int ma int.
Co uzyskamy przy zapytaniu
select * from `new_table`; ?
string | float | int
1 | 1.5 | 2

(te spcje moga sie rozjechac, sory).

Wynik nie jest najgorszy... ale zapytanie:

SELECT * FROM test.new_table where `string` = 1 and `float` = '1.5' and `int` = 1.5;

zwroci nam juz pusty wynik. A przeciez te same dane "weszly do bazy".

iluzion   5 #22 04.09.2012 23:13

@tfl

Jeśli mowa o typach i pada pytanie co uzyskamy to przypomina mi się ta prezentacja:

http://www.youtube.com/watch?v=0QZgx45aGCA&feature=player_embedded

Polecam na poprawę humoru.

  #23 05.09.2012 09:41

@hausner15:
Ale co ma string po stronie PHP do typów po stronie np. MySQL?
Fakt, zrobi sobie konwersję i jak w INT spróbujesz zapisać ciąg "Ala ma kota" to powinno być 0*.

* - czy zawsze będzie, nie wiem, dlatego czuję się bezpieczniej sam rzutując i ustalać typy.

  #24 05.09.2012 09:41

@StawikPiast:
"Ładniej" można i w PHP, nawet przy używaniu np. mysql_query / mysqli_query:

mysql_query("INSERT INTO tabela VALUES('{$val1}', '{$val2}')");

A to co pójdzie powinno być wcześniej filtrowane.
Oczywiście w PDO można czytelniej i tam też już można filtrować ale... naprawdę da się zrobić kod używający PDO, który będzie podatny na SQL Injection.
Wszystko więc zależy od osoby która pisze kod, technologia pozwala i na zabezpieczanie i na wygodę.

  #25 05.09.2012 09:43

@tfl:
Wszystko się zgadza. Przecież wcale nie te same dane weszły do bazy.

1. Puściłeś do bazy na pole INT wartość 1.5.

2. Baza sama skonwertowała to na INT i otrzymałeś 2*
Widać to w zapytaniu
"select * from `new_table`;"

3. Próba drugiego zapytania tj:
"SELECT * FROM test.new_table where `string` = 1 and `float` = '1.5' and `int` = 1.5; "

Musi zwrócić w tym wypadku 0 rekordów, bo w INTcie nawet nie może być 1.5... to nigdy nie zwróci żadnego rekordu.


* - swoją drogą, tu widać "burdel" - o ile dobrze pamiętam, C++ przy konwersjach tak jawnych jak i niejawnych zaokrągla zawsze w dół... Tu mamy zaokrąglanie w górę...

Autor edytował komentarz.
tfl   8 #26 05.09.2012 12:12

@lukasamd

Tak, wiem, ze wlasnie tak sie dzieje... ale to wlasnie chcialem udowodnic... przeciez gdyby zrobic takie zapytanie (pseudo php kod)

insert into `new_table` (`string`, `float`, `int`) values ((string) 1, (float) '1.5', (int) 1.5);

a potem:


SELECT * FROM test.new_table where `string` = (string) 1 and `float` = (float) '1.5' and `int` = (int) 1.5;

dostalisbysmy prawidlowy wynik

meron11   3 #27 05.09.2012 23:50

Przeciesz pisanie poprzez mysql_ to sztuka dla szttuki od kiedy jest PDO, lub uzywać ORM lepiej, np taki Doctrime.

mikolaj_s   13 #28 05.11.2012 11:38

Swoją drogą równie wkurzające jest działanie konsoli w Javie. Jak mam Locale PL to wczytując dane z klawiatury program oczekuje przecinka zamiast kropki dziesiętnej, a co zrobić jak człowiek się przyzwyczaił, a za chwilę musi w IDE wpisywać kropkę. Gorzej by było tylko jakby w IDE również kropka i przecinek zależały od języka.

  #29 13.04.2014 13:15

Collection of some of your personal information is essential for completion of some of the functions and activities of this Website. We will, if it is reasonable or practicable to do so, also collect your personal information directly from you. For instance, the collection of your personal information may happen when youall4dream.

Slavio71   1 #30 23.01.2015 16:35

MS SQL - Ja stosuję takie rozwiązanie.
SELECT
...
,...
,REPLACE(CAST(Kwota AS DECIMAL(9,2)) ,'.',',') AS 'Kwota'
FROM Baza