ugrás a tartalomhoz

SQL Join-ban szűrés

shark300 · 2011. Aug. 21. (V), 21.47
Sziasztok!

Egyszerű adatbázis utasítással lehetséges lenne-e az összes termosztátot kilistázni, és a hozzá tartozó utolsó hőmérséklet-et? Mert eddig csak arra találtam módot, hogy listázom a termosztátokat, és utána a maximális hőmérsékletet a termosztátokhoz.
DDL:
  1. CREATE TABLE `temperature` (  
  2.   `temp_id` int(11) NOT NULL AUTO_INCREMENT,  
  3.   `therm_id` int(11) NOT NULL,  
  4.   `temp_current` DOUBLE NOT NULL,  
  5.   `datetimestamp NOT NULL,  
  6.   PRIMARY KEY (`temp_id`),  
  7.   KEY `term_id` (`therm_id`)  
  8. ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=16607333 ;  
  9.   
  10. CREATE TABLE `thermostat` (  
  11.   `therm_id` int(11) NOT NULL AUTO_INCREMENT,  
  12.   `therm_name` varchar(50) NOT NULL,  
  13.   PRIMARY KEY (`therm_id`)  
  14. ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=18 ;  
  15.   
  16. ALTER TABLE `temperature`  
  17.   ADD CONSTRAINT `temperature_ibfk_3` FOREIGN KEY (`therm_id`) REFERENCES `thermostat` (`therm_id`),  
Segítségeteket köszönöm!
 
1

Félek, hogy rosszul értem,

H.Z. v2 · 2011. Aug. 22. (H), 07.40
Félek, hogy rosszul értem, mit is szeretnél, de

SELECT a.therm_id,a.therm_name,MAX(b.temp_current) FROM thermostat a,temperature b WHERE a.therm_id=b.therm_id GROUP BY a.therm_id,a.therm_name;

Nem ezt akarod? (100%-ig nem vagyok biztos benne, hogy szintaktikailag OK, rég játszottam SQL-lel :( )
2

Válaszod köszönöm! Lehet

shark300 · 2011. Aug. 22. (H), 08.18
Válaszod köszönöm!

Lehet elég kevés infót adtam meg.
Szóval:
Vannak a termosztátok (thermostat táblában felsorolva), amelyek 5 percenként mintát vesznek, és beszúrnak egy új rekordot a temperature táblába.
Azt kéne megoldanom, hogy az összes termosztátot kilistázni, és mellé az utoljára mért hőmérsékletet is, és nem akarom feltétlenül a termosztátokat kilistázni, és utólag, új selecttel hozzá venni a legutolsó hőmérsékletet.
Arra gondoltam, hogy inner join-nal összekötöm a termosztátonként grouppolt hőmérsékleteket, csak ugye a sellistában nem állhat nem aggregált attribútum a group attribútuma mellett (pl. MAX(date), temp_id).
Vagy rendezett, limit 1-gyel ellátott selecttel kapcsolom össze.

Sajnos egyre inkább úgy érzem, hogy amit szeretnék, egyszerű sql-ben nem lehet megcsinálni, lehet, mivel postgres a szerver, írok rá egy függvényt.
3

Bocs, szokás szerint csak

H.Z. v2 · 2011. Aug. 22. (H), 08.54
Bocs, szokás szerint csak félig olvastam el amit írtál. :(
(most az átlagosnál is hülyébb vagyok, mert dokihoz készülök és ahogy a múltkor elnéztem, a doki sem áll jobban agyilag, mint én :( )

Esetleg a HAVING nem segít? (tartok tőle, hogy nem)

Ehhh... azt hiszem, most jobb lesz, ha eldugulok.
4

Szerintem alaptalanul vannak

Hidvégi Gábor · 2011. Aug. 22. (H), 09.29
Szerintem alaptalanul vannak önértékelési gondjaid.
22

Francokat... amit itt

H.Z. v2 · 2011. Aug. 22. (H), 16.24
Francokat... amit itt hajnalban elkövettem... Részeg még életemben nem voltam, de így utólag kb. ilyesmire saccolom azt a "spicces"-nek nevezett állapotot... :DDD
(hűűű... ezt a mai dokit szívesen elmesélném valakinek... azt hittem, egészségügyben engem már nem érhet meglepetés. Tévedtem. Szóval nem volt alaptalan a reggeli agybajom :( :D )
5

Én valami ilyesmit csinálnék.

bb0072 · 2011. Aug. 22. (H), 11.20
Én valami ilyesmit csinálnék. MySQL-ben ez vagy valami hasonló biztosan működne, postgre-ben nem vagyok biztos.
  1. SELECT therm_id, therm_name, temp_current  
  2. FROM (  
  3.       SELECT therm.therm_id, therm_name, temp_current  
  4.       FROM thermostat therm  
  5.           LEFT JOIN temperature temp ON (therm.therm_id = temp.therm_id)  
  6.       ORDER BY date DESC  
  7.      )  
  8. GROUP BY therm_id  
6

Pont úgy egyikben sem fog

kuka · 2011. Aug. 22. (H), 12.06
Pont úgy egyikben sem fog működni. MySQL és PostgreSQL is megköveteli, hogy az al-lekérdezéseknek legyen aliasa.

Ami az al-lekérdezés order by-ját illeti, tök fölösleges, mert MySQL és PostgreSQL is külső group by hatására átrendezi az adatokat a feldolgozás során.

(Az on feltétel körüli kerek zárójelek szerintem csak az olvashatóságot rontják.)
7

Pont úgy egyikben sem fog

bb0072 · 2011. Aug. 22. (H), 12.14
Pont úgy egyikben sem fog működni. MySQL és PostgreSQL is megköveteli, hogy az al-lekérdezéseknek legyen aliasa.


Ebben lehet, hogy igazad van, nem néztem utána, de ez csak kis módosítás.

Ami az al-lekérdezés order by-ját illeti, tök fölösleges, mert MySQL és PostgreSQL is külső group by hatására átrendezi az adatokat a feldolgozás során.


Nem fölösleges. A külső group valóban átrendezi az adatokat, de hogy jó legyen az eredmény, a belső querybe kell az order. MySQL-nél legalábbis az történik ilyenkor, hogy mivel van group, de nincs aggregátum, a sorok közül a group by-nak megfelelő, fizikailag első találat (sor) kerül az eredménybe. Ez a fizikailag első találat pedig a belső order by miatt a legutóbb felvitt érték lesz az adott termosztáthoz. Mondom, postgre-ben nem tudom ez így van-e.
9

Utánanéztem, igazad van. Kell

bb0072 · 2011. Aug. 22. (H), 12.20
Utánanéztem, igazad van. Kell az alias :
  1.    
  2. SELECT therm_id, therm_name, temp_current    
  3.     FROM (    
  4.           SELECT therm.therm_id, therm_name, temp_current    
  5.           FROM thermostat therm    
  6.               LEFT JOIN temperature temp ON (therm.therm_id = temp.therm_id)    
  7.           ORDER BY date DESC    
  8.          ) AS tmp_view  
  9.     GROUP BY therm_id   
13

Ah, szóval arra pályáztál.

kuka · 2011. Aug. 22. (H), 12.41
Ah, szóval arra pályáztál. Most már értem, úgy tényleg nem fölösleges. PostgreSQLt illetően
ERROR: Attribute tmp_view.therm_name must be GROUPed or used in an aggregate function
Én ehhez vagyok szokva, ezért nem ugrott be a trükköd lényege.
14

Igen, én is úgy vettem észre,

bb0072 · 2011. Aug. 22. (H), 13.00
Igen, én is úgy vettem észre, hogy a postgre szigorúbb a group by tekintetében. Ami nem aggregátum, azt mind fel kell sorolni a group by részben. Így pedig a megoldásom valóban nem fog működni postgre-ben. Marad a ronda, egymásba egyázott subquery-k tömkelege, vagy a termosztátonkénti lekérdezés.
15

Ami nem aggregátum, azt mind

kuka · 2011. Aug. 22. (H), 13.22
Ami nem aggregátum, azt mind fel kell sorolni a group by részben.
Vagy úgy, vagy nem kell őket felsorolni, azaz group by helyett distinct ont használunk:
  1. SELECT    DISTINCT  
  2.        ON (therm_id)  
  3.           therm_id, therm_name, temp_current      
  4. FROM      (      
  5.           SELECT    therm.therm_id, therm_name, temp_current      
  6.           FROM      thermostat therm  
  7.           LEFT JOIN temperature temp  
  8.                  ON therm.therm_id = temp.therm_id  
  9.           ORDER BY  date  
  10.                DESC      
  11.           ) AS tmp_view    
Elméletileg működik, de csak régi teszt adatokkal próbáltam.
16

Ezt érdemes lenne kipróbálni!

bb0072 · 2011. Aug. 22. (H), 13.45
Ezt érdemes lenne kipróbálni! Érdekel, hogy működik-e.
18

Megnéztem, jól működik,

shark300 · 2011. Aug. 22. (H), 15.43
Köszönöm válaszod!
Megnéztem, jól működik, azonban az "mindent-joinolok-mindennel" miatt 43 mp a futási ideje lokális gépen, szerveren pedig a jóval több adat miatt 2 perc után állítottam le.
20

Még azt próbáld meg, hogy a

bb0072 · 2011. Aug. 22. (H), 16.00
Még azt próbáld meg, hogy a belső selectet egy view táblaként definiálod, majd abból kérdezel le. Meg ne felejtsd el a megfelelő indexeket a on-ban, a where-ben és az order by-ban lévő mezőkre. Ha még így is használhatatlanul lassú lesz, akkor elmegyek Tibetbe szerzetesnek. ;))
27

30 mp és 45 mp. Ne menj el

shark300 · 2011. Aug. 23. (K), 10.52
30 mp és 45 mp. Ne menj el ilyesmi miatt, nagyon sok az adat, egy picit hiányos adatstruktúrával.
8

(Az on feltétel körüli kerek

bb0072 · 2011. Aug. 22. (H), 12.16
(Az on feltétel körüli kerek zárójelek szerintem csak az olvashatóságot rontják.)


Kivéve akkor, ha több feltétel is van az on-ban
10

Próbáld ezt!

gabesz666 · 2011. Aug. 22. (H), 12.31
Ha nem lesz törlés a temperature táblából, akkor a következő megoldás működhet:
  1. SELECT thermostat.*, temperature.temp_current FROM thermostat LEFT JOIN temperature ON (thermostat.therm_id = temperature.therm_id AND temperature.temp_id = MAX(temperature.temp_id));  
11

Szerintem ez nem lesz jó. A

bb0072 · 2011. Aug. 22. (H), 12.36
Szerintem ez nem lesz jó. A MAX(temperature.temp_id) az egész temperature tábla legfrissebb rekordjának id-je lesz, ez egyetlen termosztátot fog listázni, amelyik a legutoljára küldött adatokat a db-be. (Azt az egyet viszont helyes temp_current értékkel fogja.)
12

Pontosítok

gabesz666 · 2011. Aug. 22. (H), 12.39
Nem teszteltem, szar is lett :) A helyes megoldás teszt után:
  1. SELECT thermostat . * , temperature.temp_current  
  2. FROM thermostat  
  3. LEFT JOIN temperature ON ( thermostat.therm_id = temperature.therm_id  
  4. AND temperature.temp_id = (   
  5. SELECT MAX( temp_id )   
  6. FROM temperature  
  7. WHERE therm_id = thermostat.therm_id ) )  
17

Köszönöm válaszod! 14 mp

shark300 · 2011. Aug. 22. (H), 15.42
Köszönöm válaszod!
14 mp lokális gépen, 36 mp szerveren, LIMIT 50-nel a WHERE feltételben 25 mp. 22 millió rekord van a temperature táblában, ezzel kéne valami csinálni.
19

22 millió rekord van a

bb0072 · 2011. Aug. 22. (H), 15.55
22 millió rekord van a temperature táblában, ezzel kéne valami csinálni


Pl. archiválni az 1 napnál régebbieket?
21

Sajnos máshol van rá

shark300 · 2011. Aug. 22. (H), 16.12
Sajnos máshol van a régi adatokra is szükség... Már több helyre ki lett helyezve a kód, nem lehet a táblákon változtatni. De próbálok definiálni egy view-t.
23

1000bocs, ha a szokásos

H.Z. v2 · 2011. Aug. 22. (H), 16.44
1000bocs, ha a szokásos figyelmetlenségem, de index van legalább a where-ben szereplő mezőkre? Ha van, explain plan (pgsql-nek is van ilyen?) szerint használja őket?

Asszem, Oracle forrásból származó tipp: particionált index? Létezik ilyen postgresql-ben?

(remélem, most nem írok nagy marhaságot... :-) )
24

Legutolsó id

gabesz666 · 2011. Aug. 22. (H), 23.55
Érdemes volna akkor a termosztátokhoz tartozó legutolsó temp_id-ket tárolni egy külön táblában. Ez lényegesen lecsökkentené a subquery idejét!
26

Még konzultálok az többi

shark300 · 2011. Aug. 23. (K), 10.50
Még konzultálok az többi fejlesztővel, de szerintem ez lesz. Köszönöm!
25

Mindenhol index, és nézet

shark300 · 2011. Aug. 23. (K), 10.49
Mindenhol index, és nézet tábla:
  1. CREATE OR REPLACE VIEW "last_temp" AS   
  2.  SELECT max(temp_id) AS max  
  3.    FROM temperature  
  4.   GROUP BY therm.id;  
Így ezt az temperature-rel inner és a thermostattal left outer joinolva lokális gépen 5 mp, szerveren 7 mp.
Ez már elég elfogadható.