Autor Zpráva
houbín
Profil
Zdravím.

Mám takovouto tabulku:
datum | cas | teplota | vlhkost | vitr | srazky | oblacnost

Potřebuji vypsat max a min u teploty, max vítr a max srážky. Budou tedy 4 výsledky a ke každému bych chtěl ještě přidat datum. Zkoušel jsem různé příkazy, ale nedošel jsem na to, jak přiřadit k výsledku agregační funkce ještě datum. Mohl bych udělat čtyři samostatné příkazy, ale připadá mi to nevhodné.

Pro jeden záznam jsem vymyslel tento jednoduchý příkaz, ale jak do toho narvat ještě MIN(teplota), atd. nevím.

SELECT MAX(teplota), datum FROM tabulka
juriad
Profil
Použij 4 dotazy. Ten dotaz, který jsi napsal totiž ani nevrací to, co bys čekal; správně je to:

SELECT t1.*
FROM tabulka t1
JOIN (
  SELECT max(t2.teplota) teplota
  FROM tabulka t2
) t3 ON t1.teplota = t3.teplota;

Pozor, toto vrátí všechny řádky s nejvyšší teplotou. Pokud bys chtěl jen ten nejnovější:

SELECT date(max(timestamp(t1.datum, t1.cas))) AS datum, time(max(timestamp(t1.datum, t1.cas))) AS cas, t1.teplota
FROM tabulka t1
JOIN (
  SELECT max(t2.teplota) teplota
  FROM tabulka t2
) t3 ON t1.teplota = t3.teplota;

Pokud chceš informace o vlhkosti, atp. pro nejvyšší teplotu, musíš přidat další úroveň:

SELECT t0.*
FROM tabulka t0
JOIN (
  SELECT max(timestamp(t1.datum, t1.cas)) AS dt, t1.teplota
  FROM tabulka t1
  JOIN (
    SELECT max(t2.teplota) teplota
    FROM tabulka t2
  ) t3 ON t1.teplota = t3.teplota;
) t4 ON t0.teplota = t4.teplota AND timestamp(t0.datum, t0.cas) = t4.dt

Mimochodem, máš nějaký důvod použít místo jednoho sloupce typu DATETIME dva sloupce typů DATE a TIME? Zbytečně se tím komplikuje ten dotaz. (Viz zvýrazněné části.)
houbín
Profil
Měření se provádí v rámci možností jen 2x denně (každý den ve stejné časy), takže sloupec 'cas' obsahuje pouze hodnoty 1, nebo 2.

Děkuji za radu. Zjistil jsem, že SQL rozumím méně, než jsem myslel.

Možná jsem se nevyjádřil správně, nebo nerozumím řešení. Pomocí JOIN spojím přece více tabulek. Já mám však jen jednu tabulku, kde jednotlivé atributy jsou 'teplota', atd., jak jsem psal v předchozím příspěvku.

Moje myšlenka, proč raději vymyslet jeden příkaz místo čtyř samostatných, byla taková, že bych zbytečně zatěžoval (teoreticky) server. Za 2 roky bude v databázi přibližně 15–20 tis. záznamů, takže se snažím myslet dopředu. Údaje, které chci vypsat, budou vedeny jako rekordy od počátku měření.

EDIT: snad jsem to nějak pochopil, SQL vrací přesně to, co potřebuji, děkuji. takové použití JOINu by mě nenapadlo.
juriad
Profil
Prosím tě, zbav se toho sloupce cas; je úplná blbost ukládat tam číslo 1 nebo 2. Až se za rok rozhodneš, že chceš měřit častěji, budeš přepisovat všechny skripty, aby ukazovaly správný čas?
Navrhuji sloupce datum a cas sloučit do jednoho, asi bych mu ponechal název datum a byl by typu DATETIME. Z tohoto sloupce můžeš vždy zjistit datum i čas zvlášť. A z času můžeš zjistit, zda to bylo dopoledne nebo odpoledne. Jedině, pokud bys chtěl zpracovávat dopoledne a odpoledne úplně zvlášť, tak by se to vyplatilo rozlišit zvláštním sloupcem.

Ano, máš jen jednu tabulku, ale já v tom dotazu propojuju tabulku s výsledkem nějakého poddotazu.

SELECT max(t2.teplota) teplota
FROM tabulka t2
je dotaz, který vratí maximální teplotu, jediný řádek

(
  SELECT max(t2.teplota) teplota
  FROM tabulka t2
) t3
je poddotaz, který se tváří jako tabulka s jedním řádkem

SELECT t1.*
FROM tabulka t1
JOIN (
  SELECT max(t2.teplota) teplota
  FROM tabulka t2
) t3 ON t1.teplota = t3.teplota;
je dotaz, který vrátí všechny řádky tabulky, které mají shodnou teplotu jako některý (ve skutečnosti víme, že jeden) řádek poddotazu.

(
  SELECT max(timestamp(t1.datum, t1.cas)) AS dt, t1.teplota
  FROM tabulka t1
  JOIN (
    SELECT max(t2.teplota) teplota
    FROM tabulka t2
  ) t3 ON t1.teplota = t3.teplota;
) t4
je poddotaz, který se tváří jako tabulka, která má jeden řádek - teplotu (víme, že maximální) a datetime (víme, že poslední), kdy událost nastala

SELECT t0.*
FROM tabulka t0
JOIN (
  SELECT max(timestamp(t1.datum, t1.cas)) AS dt, t1.teplota
  FROM tabulka t1
  JOIN (
    SELECT max(t2.teplota) teplota
    FROM tabulka t2
  ) t3 ON t1.teplota = t3.teplota;
) t4 ON t0.teplota = t4.teplota AND timestamp(t0.datum, t0.cas) = t4.dt
je dotaz, který vrátí všechny záznamy (víme, že bude jeden), které mají stejnou teplotu (maximální) a stejný datetime (poslední).

Záleží, o jaké záznamy máš zájem z databáze. Pokud by tě vždy zajímala jen extrémní hodnota a datetime, kdy naposledy nastala, a nic jiného, tak by to šlo malinko zkrátit na úroveň 3. dotazu (s ORDER BY dt DESC LIMIT 1).
Jelikož dotazy na teploty, vítr a srážky vrací stejné údaje, můžeš je vytáhnout z databáze UNIONem. Ale to je spíš jen mikrooptimalizace, kterou bych si zpočátku i odpustil.
TomášK
Profil
Předpokládám, že pro každý čas je jen jedno měření. Pak ten dotaz jde zkrátit na
SELECT datum, cas, teplota FROM tabulka ORDER BY teplota DESC, datum DESC, cas DESC LIMIT 1

JOIN je potřeba, pokud by vás zajímaly všechny záznamy, kdy bylo dosaženo maxima, nejen poslední. Čtyři dotazy jsou správné řešení. Zátěž serveru pro 15-20 tisíc je nezajímavá, je to tak málo, že se tím nemusíte zabývat. S vhodnými indexy ty čtyři dotazy budou během pár ms.
houbín
Profil
Děkuji za rady. Nakonec jsem využil návrhu od TomášK. Nevím, proč mě to nenapadlo! Někdy člověk přemýšlí příliš složitě :D

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: