Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Ostatnie zdarzenie dla określonego warunku
scanner
post 20.12.2004, 13:48:21
Post #1





Grupa: Zarząd
Postów: 3 503
Pomógł: 28
Dołączył: 17.10.2002
Skąd: Wrocław




Mam dwie tabele stworzone według zapytań jak niżej.
W "events" zapisuję pewne zdarzenia powtarzalne w czasie wykonywane przez osoby z tabelki "persons". Każde zdarzenie ma jak widać dwa stany. Moje pytanie jest nastepujące:

Jak wydostać sName wszystkich osób, których ostatnim wykonanym zdarzeniem jest 'In'?

Próbowąłem pokombinowąć trochę, ale jedyne co mi wysżło to:
  1. SELECT persons.sCode, persons.sName, events.iTimestamp
  2. FROM events LEFT JOIN persons ON events.sCode = persons.sCode
  3. WHERE sAction = 'In'
  4. GROUP BY events.sCode
  5. ORDER BY events.iTimestamp DESC

  1. -- Wersja serwera: 4.0.22
  2. -- Wersja php: 5.0.2
  3.  
  4. CREATE TABLE `events` (
  5. `iID` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  6. `sCode` varchar(12) NOT NULL DEFAULT '0',
  7. `iTimestamp` int(11) NOT NULL DEFAULT '0',
  8. `sAction` SET('In','Out') DEFAULT NULL,
  9. PRIMARY KEY (`iID`)
  10. ) TYPE=MyISAM;
  11.  
  12. CREATE TABLE `persons` (
  13. `iID` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  14. `sCode` varchar(12) NOT NULL DEFAULT '0',
  15. `sName` varchar(255) NOT NULL DEFAULT '',
  16. `iBirthdate` int(11) NOT NULL DEFAULT '0',
  17. `sAppointmentCode` varchar(12) NOT NULL DEFAULT '0',
  18. `sAppointmentName` varchar(255) NOT NULL DEFAULT '',
  19. `sPhoto` longblob NOT NULL,
  20. PRIMARY KEY (`iID`)
  21. ) TYPE=MyISAM;


--------------------
scanner.info
Warto pamiętać: KISS, DRY
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi (1 - 8)
Ar2r
post 20.12.2004, 15:49:01
Post #2





Grupa: Zarejestrowani
Postów: 140
Pomógł: 16
Dołączył: 12.06.2002
Skąd: Kielce

Ostrzeżenie: (0%)
-----


Ciężko wywnioskować z tego opisu czy mogą istnieć dwa zdarzenia tego samego typu w takich samych stanach wykonywane przez tego samego użytkownika. Jeżeli nie to zapytanie jest ok.
Go to the top of the page
+Quote Post
scanner
post 20.12.2004, 16:45:40
Post #3





Grupa: Zarząd
Postów: 3 503
Pomógł: 28
Dołączył: 17.10.2002
Skąd: Wrocław




Jako "zdarzenia" przyjmijmy wchodzenie / wychodzenie pracownika z firmy.

"events" w tym przypadku to kolejne przejścia przez drzwi. "In" / "Out" - pracownik po roku przejdzie przez drzwi tysiące razy - ja muszę z tych tabelek wyciągnąć tych, którzy weszli ale JESZCZE nie wyszli.


--------------------
scanner.info
Warto pamiętać: KISS, DRY
Go to the top of the page
+Quote Post
popbart
post 20.12.2004, 17:28:34
Post #4





Grupa: Zarejestrowani
Postów: 255
Pomógł: 0
Dołączył: 22.04.2004
Skąd: Żoliborz

Ostrzeżenie: (0%)
-----


1.jeżeli jeden persons może mieć wiele events to dlaczego nie ma poł±czenia relacyjnego(w tabeli events pole id_persont(int)) tylko przez pola varchar?
2.jak z takiego varchar wyciagn±c max() (ostatnie zdarzenie)?

jeżeli przyjmiemy że przerobisz tabele i bedziesz miał mysql'a >4.1.x to:

  1. SELECT persons.iID, persons.sName, events.iTimestamp
  2. FROM persons LEFT JOIN events ON persons.iID = events.iID_persons
  3. WHERE evets.iID IN(SELECT max(iID) FROM events GROUP BY iID_persons) AND events.sAction = 'In'
  4. ORDER BY events.iTimestamp DESC


  1. persons.iID, persons.sName
  2. FROM persons LEFT JOIN events ON persons.iID = events.iID_persons
  3. WHERE events.iID_persons IS NULL


Ten post edytował popbart 20.12.2004, 17:38:22


--------------------
Visual Basic - kto by pomyślał :)
Go to the top of the page
+Quote Post
Ar2r
post 20.12.2004, 17:34:17
Post #5





Grupa: Zarejestrowani
Postów: 140
Pomógł: 16
Dołączył: 12.06.2002
Skąd: Kielce

Ostrzeżenie: (0%)
-----


Rozważmy taki sposób:
Przy pewnym uproszczeniu, że pracownik nie wychodzi następnego dnia (czyli nie pracuje na 3 zmianę) można by porównywać znaczniki czasu zdarzeń IN / OUT w danym dniu. Czyli bierzemy MAX(iTimestamp) z IN i porównujemy z MAX(iTimestamp) z OUT dla danego użytkownika. Jeśli 1>2 to znaczy, że nie wyszedł.
Co o tym sądzisz?
Go to the top of the page
+Quote Post
scanner
post 20.12.2004, 20:35:27
Post #6





Grupa: Zarząd
Postów: 3 503
Pomógł: 28
Dołączył: 17.10.2002
Skąd: Wrocław




Może coś prościej...

Jak wyciągnąć ostatnią sAction dla każdego zapisanego sCode ?

Kurde.. pomroczość jasna u mnie nie ustepuje...


--------------------
scanner.info
Warto pamiętać: KISS, DRY
Go to the top of the page
+Quote Post
DeyV
post 20.12.2004, 22:49:41
Post #7





Grupa: Zarząd
Postów: 2 277
Pomógł: 6
Dołączył: 27.12.2002
Skąd: Wołów/Wrocław




To nie pomroczność, tylko zadanie bardzo trudne do zrealizaowania bez podzapytań.

http://dev.mysql.com/doc/mysql/en/example-...-group-row.html


--------------------
"Niezależnie od tego, jakie masz osiągnięcia, ktoś Ci pomaga..."
Go to the top of the page
+Quote Post
scanner
post 20.12.2004, 22:50:38
Post #8





Grupa: Zarząd
Postów: 3 503
Pomógł: 28
Dołączył: 17.10.2002
Skąd: Wrocław




Koniec końców pomogłem sobie takim kodem:
  1. <?php
  2. $sSQLQuery =  &#092;"SELECT persons.sCode, persons.sName, events.iTimestamp, events.sAction FROM
     
  3. vents LEFT JOIN persons ON events.sCode = persons.sCode ORDER BY events.iTimesta
  4. p DESC\";
  5.  
  6. $list = array();
  7. $Persons = array();
  8.  
  9. $PersonsList = $db->get_results( $sSQLQuery );
  10. if( $PersonsList )
  11. {
  12. foreach ( $PersonsList as $key=>$so)
  13. {
  14.  if (!in_array($so->sCode, $list))
  15.  {
  16.  $list[] = $so->sCode;
  17.  $Persons[$key] = $so;
  18.  }
  19.  if( $so->sAction == 'Out' )
  20.  {
  21.  unset( $Persons[$key] );
  22.  }
  23. }
  24. }
  25. ?>
Jakby kto pytał, to $db to obiekt klasy ezSQL - klasy której uzywam jako DAO


--------------------
scanner.info
Warto pamiętać: KISS, DRY
Go to the top of the page
+Quote Post
DeyV
post 21.12.2004, 01:00:48
Post #9





Grupa: Zarząd
Postów: 2 277
Pomógł: 6
Dołączył: 27.12.2002
Skąd: Wołów/Wrocław




A ja mimo wszystko byłem przekonany, że można to zrobić przy pomocy MySQL 4.0

  1. SELECT
  2. events.sCode ,
  3. events.sAction ,
  4. events.iTimestamp,
  5. persons .iId,
  6. persons .sName
  7. FROM events INNER JOIN persons ON ( events.sCode = persons.sCode )
  8. INNER JOIN events events2 ON ( events.sCode = events2.sCode AND events.sAction = 'In' )
  9. GROUP BY events.iID
  10. HAVING events .iTimestamp = MAX( events2 .iTimestamp )
  11. ORDER BY events.iTimestamp DESC

I wydaje mi się, że są to dokładnie oczekiwane wyniki, czyli lista wszystkich osób które teraz są In, i nie zdążyły jeszcze wyjść.

ps. Ale, scanner, podobierałeś nazwy kolumn i tabel. Mój phpMyAdmin ledwie sobie z nimi radził, a już np. ustawiene sortowania w tabeli events, przy pomocy kliknięcia w nazwę kolumny, praktycznie graniczyło z cudem.


--- edited ----

Co ciekawe jest jeszce prostsze rozwiązanie. Dla czytelności - nie dołączam tabeli persons
  1. SELECT
  2. events.sCode ,
  3. events.sAction ,
  4. events.iTimestamp
  5. FROM events LEFT JOIN events AS events2 ON (events.sCode = events2.sCode AND events.iId < events2.iId )
  6. WHERE events2.iId IS NULL AND events.sAction = 'In'

gdzie warunek events.iId < events2.iId może być zastąpiony przez events.iTimestamp < events2.iTimestamp, jeśli może się zdarzyć sytuacja, że kolejność id nie informuje nas wcale o kolejności zdażeń (bo np. wiersz był edytowany i została mu nadana nowa wartość i data, a id pozostało to samo).


--- edited 2 ---
zabawa mi się spodobała. I dzięki temu wiem, że można jeszcze inaczej (ciekawe, czy optymalniej...) winksmiley.jpg
  1. SELECT sCode,
  2. SUBSTRING( MAX( CONCAT( iTimestamp, LPAD(sAction,3,'0') ) ), 16 ) AS action,
  3. SUBSTRING( MAX( CONCAT( iTimestamp, LPAD(sAction,3,'0') ) ), 1,14 ) AS czas FROM events GROUP BY sCode
  4. HAVING action = 'In'

pojawia się tu wartość 14 i 16 ponieważ zmieniłem sobie typ kolumny na timestamp 14. Ty musiałbyś dostosować tą wartość do długości swojego zapisu daty.,


--------------------
"Niezależnie od tego, jakie masz osiągnięcia, ktoś Ci pomaga..."
Go to the top of the page
+Quote Post

Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 22.06.2025 - 06:46