« 1 2 »
Autor Zpráva
Pepik1
Profil
Dobrý den všem, chtěl bych Vás požádat o Vaší pomoc. Řeším jeden příkaz a nevím si sním rady.
Mám tabulku viz níže:

id user_id katageie_id value
1 user_1 a 9
2 user_2 a 15
3 user_3 a 6
5 user_1 b 3
6 user_2 b 1
7 user_3 b 1
9 user_1 c 6
10 user_2 c 5
11 user_3 c 2


1) Potřeboval bych docílit toho aby hodnoty z value se seskupily do skupin (a,b,c) a seřadily se od nejmneší po největší v každyý katageiri.

user_id a b c
user_1 9 3 6
user_2 15 2 5
user_3 6 2 2

2) Seřazená čísla by se nahradila indexem umístění 1=nejmenší; xx=největší. A když budou čísla stejná(jako v kategorii b bude tam index stejný "user_2 i user_3 májí inxex 1", protože mají oba stejné umístění.)

user_id a b c
user_1 2 2 3
user_2 3 1 2
user_3 1 1 1


3) A nakonec by se prvky v poli user_x(indexy_umístění) sečetli do pole user_x["soucet"] a seřadily od nejmenšího hodnocení po nejvýší. -Požadovaný výstup

user_id soucet
user_3 3
user_2 6
user_1 7

Budu hrozně moc rád za Vaší pomoc.

Předem děkuji
Kajman
Profil
Pro jakou databázi a pro jakou její verzi?

Nebo to chcete počítat v php?

A user_1 má dostat za kategorii b dva body nebo tři? Většinou když jsou dvě zlaté mediale, tak se pak dá totiž bronzová a vy tam máte stříbrnou.

Pokud jde jen o poslední výsledek a chcete to řešit v databázi, tak si to rozdělení do skupin udělejte do řádků místo sloupců, s tím se jí bude pracovat lépe.
Pepik1
Profil
Kajman:
1) Jedná se o MYSQL verze 5.6.28. Ale je jedno, jestli se to bude počítat rovnou z DB nebo v php. Jde mi pouze o ten výsledek

2) user_1 má dostat 2 body, je to tak, jak jsem napsal.

3) Ano jde jen o poslední výsledek. Rozepsal jsem to tak jen pro pochopení.
Kdyby to šlo udělat nějak jednodušeji, byl bych jedině rád.
Kajman
Profil
Pro tak starou verzi by to to mohlo jít přes temporary tabulku.
CREATE temporary TABLE test_body_tmp AS
  SELECT user_id,
         kategorie_id,
         Min(value) nejmensi
  FROM   test_body
  GROUP  BY user_id,
            kategorie_id;

SELECT user_id,
       Sum(poradi) soucet,
       Count(*)    kategorii
FROM   (SELECT user_id,
               kategorie_id,
               (SELECT Count(DISTINCT t2.nejmensi)
                FROM   test_body_tmp t2
                WHERE  t2.kategorie_id = t1.kategorie_id
                       AND t2.nejmensi <= t1.nejmensi) poradi
        FROM   test_body_tmp t1) r
GROUP  BY user_id
ORDER  BY kategorii DESC,
          soucet

Pokud v té tabulce nemůže být více řádků se stejnou kombinací (user_id, kategorie_id), tak ta temporary tabulky potřeba není.
Pepik1
Profil
Kajman:

Nemůže nastat stejná kombinace. Viz tabulka.

id user_id katageie_id value
1 user_1 a 9
2 user_2 a 15
3 user_1 a 9
(todle nastat nemůže)

Takže by měl stačit pouze dotaz

SELECT user_id,
       Sum(poradi) soucet,
       Count(*)    kategorii
FROM   (SELECT user_id,
               kategorie_id,
               (SELECT Count(DISTINCT t2.nejmensi)
                FROM   test_body_tmp t2
                WHERE  t2.kategorie_id = t1.kategorie_id
                       AND t2.nejmensi <= t1.nejmensi) poradi
        FROM   test_body_tmp t1) r
