Gathering of Tweakers

Quicksearch
Graag wil ik uit een tabel met gesprekken, weten hoeveel gesprekken er maximaal gelijktijdig zijn gevoerd.

De tabel met gesprekken heeft de volgende indeling:

- id (INT)
- anummer (INT)
- bnummer (INT)
- van (DATETIME)
- tot (DATETIME)

Ik hoop dat dit met een enkele of een paar query's mogelijk is.

Heeft iemand een idee hoe ik dit kan inrichten?

Het alternatief is per seconde kijken of een gesprek wordt gevoerd (totaal 84.400 per dag met een cronjob)

Ik gebruik PHP 5.2.5 en MySQL 5, alvast bedankt voor jullie medewerking!
 

Acties: [view][quote]


Door: RobIII Moderator PRG/SEA/WEB
Papa van LucaIII \o/

Wat heeft dit met SEA te maken?
Waar hoort mijn topic?
SEA >> PRG

En verder: wat heb je zelf al geprobeerd?

We all get along with some glue and duct tape here and there - but when the sh*t hits the fan, don’t blame the duct tape.

Trotse papa van Luca! | Pick My Icon!

Heb je al bedacht hoe je dat met de hand op zou moeten lossen? Dat idee heb ik namelijk niet, en als de een query moet bedenken zonder dat je dat al weet dan loop je idd vast :).

Overigens denk ik niet dat het met een query te doen is. Je hebt op z'n minst een stored procedure nodig als je het in de db zelf al op wilt lossen.

Call me cocky, but if there`s an alien out there I can`t kill I haven`t met him and killed him yet.
[Tomb Raider: Underworld] - [My javascript wolfenstein project]

Het maximum aantal gesprekken kan alleen bereikt worden op de begintijd van een gesprek.
Gelijktijdige gesprekken van dit gesprek hebben deze begintijd tussen hun begintijd en eindtijd in zitten.
Een bijzonder geval hierbij is het piekgesprek zelf, dus de telling moet altijd eentje minder zijn.

Op een morgen stond hij op met het ochtendgloren, trad de zon tegemoet en sprak haar aldus toe:
'Gij groot gesternte! Wat zou uw geluk waard zijn, wanneer ge niet hen hadt, die gij verlicht!'

mmh beetje vaag topic. Je kan toch gewoon een select uitvoeren, waarbij je dan alle records selecteert waarbij de eindtijd nog leeg is? Ik neem aan dat die leeg is als het gesprek nog bezig is. Hoe je dit verder uitvoert, met cronjob of niet, is afhankelijk van je wensen natuurlijk.

edit:
oeps, ik had de vraag niet helemaal door.

Noork wijzigde dit bericht 13-05-2008 12:59 (9%)

 
quote:
justmental schreef op dinsdag 13 mei 2008 @ 12:55:
Het maximum aantal gesprekken kan alleen bereikt worden op de begintijd van een gesprek.
Nou ja eigenlijk tussen de begintijd van een gesprek en de eindtijd van het eerstvolgende eindigende gesprek, maar als je de standaard haakjes-tellen-methode aanhoudt dan bereik je dat maximum idd bij de start van een gesprek (je zou ook andersom kunnen tellen namelijk ;)).

Call me cocky, but if there`s an alien out there I can`t kill I haven`t met him and killed him yet.
[Tomb Raider: Underworld] - [My javascript wolfenstein project]

Alleen in SQL lijkt me erg lastig. Efficientst zou waarschijnlijk zijn om een array te bouwen van 1440 of 86400 regels (elke minuut of seconde van een dag en een teller), dan eenmalig alle records van een dag te selecteren en per record in de array aan te geven in welke periodes het gesprek bezig was. Vervolgens orden je de array op aantal en daar heb je je maximum. Iets dergelijks kan je misschien met een tijdelijke tabel en een subselect ook doen, maar als je dan niet indexeert op tijd wordt het vast niet heel snel aangezien je veel meer queries moet doen.
 

Acties: [view][quote]


