Portál AbcLinuxu, 22. července 2025 09:12


Dotaz: Spotřeba vody za období ze stavu vodoměru

7.10.2014 01:00 pedro
Spotřeba vody za období ze stavu vodoměru
Přečteno: 1455×
Odpovědět | Admin
Zdravím,

asi nejsem dost zkušený, problém vypadá triviálně, ale lámu si hlavu s elegantním řešením.

Mějme tabulku datum date,stav integer. Například:
1.3.2014 1000
1.6.2014 1500
1.9.2014 2100
což je datum a stav vodoměru v daný den. Chci z toho dostat toto:
1.3.2014-1.6.2014 500
1.6.2014-1.9.2014 600
tedy kolik se spotřebovalo vody vždy mezi jednotlivými zápisy. Prosím o radu na elegantní řešení v PostgreSQL.

Díky.

Řešení dotazu:


Nástroje: Začni sledovat (1) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

Tarmaq avatar 7.10.2014 09:17 Tarmaq | skóre: 39
Rozbalit Rozbalit vše Re: Spotřeba vody za období ze stavu vodoměru
Odpovědět | | Sbalit | Link | Blokovat | Admin
SELECT s1.datum AS od, s2.datum AS do, s2.stav - s1.stav AS rozdil
FROM spotreba_vody s1
CROSS JOIN spotreba_vody s2
WHERE s1.datum < s2.datum
Na PostgreSQL netestovano, ale melo by to fungovat. Ma to jednu odlisnost, vraci to i rozdil mezi 1.3. a 1.9.
Don't panic!
Tarmaq avatar 7.10.2014 09:52 Tarmaq | skóre: 39
Rozbalit Rozbalit vše Re: Spotřeba vody za období ze stavu vodoměru
SELECT x.od, x.do, s2.stav - s1.stav AS rozdil
FROM
(
  SELECT 
    x1.datum AS od
  , (SELECT MIN(x2.datum) FROM spotreba_vody x2 WHERE x2.datum > x1.datum) AS do
  FROM spotreba_vody x1
) x
JOIN spotreba_vody s1 ON s1.datum = x.od
JOIN spotreba_vody s2 ON s2.datum = x.do
Tohle vrati jen ty dva zaznamy, ale opet nevim, jestli funguje i na postgresu..
Don't panic!
7.10.2014 09:36 Tomáš
Rozbalit Rozbalit vše Re: Spotřeba vody za období ze stavu vodoměru
Odpovědět | | Sbalit | Link | Blokovat | Admin

Máte dvě možnosti. První méně efektivní se self joinem a druhý lepší s window funkcemi.

  1. select 
      A.dt
      ,min(B.dt)
      ,min(B.val order by B.dt)-A.val 
    from T as A 
    join T as B on A.dt<B.dt 
    group by A.*
    
  2. select 
      A.dt
      ,max(A.dt) over( order by A.dt rows between current row and 1 following)
      ,max(A.val) over( order by A.dt rows between current row and 1 following)-A.val
    from A
    

Psáno bez jakékoliv kontroly, takže tam budou asi nějaké chybky. Ale jako nápověda je to dostatečné. BTW: Co když není datum unikátní?

rADOn avatar 7.10.2014 13:45 rADOn | skóre: 44 | blog: bloK | Praha
Rozbalit Rozbalit vše Re: Spotřeba vody za období ze stavu vodoměru
Ta druha varianta se mi libi… umi neco takovyho mysql?
"2^24 comments ought to be enough for anyone" -- CmdrTaco
7.10.2014 14:11 Tomáš
Rozbalit Rozbalit vše Re: Spotřeba vody za období ze stavu vodoměru
Pokud vím, tak ne. Musel by jste si pomoci cursorem.
7.10.2014 16:01 pedro
Rozbalit Rozbalit vše Re: Spotřeba vody za období ze stavu vodoměru
Z hlavy (skoro) perfektní, jen na konci zbude řádek, kde je stejné počáteční i koncové datum a nulová spotřeba. Výsledný select tedy vypadá takto:
select * from
(
select
  voda.datum as zacatek
  ,max(voda.datum) over( order by voda.datum rows between current row and 1 following) as konec
  ,max(voda.stav) over( order by voda.datum rows between current row and 1 following)-voda.stav as spotreba
from myschema.voda
) foo
where zacatek != konec;
Nejedinečné datum s různými stavy vodoměru je blbost, tak přidán constraint (ve skutečnosti je to timestamp, ne datum).

K dokonalosti ještě chybí ošetřit přetočení či výměnu vodoměru, ale to teď řešit nebudu.
Řešení 1× (Tarmaq)
okbob avatar 7.10.2014 11:46 okbob | skóre: 30 | blog: systemakuv_blog | Benešov
Rozbalit Rozbalit vše Re: Spotřeba vody za období ze stavu vodoměru
Odpovědět | | Sbalit | Link | Blokovat | Admin
Co např.:
postgres=> select * 
              from (select mereno, hodnota - lag(hodnota) over (order by mereno) as spotreba 
                       from odecet order by 1) s 
             where spotreba is not null;
   mereno   | spotreba 
------------+----------
 2014-01-06 |      500
 2014-01-09 |      600
(2 rows)
Kartézákům se pokud možno vyhýbejte - pro větší data to může být docela pomalé, a navíc zápis s window funckcemi je výrazně čitelnější.
7.10.2014 15:37 pedro
Rozbalit Rozbalit vše Re: Spotřeba vody za období ze stavu vodoměru
Odpovědět | | Sbalit | Link | Blokovat | Admin
Moc všem děkuji. Ano, šlo mi hlavně o window funkce, které jsem pro sebe objevil teprve včera ;).

Kartézákům jsem se chtěl vyhnout, ačkoli v mém případě by to asi nevadilo, protože se jedná skutečně o vodoměr v bytovém domě a asi ho nebudu odečítat častěji než 1x týdně, takže i za léta řádově stovky řádků.

Tak teď ještě ty window funkce pochopit a naučit se je.

S vodou není legrace, jeden protékající záchod v domě dokáže udělat na faktuře za vodu opravdu pořádný vítr.

Založit nové vláknoNahoru

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.