Autor | Zpráva | ||
---|---|---|---|
inen Profil * |
#1 · Zasláno: 7. 5. 2018, 17:33:00
Ahoj,
chtěl bych poprosit o radu s dotazem na databázi. Script jako takový funguje jen ho potřebuji omezit, aby načítal každou 30 položku z databáze. Napadlo mě dát tam podmínku s počítadlem, ale není něco jednoduššího? Nic jsem nenalezl. Děkuji za radu. <?php $url = 'www.xxx.com'; $obj = json_decode(file_get_contents($url), true); //db $conn = new mysqli("localhost", "root", "", "aa"); // Stochastic K index $Stochastic_k_15m = array(); // výběr posledních 3000 položek z databaze, ale kazde 30 polozky podle ID a casu $result = $conn->query("SELECT id, value FROM price ORDER BY id DESC LIMIT 3000"); // začnu načítat 3000 položek z databáze po jednotlivých řádcích while($row = $result->fetch_assoc()) { // Stochastic K array_push($Stochastic_k_15m, $row["value"]); } // Nacteni nejvyssi a nejnizsi hodnoty z pole $Stochastic_k_Hx_15 = max($Stochastic_k_15m); $Stochastic_k_Lx_15 = min($Stochastic_k_15m); $Stochastic_k_index15_vypocet = 100*(($obj['lastPrice']-$Stochastic_k_Lx_15)/($Stochastic_k_Hx_15-$Stochastic_k_Lx_15)); echo "Stochastic vysledek: ".$Stochastic_k_index15_vypocet; ?> |
||
Kajman Profil |
#2 · Zasláno: 7. 5. 2018, 18:08:02
Ve starších verzích mysql lze použít např. uživatelské proměnné...
SET @counter=0; SELECT id, value, @counter rownum FROM price HAVING (@counter:=@counter+1)%30=0 ORDER BY id DESC LIMIT 100 U novějších verzí mariadb by šly použít např. window funkce. |
||
inen Profil * |
#3 · Zasláno: 8. 5. 2018, 09:20:03
Děkuji za odpověď, ale nějak mi to nechce fungovat. Měl bych ještě dotaz z trochu jiného směru.
Každých 30 sekund načítám z api hodnoty a uložím do databáze. ID / Value / Date / Time Chtěl bych provést výběr z databáze podle času/id, tak aby to načetlo vždy jen hodnoty uložené každou: a) 1 minutu (tzn. 00:01, 00:02, 00:03,...) za posledních 14 dnů, aby ignoroval hodnoty mezi tím b) 15 minut (...) za posledních 14 dnů, aby ignoroval hodnoty mezi tím c) 1 hodinu (...) za posledních 14 dnů, aby ignoroval hodnoty mezi tím d) 24 hodin (...) za posledních 14 dnů, aby ignoroval hodnoty mezi tím tzn. vždy vznikne array (); které bude obsahovat jen požadované hodnoty. A to zpětně vždy 14 dnů od aktuálního času. Už pár dnů nad tím přemýšlím, ale zatím bez úspěchu. Prosím o radu. Děkuji za každou radu. |
||
Kajman Profil |
#4 · Zasláno: 8. 5. 2018, 10:56:46
Chcete, aby to bylo svižné? Máte možnost těch window funkcí?
|
||
inen Profil * |
#5 · Zasláno: 8. 5. 2018, 11:17:19
Aktuálně jedu na starším PC s Windows 10 a na něm je nainstalovaný WAMP server.
Window Functions bohužel vůbec neznám. Čím svižnější tím lepší :-) |
||
Keeehi Profil |
inen:
„Window Functions bohužel vůbec neznám.“ Nejde o to, zda je znáš ty ale zda je zná databáze. MySQL je zná od verze 8.0.2. Ty body a) - d) se provádějí v jednom a tom samém běhu scriptu? Jestli ano, pak žádný problém nemáš. Vybereš data pro a), což je obyčejný select všech záznamů za posledních 14 dní. To zvládne snad každá databáze. No a b) - d) jsou jen podmnožiny a). Jelikož pole pro a) už máš v paměti, stačí ti ho jen projít po správných indexech. A jen tak mimochodem, 20000 záznamů není až tak velké číslo a najít minimum a maximum v poli nebude tedy až tak velký problém. Přesto není potřeba toto pole vůbec vytvářet, protože minimum a maximum jde najít už v tom cyklu kde to pole vytváříš. <?php $url = 'www.xxx.com'; $obj = json_decode(file_get_contents($url), true); //db $conn = new mysqli("localhost", "root", "", "aa"); // Stochastic K index $Stochastic_k_15m = array(); $intervals = [1, 15, 60, 1440]; $min = array_fill(0, count($intervals), PHP_INT_MAX); $max = array_fill(0, count($intervals), PHP_INT_MIN); // výběr posledních 3000 položek z databaze, ale kazde 30 polozky podle ID a casu $result = $conn->query("SELECT value FROM price ORDER BY id DESC LIMIT 20160"); for($i = 0; $row = $result->fetch_assoc(); $i++) { foreach($intervals as $index => $interval ) { if($i%$interval === 0) { if($row['value'] < $min[$index]) { $min[$index] = $row['value']; } if($row['value'] > $max[$index]) { $max[$index] = $row['value']; } } } } foreach($intervals as $index => $interval ) { echo "Stochastic výsledek pro interval $interval minut: " . 100*(($obj['lastPrice']-$min[$index])/($max[$index]-$min[$index])) . "<br>\n"; } ?> Pokud ale ty window funkce máš, bude pak nejspíše nejlepší varianta nechat minimum a maximum spočítat už databázi. |
||
inen Profil * |
#7 · Zasláno: 8. 5. 2018, 14:38:46
MySQL mám verzi 5.7.21
Na druhou stranu není problém nainstalovat alternativu WAMP serveru. Doporučíš něco co je stejně "jednoduchého"? a) - d) Ano bude v rámci jednoho scriptu v tom samém běhu. Pokud budu chtít výsledky za minutu, tak v tom nevidím problém. Jednoduchý Select pro výběr 20 000 posledních položek z databáze. Jak, ale rozlišit ty podmnožiny? Dejme tomu 15-ti minutový interval. Původně jsem to chtěl udělat tak, že načtu každou 15. položku z databáze. Tam, ale nastává problém, že pokud dám SELECT databáze v 16:20, tak mi to bude načítat data zpětně v 16:05, 15:50, 15:35, 15:20,... Já bych, ale potřeboval záznamy z 16:00, 15:45, 15:30, 15:15,... Zatím mě, vůbec nenapadá jak je indexovat. |
||
inen Profil * |
#8 · Zasláno: 8. 5. 2018, 17:27:34
Ještě mě napadlo dát do scriptu co vkládá hodnoty do databáze něco takového - pro rozlišení:
<?php // kazdych 15 minut if (in_array(StrFTime("%M", Time()), array(00, 15, 30, 45))){ echo "Do databáze -> Sloupec 15minut -> Y"; } // kazdou hodinu if (in_array(StrFTime("%H:%M", Time()), array("00:00","01:00","02:00","03:00","04:00","05:00","06:00","07:00","08:00","09:00","10:00","11:00","12:00","13:00","14:00","15:00","16:00","17:00","18:00","19:00","20:00","21:00","22:00","23:00"))){ echo "Do databáze -> Sloupec 1hodina -> Y"; } // jednou za 24 hodin if (StrFTime("%H", Time()) == 00){ echo "Do databáze -> Sloupec 24hodin -> Y"; } ?> |
||
Kajman Profil |
#9 · Zasláno: 8. 5. 2018, 17:58:21
Zkuste toto, zda je to dostatečně rychlé...
SELECT t.*, p2.value first_value FROM (SELECT intervaly.sekund, intervaly.popis, p.date, Min(p.time) min_time, Min(p.value) min_value, Max(p.value) max_value, Avg(p.value) avg_value FROM price p CROSS JOIN (SELECT 'minuty' popis, 60 sekund FROM DUAL UNION ALL SELECT 'ctvrthodiny' popis, 15 * 60 sekund FROM DUAL UNION ALL SELECT 'hodiny' popis, 60 * 60 sekund FROM DUAL UNION ALL SELECT 'dny' popis, 24 * 60 * 60 sekund FROM DUAL) intervaly WHERE p.date BETWEEN Subdate('2018-05-08', 13) AND Date('2018-05-08') GROUP BY intervaly.popis, intervaly.sekund, p.date, Time_to_sec(p.time) DIV intervaly.sekund) t JOIN price p2 ON t.date = p2.date AND t.min_time = p2.time ORDER BY t.sekund DESC, t.date, t.min_time |
||
Keeehi Profil |
inen:
> Tam, ale nastává problém, že pokud dám SELECT databáze v 16:20, tak mi to bude načítat data zpětně v 16:05, 15:50, 15:35, 15:20,... > Já bych, ale potřeboval záznamy z 16:00, 15:45, 15:30, 15:15 To je ale velmi podstatná informace, kterou jsi nezmínil a v důsledku to úplně mění přístup k problému. SELECT MIN(value), MAX(value) FROM (SELECT value FROM price WHERE date > NOW() - INTERVAL 14 DAY ORDER BY date DESC) t; SELECT MIN(value), MAX(value) FROM (SELECT value FROM price WHERE date > NOW() - INTERVAL 14 DAY AND MINUTE(date) in (0, 15, 30, 45) ORDER BY date DESC) t; SELECT MIN(value), MAX(value) FROM (SELECT value FROM price WHERE date > NOW() - INTERVAL 14 DAY AND MINUTE(date) = 0 ORDER BY date DESC) t; SELECT MIN(value), MAX(value) FROM (SELECT value FROM price WHERE date > NOW() - INTERVAL 14 DAY AND HOUR(date) = 0 AND MINUTE(date) = 0 ORDER BY date DESC) t; Mělo by to být snad dostatečně rychlé. Pokud ne, tak to bude testováním, těch určených intervalů. V takovém případě by se přistoupilo k denormalizaci právě skrz ty pomocné sloupce, jak tě to napadlo. Ale to jen v případě, že by to bylo pomalé. Jen bych ten výpočet pomocných sloupců nechal pak na MySQL. A taky jsi nikde neuvedl, zda bereš 14 dní jako 20160 minut (což je trochu problém v období změny letního a zimního času) nebo chceš zažít vždy půlnocí 13 celých dní nazpět + ta část dne, co zatím dnes uběhla. |
||
inen Profil * |
#11 · Zasláno: 9. 5. 2018, 16:09:29
Děkuji mockrát. Nakonec jsem použil :
SELECT MIN(value), MAX(value) FROM (SELECT value FROM price WHERE date > NOW() - INTERVAL 14 DAY ORDER BY date DESC) t; SELECT MIN(value), MAX(value) FROM (SELECT value FROM price WHERE date > NOW() - INTERVAL 14 DAY AND MINUTE(date) in (0, 15, 30, 45) ORDER BY date DESC) t; SELECT MIN(value), MAX(value) FROM (SELECT value FROM price WHERE date > NOW() - INTERVAL 14 DAY AND MINUTE(date) = 0 ORDER BY date DESC) t; SELECT MIN(value), MAX(value) FROM (SELECT value FROM price WHERE date > NOW() - INTERVAL 14 DAY AND HOUR(date) = 0 AND MINUTE(date) = 0 ORDER BY date DESC) t; A vše funguje. Snad tedy. Reálné výsledky se dozvím až budu mít 14 dnů dat. |
||
Kajman Profil |
#12 · Zasláno: 9. 5. 2018, 18:18:53
Pokud je sloupec date typu date a ne datetime (tedy tam je jen datum bez času jak píšete v [#3]), tak to nebude počítat dobře.
V takovém případě musíte ve funkcích minute a hour používat sloupec, kde je čas. Další problém bude, že do vzorku se přidají např. všechny hodnoty z první minuty tedy 8:01:00 i 8:01:30. Možná by pomohlo přidat i podmínky, že sekundy z toho času jsou menší než 30. |
||
inen Profil * |
#13 · Zasláno: 9. 5. 2018, 20:43:54
Nakonec jsem omezil načítání z api/vkládání do databáze jednou za minutu. A to vždy v celou minutu. Stává se ale, že se to vloží do databáze např. 16:00:02, 16:01:01, 16:02:02,... To by, ale vliv mít nemělo, že?
Jinak ve sloupci date je i čas ve formátu: 2018-05-09 19:57:01 Takže by mělo být vše korektní, že? |
||
Kajman Profil |
#14 · Zasláno: 9. 5. 2018, 21:40:16
Ano, pokud nebude v minutě více záznamů a je to datetime, tak to bude fungovat.
Lze to i zkrátit. Order by je k ničemu a poddotaz také není potřeba. Pro test si můžete dát i count(*), abyste věděl, z kolika vzorků hodnot se hraniční hodnoty hledaly. SELECT min(`value`), max(`value`) FROM `price` WHERE `date` > Now() - INTERVAL 14 day AND Minute(`date`) IN ( 0, 15, 30, 45 ) |
||
inen Profil * |
Děkuji za odpovědi. Tohle je tedy nejkratší možný zápis? Mám to správně? :-)
<?php // připojení k databázi $conn = new mysqli("localhost", "root", "", ""); $url = 'https://www.xxx.com/'; $obj = json_decode(file_get_contents($url), true); // Výpočet Stochastic - K indexu // Vzorec: %K = 100((C-Lx)/(Hx-Lx)) // Kde: Lx je nejnižší bod (low) za vybraný časový úsek, Hx je nejvyšší bod (high) za vybraný časový úsek, C je poslední zavírací cena (close) na příslušném časovém období (timeframu), //Stochastic 1 minuta - 14 dnů $Stochastic_K_1minuta = $conn->query("SELECT MIN(value), MAX(value) FROM price WHERE date > NOW() - INTERVAL 14 DAY")->fetch_assoc(); $Stochastic_K_1minuta_vypocet = round(100*(($obj['lastPrice']-$Stochastic_K_1minuta["MIN(value)"])/($Stochastic_K_1minuta["MAX(value)"]-$Stochastic_K_1minuta["MIN(value)"])), 1); //Stochastic 15 minut - 14 dnů $Stochastic_K_15minut = $conn->query("SELECT MIN(value), MAX(value) FROM price WHERE date > Now() - INTERVAL 14 day AND Minute(date) IN (0,15,30,45)")->fetch_assoc(); $Stochastic_K_15minut_vypocet = round(100*(($obj['lastPrice']-$Stochastic_K_15minut["MIN(value)"])/($Stochastic_K_15minut["MAX(value)"]-$Stochastic_K_15minut["MIN(value)"])), 1); //Stochastic 1 hodina - 14 dnů $Stochastic_K_1hodina =$conn->query("SELECT MIN(value), MAX(value) FROM price WHERE date > Now() - INTERVAL 14 DAY AND MINUTE(date) = 0 ")->fetch_assoc(); $Stochastic_K_1hodina_vypocet = round(100*(($obj['lastPrice']-$Stochastic_K_1hodina["MIN(value)"])/($Stochastic_K_1hodina["MAX(value)"]-$Stochastic_K_1hodina["MIN(value)"])), 1); //Stochastic 1 den - 14 dnů $Stochastic_K_1den = $conn->query("SELECT MIN(value), MAX(value) FROM price WHERE date > NOW() - INTERVAL 14 DAY AND HOUR(date) = 0 AND MINUTE(date) = 0")->fetch_assoc(); $Stochastic_K_1den_vypocet = round(100*(($obj['lastPrice']-$Stochastic_K_1den["MIN(value)"])/($Stochastic_K_1den["MAX(value)"]-$Stochastic_K_1den["MIN(value)"])), 1); echo "Stochastic vysledek - 1 minuta: ".$Stochastic_K_1minuta_vypocet."<br>"; echo "Stochastic vysledek - 15 minut: ".$Stochastic_K_15minut_vypocet."<br>"; echo "Stochastic vysledek - 1 hodina: ".$Stochastic_K_1hodina_vypocet."<br>"; echo "Stochastic vysledek - 1 den: ".$Stochastic_K_1den_vypocet."<br>"; ?> //edit... Je tedy fakt, že za minutu a hodinu se mi teď vypisují stejné výsledky, takže tam asi mám chybu /// edit2 - tak kecám - byla to jen náhoda několika minut... Teď už tam rozdíl je: Stochastic vysledek - 1 minuta: 40.1 Stochastic vysledek - 15 minut: 40.6 Stochastic vysledek - 1 hodina: 40 Stochastic vysledek - 1 den: 15.8 |
||
Kajman Profil |
#16 · Zasláno: 11. 5. 2018, 01:01:32
Zkrátit to lze tím, že nebudete stejné nebo podobné kusy kódu tapetovat, ale uděláte si alespoň pomocnou funkci, abyste případnou změnu dělal na jednom místě a ne na čtyřech. Tedy např. něco takového...
<?php // připojení k databázi $conn = new mysqli("localhost", "root", "", ""); $url = 'https://www.xxx.com/'; $obj = json_decode(file_get_contents($url), true); // Výpočet Stochastic - K indexu // Vzorec: %K = 100((C-Lx)/(Hx-Lx)) // Kde: Lx je nejnižší bod (low) za vybraný časový úsek, Hx je nejvyšší bod (high) za vybraný časový úsek, C je poslední zavírací cena (close) na příslušném časovém období (timeframu), function stochastic_formula($C, $Lx, $Hx, $scale=1) { return round(100*(($C-$Lx)/($Hx-$Lx)), $scale); } function stochastic_from_db($conn, $C, $add_condition='', $days=14) { $data = $conn->query("SELECT MIN(value) minv, MAX(value) maxv FROM price WHERE date > Now() - INTERVAL {$days} day {$add_condition}")->fetch_assoc(); return stochastic_formula($C, $data['minv'], $data['maxv']); } //Stochastic 1 minuta - 14 dnů $Stochastic_K_1minuta_vypocet = stochastic_z_db($conn, $obj['lastPrice']); //Stochastic 15 minut - 14 dnů $Stochastic_K_15minut_vypocet = stochastic_z_db($conn, $obj['lastPrice'], "AND Minute(date) IN (0,15,30,45)"); //Stochastic 1 hodina - 14 dnů $Stochastic_K_1hodina_vypocet = stochastic_z_db($conn, $obj['lastPrice'], "AND MINUTE(date) = 0"); //Stochastic 1 den - 14 dnů $Stochastic_K_1den_vypocet = stochastic_z_db($conn, $obj['lastPrice'], "AND HOUR(date) = 0 AND MINUTE(date) = 0"); |
||
inen Profil * |
#17 · Zasláno: 11. 5. 2018, 20:13:29
Děkuji za odpověď.
|
||
inen Profil * |
Ještě bych měl jeden dotaz.
Chci zobrazit poslední hodnoty - od aktuálního času 14 hodnot v rozmezí 15 minut Zkoušel jsem tohle: SELECT value FROM price WHERE date > Now() - INTERVAL 3.5 HOUR AND Minute(date) IN (0,15,30,45) Zobrazí mi to ale 16 záznamů. Jak to? V jedné hodině 4 záznamy - tzn. 4 záznamy * 3 a půl hodiny = 14 záznamů. Proč tedy 16 ? Děkuji za odpověď. // edit vyřešil jsem to: INTERVAL 210 MINUTE Ale i tak, proč? |
||
Kajman Profil |
#19 · Zasláno: 12. 5. 2018, 21:37:47
Vypište si i date.
|
||
inen Profil * |
#20 · Zasláno: 12. 5. 2018, 22:06:27
aha, hloupý dotaz :-)
|
||
Časová prodleva: 6 let
|
0