Door: RobIII Moderator PRG/SEA/WEB
Papa van LucaIII \o/

quote:
dajappie schreef op dinsdag 13 mei 2008 @ 13:20:
Vervolgens orden je de array op aantal en daar heb je je maximum.
Waarom nog ordenen? Je kunt tijdens het vullen toch al prima de max bijhouden? En desnoods race je 1 keer door je array om de max te vinden; nog altijd sneller dan een sort ;)

We all get along with some glue and duct tape here and there - but when the sh*t hits the fan, don’t blame the duct tape.

Trotse papa van Luca! | Pick My Icon!

Bedankt voor de snelle reacties. Het probleem wat ik had was het grote aantal query's wat nodig was (script reageerde veel te langzaam). Ik zal het nu proberen om de manier zoals dajappie die omschreef. Een array maken met php en dan alle records ophalen en de (seconden)array vullen.
 
quote:
dajappie schreef op dinsdag 13 mei 2008 @ 13:20:
Alleen in SQL lijkt me erg lastig. Efficientst zou waarschijnlijk zijn om een array te bouwen van 1440 of 86400 regels (elke minuut of seconde van een dag en een teller)
En dan zit je dus per seconde of per minuut te werken, wat niet per se hoeft te kloppen. Het handigst is waar ik al naar hintte: zet de tabel om in events - een begin-event en een eind-event. Gooi alle events op een hoop en sorteer die op tijd. Loop er dan in volgorde overheen, waarbij je een tellertje bijhoudt die bij 0 begint en +1 doet bij een nieuw gesprek en -1 bij een eindigend gesprek. Hou verder nog de maximale waarde bij.

Als je over alle gegevens bent gelopen is je maximale waarde het maximum aantal gesprekken op een bepaald moment.

Call me cocky, but if there`s an alien out there I can`t kill I haven`t met him and killed him yet.
[Tomb Raider: Underworld] - [My javascript wolfenstein project]

Andere manier dan achteraf opzoeken is misschien in je applicatie bijhouden hoeveel actieve gesprekken er zijn (kwestie van +1 bij start en -1 bij einde gesprek). Hierbij kun je ook even kijken of het huidige aantal hoger is dan het maximum van die dag (of andere eenheid) en zo ja dat maximum vervangen.

Zo zou je uiteindelijk een tabel overhouden met per eenheid (uur, dag, wat je wilt) het maximum aantal gesprekken tegelijk. Zo kun je ook zonder hele zware bewerkingen achteraf hier statistieken aan verbinden over langere tijd.

Edit: lees nu .oisyns reactie pas :+ Zegt ongeveer hetzelfde, maar dan alsnog achteraf. Keuze is aan TS natuurlijk. Ik geef zelf vaak voorkeur aan eenvoudige gegevens continu bijhouden ipv zware bewerkingen achteraf.

Bosmonster wijzigde dit bericht 13-05-2008 14:22 (17%)


KLIK HIER!!! >>> Mooie foto's van mijn vriendinnetje! <<< KLIK HIER!!!

quote:
.oisyn schreef op dinsdag 13 mei 2008 @ 13:53:
[...]

En dan zit je dus per seconde of per minuut te werken, wat niet per se hoeft te kloppen. Het handigst is waar ik al naar hintte: zet de tabel om in events - een begin-event en een eind-event. Gooi alle events op een hoop en sorteer die op tijd. Loop er dan in volgorde overheen, waarbij je een tellertje bijhoudt die bij 0 begint en +1 doet bij een nieuw gesprek en -1 bij een eindigend gesprek. Hou verder nog de maximale waarde bij.

Als je over alle gegevens bent gelopen is je maximale waarde het maximum aantal gesprekken op een bepaald moment.
What he says :)

Iets andere smaak daarvan is een tellertje bijhouden voor ieder tegengekomen tijdstip van het aantal gesprekken dat ooit gestart is en ooit ge-eindigd is.
Iets SQL-esquer?! Allemaal wel makkelijk in extra tabellen te updaten.
Mag je alsnog wel maximaliseren over het verschil, sorteren e.d..
 
quote:
pkuppens schreef op dinsdag 13 mei 2008 @ 14:32:
What he says :)

Iets andere smaak daarvan is een tellertje bijhouden voor ieder tegengekomen tijdstip van het aantal gesprekken dat ooit gestart is en ooit ge-eindigd is.
Da's idd ook wel een goede. Die data is met een simpele query wel te krijgen. Ook updates zijn goed te doen - een insert betekent een extra startcount voor alle rijen met een starttijd groter dan de starttijd van de nieuwe entry en een extra eindcount voor alle rijen met een eindtijd groter dan de eindtijd van de nieuwe entry. Bij deletes een vergelijkbare update (aftrekken ipv optellen). Sterker nog, je hebt niet eens aparte counters nodig - je kunt ook gewoon direct het verschil in de kolom opslaan. En dan moet je dus ophogen/verlagen bij alle gesprekken die begonnen zijn tussen starttijd en eindtijd bij resp. een insert en een delete.

Call me cocky, but if there`s an alien out there I can`t kill I haven`t met him and killed him yet.
[Tomb Raider: Underworld] - [My javascript wolfenstein project]

