Databázy (1) Prednáška 10 Alexander Šimko simko@fmph.uniba.sk
Contents I Práca s dátumom a časom Náhodné čísla Generovanie dát
Práca s dátumom a časom Section 1 Práca s dátumom a časom
Práca s dátumom a časom Dátumové a časové typy podrobne Dátum bez času date 4 bajty od 4717 p.n.l. po 5874897 n.l. Dátumový literál DATE YYYY-MM-DD 17. jún 2015: DATE 2015-06-17
Práca s dátumom a časom Dátumové a časové typy podrobne Čas bez dátumu time 8 bajtov od 0:00:00 do 24:00:00 vrátane
Práca s dátumom a časom Dátumové a časové typy podrobne Časový literál Formát TIME HH:MM:SS.SSSSSS Prvá milisekunda po odchode poslednej 39ky z Mlynskej TIME 23:05:00.000001
Práca s dátumom a časom Dátumové a časové typy podrobne Čas 00:00 vs 24:00 CREATE TABLE test ( x time ) INSERT INTO test (x) VALUES (TIME 00:00:00 ), (TIME 24:00:00 ) x 00:00:00 24:00:00 00:00:00 < 24:00:00
Práca s dátumom a časom Dátumové a časové typy podrobne Použitie schedule day start end activity Monday 00:00 02:00 film watching Monday 22:00 24:00 film watching
Práca s dátumom a časom Dátumové a časové typy podrobne Dátum s časom timestamp 8 bajtov rozsahy rovnako ako pri dátume a čase interne reprezentovaný ako počet sekúnd od nejakého pevného času Literál dátumu s časom: TIMESTAMP YYYY-MM-DD HH:MM:SS.SSSSSS
Práca s dátumom a časom Dátumové a časové typy podrobne Dátum a čas 00:00 vs 24:00 CREATE TABLE test ( x timestamp ) INSERT INTO test (x) VALUES (TIMESTAMP 2015-06-17 00:00:00 ), (TIMESTAMP 2015-06-16 24:00:00 ) x 2015-06-17 00:00:00 2015-06-17 00:00:00 TIMESTAMP 2015-06-17 00:00:00 = TIMESTAMP 2015-06-16 24:00:00
Práca s dátumom a časom Dátumové a časové typy podrobne Varianty s časovou zónou timestamp with time zone time with time zone
Práca s dátumom a časom Dátumové a časové typy podrobne Časový úsek bez ohľadu na začiatok a koniec interval 16 bajtov od -178000000 rokov po 178000000 rokov
Práca s dátumom a časom Dátumové a časové typy podrobne Časový úsek bez ohľadu na začiatok a koniec INTERVAL počet jednotka [počet jednotka...] Jednotky microsecond millisecond second minute hour day week month year decade century millennium INTERVAL 1 year 2 weeks 7 minutes
Práca s dátumom a časom Dátumová a časová aritmetika Dátumová a časová aritmetika Big Picture bod ± interval bod posúva bod v čase bod + bod nedáva zmysel bod bod interval časový úsek medzi bodmi interval ± interval interval sčíta/odčíta intervaly interval / číslo interval naškáluje interval
Práca s dátumom a časom Dátumová a časová aritmetika Dátumová a časová aritmetika Nejednotnosť date ± integer date dátum posunie dopredu/dozadu o daný počet dní timestamp ± integer time ± integer taký operátor nie je
Práca s dátumom a časom Dátumová a časová aritmetika Dátumová a časová aritmetika Nejednotnosť date ± interval timestamp timestamp ± interval timestamp dátumočas posunie dopredu/späť o daný interval dátum (date), sa považuje za dátumočas s časovou zložkou 00:00:00 výsledok je timestamp bez ohľadu či má interval časovú zložku time ± interval time čas posunie dopredu/dozadu o daný interval dátumovú zložku intervalu ignoruje TIME 01:02:03 + 5 days 1 second = TIME 01:02:04 TIME 01:02:03-5 days 1 second = TIME 01:02:02
Práca s dátumom a časom Dátumová a časová aritmetika Dátumová a časová aritmetika Podrobne viď dodatok
Práca s dátumom a časom Dátumové a časové funkcie Aktuálny dátum a čas current_date date vráti aktuálny dátum localtime time vráti aktuálny čas localtimestamp timestamp vráti aktuálny dátum a čas
Práca s dátumom a časom Dátumové a časové funkcie Vytvorenie dátumu a času make_date(rok, mesiac, deň) date vytvorí zadaný dátum make_time(hodina, minúta, sekunda) time vytvorí zadaný čas make_timestamp(rok, mesiac, deň, hodina, minúta, sekunda) timestamp vytvorí zadaný dátum a čas make_interval(roky, mesiace, týždne, dni, hodiny, minúty, sekundy) interval vytvorí zadaný interval
Práca s dátumom a časom Dátumové a časové funkcie Získanie časti dátumu, času a intervalu date_part(časť, timestamp) double precision date_part(časť, interval) double precision získa zadanú časť dátumočasu/intervalu dátum/čas sa konvertujú na dátumočas SELECT date_part( month, TIMESTAMP 2015-04-07 12:56:34 ) date_part 4
Práca s dátumom a časom Dátumové a časové funkcie Získanie časti dátumu, času a intervalu Ako časť môžu byť hodnoty century day decade dow (deň týždňa) doy (deň roka) epoch hour isodow (deň týžňa od Po) isoyear (od Po) microseconds millennium milliseconds minute month quarter (štvrťrok) second week (od Po) year
Práca s dátumom a časom Dátumové a časové funkcie Získanie časti dátumu, času a intervalu date_trunc(časť, timestamp) timestamp date_trunc(časť, interval) timestamp odreže dátumočas/interval po danú časť dátum/čas sa konvertujú na dátumočas SELECT date_trunc( month, TIMESTAMP 2015-04-07 12:56:34 ) date_trunc 2015-04-01 00:00:00
Práca s dátumom a časom Dátumové a časové funkcie Získanie časti dátumu, času a intervalu Ako časť môžu byť hodnoty microseconds milliseconds second minute hour day week (od Po) month quarter year decade century millennium
Práca s dátumom a časom Dátumové a časové funkcie Získanie časti dátumu, času a intervalu Príklad orders id time_of_order amount 1 2015-02-05 12:49:00 10 2 2015-02-06 12:50:00 15 SELECT date_trunc( week, time_of_order) as week, sum(amount) FROM orders GROUP BY week week sum 2015-02-02 00:00:00 25
Práca s dátumom a časom Dátumové a časové funkcie Získanie časti dátumu, času a intervalu Príklad orders id time_of_order amount 1 2015-02-05 12:49:00 10 2 2015-02-06 12:50:00 15 SELECT date_part( year, time_of_order) as year, date_part( week, time_of_order) as week, sum(amount) FROM orders GROUP BY year, week year week sum 2015 6 25
Náhodné čísla Section 2 Náhodné čísla
Náhodné čísla Náhodné čísla random() vráti náhodné desatinné číslo z intervalu 0.0, 1.0), číslo je typu double precision, rovnomerná distribúcia. SELECT random() random 0.216747856233269
Náhodné čísla Náhodné čísla Zmena intervalu Ak chceme náhodné čísla z intervalu min, max), musíme pôvodný rozsah naškálovať. random() * (max - min) + min
Náhodné čísla Náhodné čísla Celé čísla Ak chceme, aby boli náhodné čísla celé, musíme ich vhodne konvertovať: funkcia floor(x) funkcia ceil(x) funkcia trunc(x) funkcia round(x) CAST
Náhodné čísla Náhodné čísla Celé čísla Funkcia floor floor(x) zaokrúhli číslo na najbližie menšie celé číslo floor(1.5) = 1 floor(-1.5) = -2 floor(random() * (max - min) + min) dáva potom celé čísla z rozsahu min, max)
Náhodné čísla Náhodné čísla Celé čísla Funkcia ceil ceil(x) zaokrúhli číslo na najbližie väčšie celé číslo ceil(1.5) = 2 ceil(-1.5) = -1 ceil(random() * (max - min) + min) dáva potom celé čísla z rozsahu min, max získať ale číslo min je prakticky nemožné, nakoľko ho dostaneme, iba ak random() vráti presne číslo 0.0 nakoľko to ale nie je vylúčené, takýto vzťah negeneruje čísla s rovnomernou pravdepodobnosťou
Náhodné čísla Náhodné čísla Celé čísla Funkcia trunc trunc(x) odreže desatinnú časť trunc(1.5) = 1 trunc(-1.5) = -1 trunc(random() * (max - min) + min) ak je min < 0, tak min bude vygenerované iba ak random vygeneruje presne 0.0, čo sa stane s nízkou pravdepodobnosťou ak je min > 0, tak sa vygeneruje s dobrou pravdepodobnosťou ak je max > 0, tak nebude nikdy vygenerované ak je max 0, tak sa vygeneruje s dobrou pravdepodobnosťou takýto výraz sa správa rôzne v závislosti od toho, či pracujeme s kladnými alebo zápornými číslami
Náhodné čísla Náhodné čísla Celé čísla Funkcia round round(x) zaokrúhli desatinné číslo na celé číslo podľa bežných pravidiel zaokrúhľovania round(random() * (max - min) + min) dáva potom celé čísla z rozsahu min, max kedže čísla min a max vzniknú iba zaokruhľovaním z jednej strany, pravdepodobnosť ich vzniku je polovičná než ostatných čísel tým pádom takýto vzťah negeneruje čísla s rovnomernou pravdepodobnosťou
Náhodné čísla Náhodné čísla Celé čísla CAST CAST (x AS integer) pretypuje x na celé číslo, zároveň zaokrúhli x podľa bežných pravidiel zaokruhľovania situácia je podobná ako v prípade round
Náhodné čísla Náhodné čísla Celé čísla Záver Používajte variant floor
Náhodné čísla Náhodné čísla Celé čísla Typ floor a iné funkcie vracajú rovnaký dátový typ ako majú na vstupe floor(random() * (max - min) + min) je síce celé číslo, ale dátového typu double precision Ak chceme typ integer, treba pretypovať floor(random() * (max - min) + min)::integer
Náhodné čísla Náhodné čísla Komplikácia Chceme náhodné číslo a zároveň jeho dvojnásobok SELECT random() AS x, x * 2 AS y ERROR: column "x" does not exist
Náhodné čísla Náhodné čísla Komplikácia SELECT random() AS x, random() * 2 AS y x y 0.926946882158518 0.789256273768842
Náhodné čísla Náhodné čísla Komplikácia SELECT x, x * 2 as y FROM (SELECT random() AS x) AS tmp x y 0.239173104055226 0.478346208110452
Náhodné čísla Náhodné čísla Riadky v náhodnom poradí SELECT * FROM názov_tabuľky ak nepožijeme ORDER BY nemáme garantované poradie riadkov, riadky ale nie sú v náhodnom poradí, je dané tým ako sú uložené na disku a stavom dátových štruktúr v databázovom systéme, ak spustíme po sebe 2x ten istý dopyt bez toho, aby sme medzi tým spravili niečo iné, pravdepodobne dostaneme riadky v tom istom poradí
Náhodné čísla Riadky v náhodnom poradí Náhodné čísla Riadky v náhodnom poradí SELECT * FROM názov_tabuľky ORDER BY random()
Generovanie dát Section 3 Generovanie dát
Generovanie dát Generovanie jedneho riadku SELECT CASE floor(random() * 4) WHEN 0 THEN Mária WHEN 1 THEN Katarína WHEN 2 THEN Júlia WHEN 3 THEN Eliška END AS name, CASE floor(random() * 6) WHEN 0 THEN Priezvisko 1 WHEN 1 THEN Priezvisko 2 WHEN 2 THEN Priezvisko 3 WHEN 3 THEN Priezvisko 4 WHEN 4 THEN Priezvisko 5 WHEN 5 THEN Priezvisko 6 END AS surname, floor(random() * 70) + 13 AS age name surname age Júlia Priezvisko 5 33
Generovanie dát Funkcia generate_series generate_series(začiatok, koniec) generuje postupnosť celých čísel od začiatku po koniec s krokom jedna vracia tabuľku s jedným stĺpcom a potenciálne veľa riadkami
Generovanie dát Funkcia generate_series SELECT * FROM generate_series(-1, 2) generate_series -1 0 1 2
Generovanie dát Funkcia generate_series SELECT seq.i FROM generate_series(-1, 2) AS seq(i) i -1 0 1 2
Generovanie dát Generovanie viacerých riadkov SELECT CASE floor(random() * 4) WHEN 0 THEN Mária WHEN 1 THEN Katarína WHEN 2 THEN Júlia WHEN 3 THEN Eliška END AS name, CASE floor(random() * 6) WHEN 0 THEN Priezvisko 1 WHEN 1 THEN Priezvisko 2 WHEN 2 THEN Priezvisko 3 WHEN 3 THEN Priezvisko 4 WHEN 4 THEN Priezvisko 5 WHEN 5 THEN Priezvisko 6 END AS surname, floor(random() * 70) + 13 AS age FROM generate_series(1,20) name surname age Júlia Priezvisko 5 60 Katarína Priezvisko 3 50.........
Generovanie dát CREATE TABLE AS CREATE TABLE názov_tabuľky [(názov_stĺpca_1,... názov_stĺpca_n)] AS dopyt vytvorí zadanú tabuľky a naplní ju dátami z dopytu názvy stĺpcov sa odvodia z dopytu ak názvy stĺpcov zadáme explicitne, prebijú tie z dopytu typ stĺpcov sa odvodí z dopytu nevieme ho zadať explicitne tento príkaz neakceptuje integritné obmedzenia
Generovanie dát CREATE TABLE AS CREATE TABLE users AS SELECT id, CASE floor(random() * 4) WHEN 0 THEN Mária WHEN 1 THEN Katarína WHEN 2 THEN Júlia WHEN 3 THEN Eliška END AS name, CASE floor(random() * 6) WHEN 0 THEN Priezvisko 1 WHEN 1 THEN Priezvisko 2 WHEN 2 THEN Priezvisko 3 WHEN 3 THEN Priezvisko 4 WHEN 4 THEN Priezvisko 5 WHEN 5 THEN Priezvisko 6 END AS surname, floor(random() * 70) + 13 AS age FROM generate_series(1,20) AS seq(id)
Generovanie dát INSERT INTO INSERT INTO názov_tabuľky (názov_stĺpca_1,... názov_stĺpca_n) dopyt namiesto VALUES môžeme uviesť dopyt do zadanej tabuľky vloží dátai z dopytu
Generovanie dát INSERT INTO Predpokladáme, že tabuľku už máme INSERT INTO users (id, name, surname, age) SELECT id, CASE floor(random() * 4) WHEN 0 THEN Mária WHEN 1 THEN Katarína WHEN 2 THEN Júlia WHEN 3 THEN Eliška END AS name, CASE floor(random() * 6) WHEN 0 THEN Priezvisko 1 WHEN 1 THEN Priezvisko 2 WHEN 2 THEN Priezvisko 3 WHEN 3 THEN Priezvisko 4 WHEN 4 THEN Priezvisko 5 WHEN 5 THEN Priezvisko 6 END AS surname, floor(random() * 70) + 13 AS age FROM generate_series(1,20) AS seq(id)
Generovanie dát Ďalší príklad CREATE TABLE films AS SELECT id, Film id AS name, floor(random() * 45) + 1970 AS year FROM generate_series(1,20) AS seq(id)
Generovanie dát Generovanie väzobnej tabuľky Ak idečka sú spojité CREATE TABLE ratings AS SELECT floor(random() * 10000 + 1) AS user_id, floor(random() * 200 + 1) AS film_id, floor(random() * 10 + 1) AS rating FROM generate_series(1, 100)
Generovanie dát Generovanie väzobnej tabuľky Ak v idečkách sú medzery CREATE TABLE ratings AS SELECT user.id AS user_id, film.id AS film_id, floor(random() * 10 + 1) AS rating FROM users CROSS JOIN films WHERE random() < 0.7 Pozor: toto je neefektívne pre veľké tabuľky
Generovanie dát Generovanie maximálneho počtu prvkov Pre každého používateľa chceme maximálne 2 obľúbené filmy SELECT users.id AS user_id, tmp.id AS favourite_film_id FROM users CROSS JOIN (SELECT films.id FROM films ORDER BY random() LIMIT 2) AS tmp
Generovanie dát Generovanie maximálneho počtu prvkov Pre každého používateľa chceme maximálne 2 obľúbené filmy SELECT users.id AS user_id, tmp.id AS favourite_film_id FROM users CROSS JOIN (SELECT films.id FROM films ORDER BY random() LIMIT 2) AS tmp Nie tak úplne
Generovanie dát Čo očakávame? user_id favourite_film_id 1 3 1 7 2 61 2 1 3 76 3 6......
Generovanie dát Čo dostaneme? user_id favourite_film_id 1 3 1 7 2 3 2 7 3 3 3 7......
Generovanie dát Prečo? SELECT users.id AS user_id, tmp.id AS favourite_film_id FROM users CROSS JOIN (SELECT films.id FROM films ORDER BY random() LIMIT 2) AS tmp
Generovanie dát Prečo? SELECT users.id AS user_id, tmp.id AS favourite_film_id FROM users CROSS JOIN [(2), (7)] as tmp [(2), (7)] má predstavovať akože tabuľku s dvoma riadkami toto je iba moja vizualizácia, nič také sa nedá zapísať
Generovanie dát A ako to opraviť? Pomocou vlastnej databázovej funkcie
Generovanie dát A ako to opraviť? CREATE FUNCTION random_films(x int) RETURNS TABLE (id integer) LANGUAGE SQL AS $$ SELECT id FROM films ORDER BY random() LIMIT 2 $$ SELECT user.id AS user_id, tmp.id AS favourite_film_id FROM users CROSS JOIN LATERAL random_films(users.id) AS tmp volanie funkcie sa odkazuje na riadok tabuľky, takže sa musí zavolať pre každý riadok volanie vlastnej databázovej funkcie systém štandarne nezoptimalizuje a každé volanie vyhodnotí nanovo
Generovanie dát Kontrola rozloženia pravdepodobnosti SELECT round(random() * 10) AS x, round(count(*) * 100.0 / 1000000.0, 2) AS prob FROM generate_series(1, 1000000) GROUP BY x ORDER BY x x prob 0 5.03 1 10.02 2 9.99 3 10.01 4 10.01 5 10.00 6 9.93 7 9.99 8 10.04 9 9.97 10 5.00
Generovanie dát Koniec Koniec