GROUP  BY user_id
ORDER  BY kategorii DESC,
          soucet

A jak poté bude vypadat tedy ten výpis, abych docílil tohoto formátu?

user_id soucet
20 3
12 6
6 7



Jinak vážně děkuji moc, za pomoc.
Kajman
Profil
A nestačí tam použít správný název tabulky a sloupečku (value místo nejmensi)?

Sloupeček s počtem kategorií jsem tam dal navíc, abyste mohl kontrolovat, zda měl uživatel záznam pro všechny kategorie. Stačí ho v php nevypsat, ne?
Pepik1
Profil
Kajman:
Vy jste psal, že by se nemusela používat at Temporary tabulka. Tak jsem myslel, že bych to udělal bez ní a výstup, který potřebuju je.

Pole
user_1 -> 3
user_3 -> 6
user_2 -> 7
(součet pořadí)

Jinak tabulka s kterou pracuji má tyto sloupce id; user_id; katageie_id; value a nazývá se (challenge_result).

Prosím pomohl bys mi to teda, dát do kupy? Bohužel se v tomhle moc nevyznám. A jsem Vám vděčný za každou radu.
Kajman
Profil
Stačí v tom dotaze nahradit řetězce test_body_tmp za challenge_result a nejmensi za value. Kdyby to pak házelo chybu, tak ji sem vypište i s tím upraveným dotazem.
Pepik1
Profil
Kajman:
Tak jsem to vyzkoušel a neháže to žádnou chybu a ani žádný výsledek.