quote:
robigoal schreef op dinsdag 13 mei 2008 @ 13:41:
Bedankt voor de snelle reacties. Het probleem wat ik had was het grote aantal query's wat nodig was (script reageerde veel te langzaam). Ik zal het nu proberen om de manier zoals dajappie die omschreef. Een array maken met php en dan alle records ophalen en de (seconden)array vullen.
Begin alsjeblieft niet met dat idee. Je hele bouwwerk valt om zodra er een keer iemand besluit om 23:59 voor 2 minuten te gaan bellen.
Of iemand vindt ineens de microsecondes ook belangrijk.
 

Acties: [view][quote]


Door: dusty Global Moderator
Er ontbreekt nogal wat aan je vraag wat je wilt, op een bepaalde dag, bepaald uur, bepaald gesprekID...

Dus hier een pseudo query uit de losse pols (zonder te testen) op bepaald gesprek om te kijken hoeveel gesprekken aan de gang was bij het gesprekid 48747.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
select
  a.id,
  a.van,
  a.tot,
  count(b.id) as TotalConcurrentCalls
from
  calllog a
  left join calllog b on (
    ( a.van between b.van and b.tot )
    or
    ( a.tot between b.van and b.tot )
    or
    ( b.van between a.van and a.tot )
    or
    ( b.tot between a.van and a.tot )
  )
where
  a.id=48747
group by
  a.id,
  a.van,
  a.tot
order by
  count(b.id)
limit 0,1

Curlio.com Music News For You!
Y! Celebrate Life!

Dat was de vraag niet. De vraag was wat het maximaal aantal gesprekken tegelijk was. Als gesprek A start, en daarop volgen B, C en D allemaal na elkaar, en dan einigt A weer, dan tel jij er 4, maar het maximum was maar 2. Bovendien kan het ook korter dan die 4 betweens, namelijk: b.van < a.tot AND a.van < b.tot ;)

Call me cocky, but if there`s an alien out there I can`t kill I haven`t met him and killed him yet.
[Tomb Raider: Underworld] - [My javascript wolfenstein project]


Acties: [view][quote]


Door: dusty Global Moderator
Zodra hij de query gaat aanpassen aan wat hij exact wilt ( calls/sec ) zal hij toch "between" gaan gebruiken. :P

Curlio.com Music News For You!
Y! Celebrate Life!

quote:
dusty schreef op dinsdag 13 mei 2008 @ 16:10:
Zodra hij de query gaat aanpassen aan wat hij exact wilt ( calls/sec )
Grappig dat jij weet wat hij exact wilt terwijl hij toch echt iets anders zegt in z'n topic :+. En ik zei niet dat de between in z'n algemeenheid overbodig was, ik zei dat dat wat jij deed korter opgeschreven kon worden.

Wat in z'n algemeenheid dus wel zo is is dat als je twee ranges op overlap wilt testen, dat een (range1.min <= range2.max && range2.min <= range1.max) volstaat, en je dus niet hoeft te testen of elk van de 4 punten in de andere range voorkomt. Vergelijkbaar (en wellicht wat intuitiever) is de test om te kijken of ze juist niet overlappen: range1.min > range2.max || range2.min > range1.max. Immers, als het minimum van de ene range na het maximum van de andere komt kan er nooit een overlap zijn, en vice versa.

.oisyn wijzigde dit bericht 13-05-2008 16:58 (41%)

Call me cocky, but if there`s an alien out there I can`t kill I haven`t met him and killed him yet.
[Tomb Raider: Underworld] - [My javascript wolfenstein project]

Jep, de overlappende periodes vraag komt zo'n beetje maandelijks terug, zie oa Voutloos in "[PHP/MySQL]Event selecteren binnen tijdg..." . :)

Talkin.nl daily photoblog
Day 940: Agricultural Machinery
Foto specs: Canon 300D, Tamron 17-50 f/2.8, 1/160s, f/6.3, ISO 100

M'n occlusion culling code staat ook vol met dat soort tests ;)

Call me cocky, but if there`s an alien out there I can`t kill I haven`t met him and killed him yet.
[Tomb Raider: Underworld] - [My javascript wolfenstein project]


Acties: [view][quote]


Door: ACM Devver / Serveradmin
quote:
dajappie schreef op dinsdag 13 mei 2008 @ 13:20:
Alleen in SQL lijkt me erg lastig.
Het is bijzonder lastig - zo niet onmogelijk - in SQL. Je moet namelijk conditioneel relaties gaan leggen tussen de records van een set waarbij de condities veranderen tijdens de constructie van de set en dat hoort helemaal niet in SQL.
quote:
Efficientst zou waarschijnlijk zijn om een array te bouwen van 1440 of 86400 regels (elke minuut of seconde van een dag en een teller), dan eenmalig alle records van een dag te selecteren en per record in de array aan te geven in welke periodes het gesprek bezig was. Vervolgens orden je de array op aantal en daar heb je je maximum. Iets dergelijks kan je misschien met een tijdelijke tabel en een subselect ook doen, maar als je dan niet indexeert op tijd wordt het vast niet heel snel aangezien je veel meer queries moet doen.
Zelfs als je wel indexeert op tijd is dat erg vervelend om te doen. Bij 10.000 records met willekeurige starttijden over de dag verdeed en willekeurige eindtijden daar maximaal een uur na, kostte het mijn postgresql installatie ruim andehalve minuut om te vinden welke van de 86400 seconden binnen de meeste gesprekken viel.

De procedure die .oisyn beschrijft is echter ook prima in een procedurele SQL-taal te implementeren (zoals plpgsql in PostgreSQL) en daarmee kostte het minder dan 90ms.

Je hoeft daar overigens niet per se losse events van je tabel van te maken, UNION ALL is natuurlijk een prima vriend op zo'n moment:
SQL:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
-- tabel met 10.000 willekeurige begintijden op vandaag
-- en eindtijd daar willekeurig binnen 3600 seconden na
CREATE TABLE dateranges AS
SELECT idstarttime,
  starttime + (INTERVAL '1 SECOND' * RANDOM() * 3600AS endtime
FROM
  (SELECT generate_series as id,
       CURRENT_DATE::TIMESTAMP + (INTERVAL '1 SECOND' * RANDOM() * 86400)
              AS starttime
    FROM generate_series(1,10000)) AS dateseries;

CREATE INDEX dateranges_start_end_idx ON dateranges (starttimeendtime);

-- Deze select duurt zo'n anderhalve minuut bij mij
SELECT timemomentcount(*) as cnt
FROM
  (SELECT CURRENT_DATE::timestamp
                     + (INTERVAL '1 SECOND' * generate_series)
                 as timemoment
     FROM generate_series(086399)) as t
JOIN dateranges d ON timemoment BETWEEN d.starttime AND d.endtime
GROUP BY timemoment
ORDER BY cnt DESC;
-- Time: 91044.799 ms

-- En deze procedure is zo klaar:
CREATE OR REPLACE FUNCTION count_max_usage () 
    RETURNS integer AS $$
DECLARE 
    counter INTEGER;
    maxcount INTEGER;
    temp RECORD;
BEGIN
    maxcount := 0;
    counter := 0;
    
    FOR temp IN 
        (SELECT 1 as incrstarttime as tm FROM dateranges
         UNION ALL
         SELECT -1 as increndtime as tm FROM daterangesORDER BY tm
    LOOP
        counter := counter + temp.incr;
        IF counter > maxcount THEN 
            maxcount := counter;
        END IF;
    END LOOP;
    
    RETURN maxcount;
END    
$$ LANGUAGE plpgsql;

SELECT count_max_usage();
-- Time: 89.051 ms

Ik weet niet hoe goed MySQL's functionele taal is in 5.1, maar die PostgreSQL-functie zou je op zich vrij eenvoudig moeten kunnen vertalen naar een functie in MySQL.

[13:34:02] <baa> maar fbsd schijnt nog steeds hopeloos schijnt

Ik had een tijdje terug ongeveer hetzelfde nodig, het maximale aantal events op dezelfde dag. Volgens mij moet dat prima toepasbaar zijn op jouw geval.

SQL:
1
2
3
4
5
6
7
8
9
10
11
12
SELECT
    COUNT(DISTINCT b.idAS nr_conversations
FROM
    call_log a
    INNER JOIN call_log b ON a.van BETWEEN b.van AND COALESCE(b.totNOW())
WHERE
    1
GROUP BY
    a.van
ORDER BY
    nr_conversations DESC
LIMIT 1

Mijn grootste probleem was dat je een soort dubbele group by nodig hebt. Eentje die een count doet van conversaties op dezelfde momenten, en eentje die het maximale nummer van die counts pakt. Dat heb ik opgelost door het maximale nummer te bepalen door een order by + limit 1.

Alleen gezien het aantal ervaren mensen dat hier aangeeft dat het zo goed als onmogelijk is dit met SQL te doen, twijfel ik wel. Iemand die kan bevestigen dat dit werkt?

OnTracK wijzigde dit bericht 13-05-2008 20:06 (5%)

Not everybody wins, and certainly not everybody wins all the time.
But once you get into your boat, push off and tie into your shoes.
Then you have indeed won far more than those who have never tried.


Acties: [view][quote]


Door: ACM Devver / Serveradmin
Als je het probleem omdraait - en dus netjes in Sets gaat denken - kan het wel in SQL.

Het moment met de meeste calls tegelijk, is per definitie als de meest recente call van die specifieke subset begonnen is, totdat de eerstvolgende call daarna eindigt. En dat laatste kan die laatst gestartte call zijn, maar ook een van de anderen waar ie na begon.

Oftewel, voor elke call kijk je binnen hoeveel andere calls zijn begintijd valt, telt er een bij op, sorteerd het omgekeerd en je weet het drukste moment.

Oftewel, in SQL:
SQL:
1
2
3
4
5
6
7
8
9
10
SELECT 
d.starttimed.endtime,
(SELECT COUNT(*) 
    FROM dateranges ds
    WHERE d.starttime
            BETWEEN ds.starttime AND ds.endtime AND ds.id <> d.id) + 1 as cnt
FROM dateranges d
GROUP BY d.idd.starttimed.endtime
ORDER BY cnt DESC
LIMIT 1

Duurt helaas nog 6 seconden bij mij, maar dat is al een stuk beter dan de 90 voor de eerste aanpak.
quote:
Afgezien van de (imho) overbodige DISTINCT en de WHERE-clause, doet die van jou inderdaad wat hier gevraagd wordt. Hij is semantisch min of meer hetzelfde als de mijne.
quote:
Mijn grootste probleem was dat je een soort dubbele group by nodig hebt. Eentje die een count doet van conversaties op dezelfde momenten, en eentje die het maximale nummer van die counts pakt. Dat heb ik opgelost door het maximale nummer te bepalen door een order by + limit 1.
Sja, je kan de boel ook in een nieuwe SELECT verpakken en er een MAX overheen halen... de order by + limit werkt ook prima in MySQL.
quote:
Alleen gezien het aantal ervaren mensen dat hier aangeeft dat het zo goed als onmogelijk is dit met SQL te doen, twijfel ik wel. Iemand die kan bevestigen dat dit werkt?
Het grootste manco dat ik aan de jouwe zie is dat het heel erg impliciet werkt als er maar 1 record is op een dag en dat je het record dat je aan het bekijken bent ook heel impliciet meetelt. Maar afgezien daarvan heb je voor zover ik kan zien inderdaad een oplossing voor het gestelde probleem gepost. Dat manco zou je nog op kunnen lossen door de INNER join naar een LEFT te veranderen, maar je kan het ook goed proberen te onthouden zodat je bij een wijziging van je ON-clause niet ineens een hele rustige dag (of een korter bereik) verpest ;)

ACM wijzigde dit bericht 13-05-2008 20:17 (45%)

[13:34:02] <baa> maar fbsd schijnt nog steeds hopeloos schijnt

quote:
[b][message=30062813,noline]

[...]

Afgezien van de (imho) overbodige DISTINCT en de WHERE-clause, doet die van jou inderdaad wat hier gevraagd wordt. Hij is semantisch min of meer hetzelfde als de mijne.
Komt omdat ik in mijn oorspronkelijke query wel wat meer join'de en selecteerde, ik had even geen zin om uit te pluizen wat er nou ook alweer precies nodig was. En of een WHERE in MySQL nou verplicht was...

Mijn oorspronkelijk query had natuurlijk een iets ander doel. Daarom was ik ook niet zeker of deze toepasbaar was.
quote:
[...]

Sja, je kan de boel ook in een nieuwe SELECT verpakken en er een MAX overheen halen... de order by + limit werkt ook prima in MySQL.
Dat werkt (voor zover ik weet) niet in MySQL (misschien alleen MySQL 4?)

OnTracK wijzigde dit bericht 13-05-2008 20:19 (8%)

Not everybody wins, and certainly not everybody wins all the time.
But once you get into your boat, push off and tie into your shoes.
Then you have indeed won far more than those who have never tried.


Acties: [view][quote]


Door: ACM Devver / Serveradmin
quote:
OnTracK schreef op dinsdag 13 mei 2008 @ 20:17:
Dat werkt (voor zover ik weet) niet in MySQL (misschien alleen MySQL 4?)
Subqueries werken vanaf 4.1, maar zelfs nu in 5.0 nog niet helemaal soepeltjes. Dus jouw variant is waarschijnlijk sneller in MySQL. Maar 'SELECT MAX(foo.cnt) FROM (SELECT count(b.id) as cnt FROM ...) as foo' zou wel al sinds 4.1.0 ofzo moeten werken.

Als je nu nog aan 3.x of 4.0 vast zou je bij je provider/sysadmin aan de bel moeten trekken. De performance van 4.1 en 5.0 zijn aardig beter en de veiligheid van die twee deprecated versies zal ook wel wat te wensen overlaten.

En ik heb nog nooit gehoord van een verplichte WHERE in MySQL. Zelfs de FROM is dat niet.

ACM wijzigde dit bericht 13-05-2008 20:29 (6%)

[13:34:02] <baa> maar fbsd schijnt nog steeds hopeloos schijnt



© 1998-2008 Tweakers.net BV - Based on React - Hosted by True - Served by Alectrona

© 1998-2008 Tweakers.net BV - Based on React - Hosted by True - Served by Alectrona

[RSS][XML]

Update Tracker

Active Topics
Active Topics
Frontpage Nieuws
Frontpage Nieuws