Marcin.Miga

Marcin.Miga
2019-01-11 13:17

Dziś takie cudeńko w bazie znalazłem (sam je zresztą swego czasu napisałem...)

CREATE OR REPLACE FUNCTION xxx(IN text)  RETURNS TABLE(wartosc text) AS
$BODY$ 
WITH"t"AS(SELECT($1)"w"),"r"AS(SELECT"regexp_matches"(w,E'i:(\\d+);.:(\\d+);','g')"r"FROM"t")SELECT(r::text[])[2]FROM"r" 
$BODY$
  LANGUAGE SQL VOLATILE

wewnątrz SQL nie ma spacji :)
#postgreSQL

Marcin.Miga

@WeiXiao: funkcja ma zwracać dla zserializowanej w PHP tablicy intów wartości elementów tablicy. Czy dla np.`a:4:{i:0;i:21;i:1;i:33;i:2;i:45;i:3;i:123}' zwróci 4 rekordy: 21, 33,45 i 123

Marcin.Miga
2018-11-05 23:03

Ostatnio postgreSQL mnie zaskoczył... Pisałem o tym. Okazało się, że to nie błąd, a ficzer.
A że w bazach cały czas się uczę i eksperymentuję, to naukę z tamtego wpisu (dzięki @Panczo) postanowiłem wykorzystać.
Napisałem klasycznego "jednolinijkowca":

SELECT string_agg(x, '') FROM  (SELECT unnest(regexp_split_to_array('zażółć gęślą jaźń', E'\\s*')) x ORDER BY x) x

który wykorzystywał tę właściwosć (SELECT bez FROM)
Ale potem przypomniałem sobie, że w funkcjach agregujących w postgres można podać kolejność rekordów (dla SUM, AVG i podobnych zupełnie niepotrzebne, ale tu się przyda). I wyszedł jeszcze ładniejszy "jednolinijkowiec":

SELECT string_agg(x, '' ORDER BY x) FROM  unnest(regexp_split_to_array('zażółć gęślą jaźń', E'\\s*')) x(x) 

A co on robi? Daje w wyniku aaąćęgjlłńóśzźż . Bez spacji - jeśli by miało być ze spacjami to trzeba zamenić E'\\s'* na E'\\.*'

cerrato

Jak uda Ci się coś ustalić w tej sprawie to daj znać, bo sam jestem ciekawy, co się za tym kryje ;)

Marcin.Miga
2018-10-27 10:59

Błąd w postgreSQL, który kosztował mnie pół dnia pracy... Zapytanie było częścią dużego skryptu i robiło UPDATE nie tych rekordów...

SELECT * FROM users WHERE id IN (SELECT id WHERE login='MM')

Zapytanie przechodzi, jest poprawne... Ale podzapytanie w IN już nie...
(Sprawdzane na postgreSQL 9.x)

Panczo

To co koleś napisał ma sens, więc wydaje się że to rozwiązuje sprawę: https://stackoverflow.com/que[...]3641/inner-query-without-from

Marcin.Miga
2018-10-11 21:37

Matematyka jest fajna. Czasem pomaga w informatyce. Załóżmy, że mamy do obliczenia miejsca zerowe dwumianu zapisanego w postaci:

x2+px+q=0

Czyli sprowadzić dwumian do postaci iloczynowej:

(x-x1)(x-x2)=0

Potrzebne będą wzory na deltę oraz x1 i x2:

∆=b2-4ac
x1=(b-√∆)/2a, x2=(b+√∆)/2a

Dla postaci z p i q te wzory wyglądają następująco:

∆=p2-4q
x1=(p-√∆)/2, x2=(p+√∆)/2

Ile zmiennych potrzeba, aby wyznaczyć rozwiązania? Na pewno 2 (p i q). Może 3, 4 albo 5? 2 wystarczą w zupełności… Pomogą małe przekształcenia matematyczne…

x1=(p-√∆)/2 → x1=p/2-√∆/2
x2=(p+√∆)/2 → x2=p/2+√∆/2

Zaś dodając stronami do siebie otrzymujemy:

x1+x2=p/2-√∆/2+p/2+√∆/2 → x2+x1=p → x2=p-x1

Jak widać q jest potrzebne tylko na początku – do obliczenia , potem już nie. Więc podstawimy w jej miejsce (jedna zmienna zaoszczędzona). Pseudokod, jak są zmienne wykorzystywane:

INPUT(p) # wprowadzenie p
INPUT(q) # wprowadzenie q

q = p*p-4*q  #∆ w zmiennej q
# q, czyli ∆ też właściwie nie jest potrzebna. Potrzebna jest połowa pierwiastka z ∆

q = SQRT(q)/2
# to obliczone q jest potrzebne tylko do wyznaczenia x1, do x2 nie. Czyli znowu możemy x1 wstawić do q, które już nie będzie później potrzebne

q = p/2-q  
# x1 w zmiennej q. jeśli ktoś nie lubi kroków pośrednich to może to zastąpić: 
# q=(p-SQRT(p*p-4*q))/2
# Prawda, że ładne? 😊)

p = p-q  # x2 w zmiennej p
furious programming

Dało się bez problemu. Mimo wszystko końcowy pseudokod trochę nieczytelny jest i trzeba by coś z tymi nawiasami zrobić, bo przez nie panuje mały haos.

Marcin.Miga
2018-01-16 22:12

Tradycyjnie - o SQL. Dziś coś sprawdzałem i "wykonało mi się" zapytanie:
SELECT true>false
Wynik : true. True :)
I tak się zastanowiłem. Analogicznie jest (true):
1>0, 'yes'>'no', PRAWDA>FAŁSZ (KŁAMSTWO), true>false.
No, może za wyjątkiem VB(A/S), gdzie
Print True>False zwraca False :)

krzysiek050

W C, prawdą jest każda liczba różna od 0, więc pod true można równie dobrze podstawić -1 i będzie to działało tak samo.

yarel

Google mówi, że Boolean został wprowadzony przez standard SQL:1999 jako opcjonalny typ danych. Z ciekawości sprawdziłem na podręcznym postgresie i wspiera booleana, nawet: select 'on'>false działą :) https://www.postgresql.org/do[...]/static/datatype-boolean.html "Baza wiedzy została zaktualizowana":)

Marcin.Miga
2017-07-19 23:39

Że MySQL jest głupi, to wiem nie od dziś. Ale dziś mnie dobił kompletnie.

UPDATE tabela123 SET pole1=pole2, pole2=NULL WHERE id<5;
UPDATE tabela123 SET pole2=NULL, pole1=pole2 WHERE id>4;

Zapytania wyglądają podobnie (bez WHERE), ale zachowują się inaczej. Inaczej niż drugie i inaczej niż inne bazy danych:
http://sqlfiddle.com/#!9/ce8cd6/1 - MySQL
http://sqlfiddle.com/#!4/ce8cd6/1 - Oracle
http://sqlfiddle.com/#!15/ce8cd/1 - PostgreSQL
http://sqlfiddle.com/#!5/ce8cd/1 - SQLite
http://sqlfiddle.com/#!6/ce8cd/1 - MS SQL

Boję się myśleć, jak robią to ORM-y...

Julian_

@kate87: insert into kate87 (dupa) values (masc_na_bol_dupy)

vpiotr

Wyjaśnienie czysto teoretyczne: 1) MySQL jest ogólnie "dziwny", w zasadzie w założeniach to był na początku taki dzisiejszy "NoSQL" - czyli szybki i prosty SQL bez transakcji. 2) MySQL kiedyś nie miał triggerów. 3) Triggery (before update) mają koncepcję wierszy "old" i "new" w update, dzięki czemu widzą wartości sprzed aktualizacji aktualnego wiersza. 4) Możliwe że wszystkie DBMS-y korzystają z tych starych wartości w czasie wykonania UPDATE (może jest to gdzieś w standardzie). 5) SQLite chwali się zgodnością z SQL92 (chociaż niepełną). Stąd pewnie taki efekt w przypadku MySQL (o ile tylko o niego chodzi).

Marcin.Miga
2017-04-24 10:44

Pisałem, że sztuczka nie zadziała dla liczb ujemnych. Bo dla nich nie są określone logarytmy. Praw fizyki Pan nie zmienisz... :)
Ale można obejść to inną sztuczką. Policzyć, ile jest liczb ujemnych i w zależności od tego tak zmienić wartość iloczynu bezwzględnych wartości.
(-2)x3x(-6)x(-8) = 2x3x6x8 x(-1)x(-1)x(-1) = 2x3x6x8 x (-1)^3

SELECT EXP(SUM(Ln(Abs(liczba))))*POWER(-1,SUM((liczba<0)::INT)) FROM (VALUES(-2),(3),(-6),(-8)) AS x(liczba)

Czysta matematyka :)
Ma to jednak tę wadę, że w wyniku dostajemy typ zmiennoprzecinkowy (i to ten najgorszy - double)

Marcin.Miga
2017-04-22 18:09

Było o iloczynie kartezjańskim, pora na zwykły iloczyn.
Tak nawiasem to dopiero dzięki bazom danych a właściwie dzięki iloczynowi kartezjańskiemu (zwanym również produktem kartezjańskim) zapamiętałem, że to wynik mnożenia. Przez tyle lat szkół nie potrafiłem tego zapamiętać... :)
Jak wiadomo, w bazach jest funkcja agregująca SUM() dająca wynik dodawania wszystkich wartości, ale nie ma takiej dla mnożenia...
Można natomiast to zrobić używając właśnie... SUM. (i pewnej właściwości logarytmów). Bez wchodzenia w teorię, bo to nudne, można to zrobić tak:

SELECT EXP(SUM(Ln(liczba))) FROM (VALUES(2),(4),(5)) AS x(liczba)

Ładnie zwróci 40, które jest wynikiem mnożenia 2x4x5. A zapytanie:

SELECT EXP(SUM(Ln(liczba))) FROM generate_series(1,5) x(liczba)

zwróci wynik mnożenia 1x2x3x4x5, czyli 5! (pięć silnia), czyli 120.
Niestety, ta sztuczka ma tę wadę, że działa tylko dla liczb dodatnich (bo dla nich są określone logarytmy)

Marcin.Miga
2017-04-21 19:17

Był iloczyn kartezjański, to jeszcze taki przykład. (WSZYSTKIE moje przykłady, o ile nie zaznaczę inaczej są na #postgreSQL)

SELECT * FROM unnest(array[1,2]) x

Zwraca dwa rekordy - zamienia tablicę na poszczególne rekordy. Czyli analogicznie:

SELECT * FROM unnest(array[1,2]) x, unnest(array[1,2,3,4,5,6]) y

zwróci 12 rekordów: 2x6
Ale ..

SELECT  unnest(array[1,2]) x, unnest(array[1,2,3,4,5,6]) y

nie zwraca 12 rekordów, tylko 6! :) Tej składni możemy użyć do wyszukiwania NWW, gdybyśmy czasem chcieli robić to bazą danych... :)
Np. NWW 16 i 34 (nie wiem...):

SELECT COUNT(*) FROM
(
SELECT generate_series(1,16), generate_series(1,34)
) x

wynik - 272. (muszę sprawdzić - =NAJMN.WSP.WIEL(16;34) z Excela daje taki sam wynik :))

Julian_

a jaki jest odpowiednik unnest i array w Oraclu albo MS SQL? bo pierwszy raz takie coś widzę.

Marcin.Miga

Posługuję się tu unnest() + array[], albo dla liczb generate_series(), bo te funkcje najszybciej robią mi zbiór rekordów. Możesz oczywiście użyć tabel, jako parametrów wejściowych.

Marcin.Miga
2017-04-19 09:34

Nic z czegoś:

WITH tab1 AS (SELECT generate_series(1,10) lp)
SELECT * FROM (SELECT * FROM tab1 WHERE lp<3) t1, (SELECT * FROM tab1 WHERE lp<4) t2

Piękny iloczyn kartezjański :) - 6 rekordów
Ale wystarczy niewielka modyfikacja:

WITH tab1 AS (SELECT generate_series(1,10) lp)
SELECT * FROM (SELECT * FROM tab1 WHERE lp<3) t1, (SELECT * FROM tab1 WHERE lp<1) t2

i już nic nie zwraca. Co jest zresztą logiczne, bo 2x3 = 6, a 2x0=0
Trzeba uważać używając CROSS JOINów