mysql_query("CREATE temporary TABLE test_body_tmp AS
  SELECT user_id,
         kategorie_id,
         Min(value) value
  FROM   challenge_result
  GROUP  BY user_id,
            kategorie_id;");
             


$query = mysql_query("SELECT user_id,
       Sum(poradi) soucet,
       Count(*)    kategorii
FROM   (SELECT user_id,
               kategorie_id,
               (SELECT Count(DISTINCT t2.value)
                FROM   test_body_tmp t2
                WHERE  t2.kategorie_id = t1.kategorie_id
                       AND t2.value <= t1.value) poradi
        FROM   test_body_tmp t1) 
GROUP  BY user_id
ORDER  BY kategorii DESC,
          soucet");   
$user=MySQL_Fetch_Array($query);
Kajman
Profil
Ale vždyť neověřujte výsledek, zda nedošlo k chybě v dotazu...
Některé časteji řešené dotazy pro MySQL - FAQ » Jak si vypsat chybu

V prvním dotaze může být problém se středníkem. Pak by spadnul i druhý. Ale pokud tam jsou jedinečné hodnoty, tak tu temporary tabulku nepotřebujete.

A mysql_ funkce už nepoužívejte, pište to rovnou v mysqli.

Dotaz si navíc můžete vyzkoušet bokem, např. v admineru.
Pepik1
Profil
Kajman, Pepik1:
Tak středníku jsem si nevšiml a na výpis chyby jsem taky zapoměl.

První dotaz píše chybu.
Access denied for user 'xx'@'88.86.12%' to database 'yy'

Druhý :
Query was empty

Upravil jsem to taklo, bez té temporary tabulky.

$query = mysqli_query("SELECT user_id,
       Sum(poradi) soucet,
       Count(*)    kategorii
FROM   (SELECT user_id,
               kategorie_id,
               (SELECT Count(DISTINCT t2.value)
                FROM   challenge_result t2
                WHERE  t2.kategorie_id = t1.kategorie_id
                       AND t2.value <= t1.value) poradi
        FROM   challenge_result t1) 
GROUP  BY user_id
ORDER  BY kategorii DESC,
          soucet");   
Kajman
Profil
Funkce mysqli_query má první parametr identifikátor spojení. Už jste v php někdy s databází pracoval? Jestli ne, nejdříve si o tom něco přečtěte. Ve výsledku to bude rychlejší než nacházet slepé uličky postupem pokus-omyl.
Pepik1
Profil
Kajman:
Pracoval, ale s funkci mysqli ne. Nejsem programátor, tak plno věcí neznám, ale chtěl jsem něco vytořit. Jdu na to kouknu. Vždy jsem používal mysql_query.
Taps
Profil
Pepik1:
POkud se nepletu tak princip sql dotazů je stejný jak v mysql tak i v mysqli.
Pepik1
Profil
Kajman:
$query = mysqli_query($con, "SELECT user_id,
       Sum(poradi) soucet,
       Count(*)    kategorii
FROM   (SELECT user_id,
               kategorie_id,
               (SELECT Count(DISTINCT t2.value)
                FROM   challenge_result t2
                WHERE  t2.kategorie_id = t1.kategorie_id
                       AND t2.value <= t1.value) poradi
        FROM   challenge_result t1) 
GROUP  BY user_id
ORDER  BY kategorii DESC,
          soucet"); 

Stále to píše to samé Query was empty
Kajman
Profil
Tento kód to asi těžko vypisuje. Dotaz v admineru funguje?
Pepik1
Profil
Kajman:
Dík moc za ten Adminer, vůbec jsem nevěděl, že něco takového existuje, ale dotaz jsem dal do kupy.
SELECT user_id,
       Sum(poradi) soucet,
       Count(*)    kategorii
FROM   (SELECT user_id,
               exercise_id,
               (SELECT Count(DISTINCT t2.value)
                FROM   challenge_result t2
                WHERE  t2.exercise_id = t1.exercise_id
                       AND t2.value <= t1.value) poradi
        FROM   challenge_result t1) r
WHERE exercise_id=32 || exercise_id=34
GROUP  BY user_id
ORDER  BY kategorii DESC,
          soucet

Ale potřeboval bych ještě 1 věc.

Doplnit do tabulku JOIN
Tabulku challenge_result.user_id připojit
na tabulku registration.user_id a z tabulky registration bych potřeboval sloupec category_id

a

Tabulku challenge_result.user_id připojit
na tabulku user.id a z tabulky user bych potřeboval sloupec last_name

A to bude vše a budu ti vážně vděčný. Zkoušel jsem to, ale nepovedlo se mi to.
Keeehi
Profil
Pepik1:
Nevím, zda je to v tomto případě potřeba ale vždy to celé můžeš vzít jako subdotaz, dát tomu výsledku alias a joinovat na to.
SELECT *
FROM ( ten původní dotaz ) t3
JOIN registration ON t3.user_id = registration.user_id
JOIN user ON t3.user_id = user.id
Pepik1
Profil
Díky moc
Kajman
Profil
Jen to order by presuňte až na konec nového dotazu.
Keeehi
Profil
Kajman:
Fungoval by ten join i v původním dotazu? Jelikož je tam group by podle sloupce podle kterého se dělá join, tak si říkám, že by to mohlo fungovat ale tvrdit si to netroufám.
Kajman
Profil
Asi jo, ale raději bych to takto obalil, aby plánovač mysql měl méně šancí dotaz zpomalit.
Pepik1
Profil
Tak nadšení bylo předčasné, nedělá to to co má. Nevíte někdo čím by to mohlo být? I když vyberu pouze 1 kategorii, tak ty součty.

SELECT  *
FROM ( SELECT user_id,
       Sum(poradi) soucet,
       Count(*)    kategorii
FROM   (SELECT user_id,
               exercise_id,
               (SELECT Count(DISTINCT t2.value)
                FROM   challenge_result t2
                WHERE  t2.exercise_id = t1.exercise_id 
                       AND t2.value <= t1.value) poradi
        FROM   challenge_result t1) r
WHERE (exercise_id=36 OR exercise_id=34) 
GROUP  BY user_id) t3
JOIN registration ON t3.user_id = registration.user_id
JOIN users ON t3.user_id = users.id
WHERE category_id=11
ORDER  BY soucet
Kajman
Profil
Pokud se to pořadí má určovat jen vůči uživatelům v category_id 11, tak ta podmínka musí být i v tom výpočtu bodů...

SELECT t3.*,
       users.last_name
FROM   (SELECT user_id,
               Sum(poradi) soucet,
               Count(*)    kategorii
        FROM   (SELECT user_id,
                       exercise_id,
                       (SELECT Count(DISTINCT t2.value)
                        FROM   challenge_result t2
                               JOIN registration r2
                                 ON t2.user_id = r2.user_id
                                    AND r2.category_id = 11
                        WHERE  t2.exercise_id = t1.exercise_id
                               AND t2.value <= t1.value) poradi
                FROM   challenge_result t1
                       JOIN registration r1
                         ON t1.user_id = r1.user_id
                            AND r1.category_id = 11
                WHERE  exercise_id IN ( 34, 36 )) r
        GROUP  BY user_id) t3
       JOIN users
         ON t3.user_id = users.id
ORDER  BY kategorii DESC,
          soucet



Když už tam je tolik podmínek, tak se možná přeci jen ta temporary tabulka mohla hodit, aby ten filtr na exercise_id a category_id byl jen jednou. Těžko říci, co bude ryhlejší.

Nebo přejít na mariadb 10.2.+, která umí window funkce.
Pepik1
Profil
Kajman:
Jinak obdivuji tvé znalosti. V Admineru mi to píše chybu.

Chyba v dotazu (1052): Column 'user_id' in field list is ambiguous


Vyřešeno, snad už to bude šlapat
Kajman
Profil
Asi tam chybělo t1.user_id na řáxku 6, jen jsem dotaz odhadoval :-)

Snad jen jedna věc. Myslel jsem, že méně bodů znamená lépe, ale pokud to jsou naopak nejhorší, tak řaďte dle součtu a počet kategorií, které tam stále cpu, nemá být prvotní řadící kritérium.
Pepik1
Profil
Už to začíná vypadat, ale furt tam něco nesedí.
Ještě můžu dodat, že sloupec value(varchar) a můžou v něm být 3 typy hodnot Čas(6:01), body(35) nebo
body (35,5). Do sloupce "type" doplnuji jestli je to format(Time,number nebo float).

když vyberu pouze jednu exercise_id IN ( 34) typu čas, seřadíme se to:
4 (poslední je na 1 místě)
1
2
3

když vyberu pouze jednu exercise_id IN ( 32) typu body(číslo), seřadíme se to:
5 (poslední je na 1 místě)
1 (Ten co má být 1 je na 2 místě
4
3
2 (Ten co má být 2 je na posledním míste a potom už to jde posloupností nahoru.

Omlouvám se ty formáty v sloupci value jsem si neuvědomil.


Kajman:
Je to tak, nesedí to jen u toho nejhrošího, řadího to na 1 místo
Kajman
Profil
Podle řetězce nemůžete správně řadit, protože '2'>'19' a '9:59'>'10:00'!
Pepik1
Profil
Kajman:
Aha a řešení? Zkusit to teda přes PHP?
Jinak vždy kategorie bude mít stejný formát. Kategorie a (všechny záznamy int)
Kategorei b (všechny záznamy time)
Kajman
Profil
Možná bude nejjednodušší přidat do tabulky challenge_result sloupce
value_time
value_number
value_float (float nebo decimal)
Převést z nynějšího varcharu do odpovídajího sloupce dle konfigurace a v ostatních nechal null hodnoty. A při ukládání nových hodnot vždy vyplnit dvě hodnoty - value i value_spravnydatovytyp.

Pak stačí místo
AND t2.value <= t1.value
napsat
AND (t2.value_time <= t1.value_time OR t2.value_number <= t1.value_number OR t2.value_float <= t1.value_float)


Nebo necháte value a přidáte číslo value_normalized, kde bude číslo pro porovnání (čas převést na sekundy, u desetinných míst udělal posun dle konfigurace nebo použít decimal, pokud je jejich počet omezený).
« 1 2 »

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: