Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: помогите с запросом в MySql  (Прочитано 8569 раз)
0 Пользователей и 1 Гость смотрят эту тему.
djan
Гость
« : 18-03-2009 13:36 » 

На MySql описана таблица, в которую заносятся вход/выход людей. Таблица примерно такого вида
CountHumanIdDateAction
Auto-incrementID человека, из другой таблицыКогда произошло событиеENUM('enter','exit')
Помогите составить запрос, который выводит всех пользоветелей, которые внутри, т.е. для которых последняя запись Action=enter
Записан
RuNTiME
Помогающий

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 18-03-2009 14:08 » 

Код:
SELECT Count, HumanId, Date FROM <имя таблицы> WHERE Action='enter';
Записан

Любимая игрушка - debugger ...
McZim
Модератор

ru
Offline Offline
Пол: Мужской
Я странный


WWW
« Ответ #2 : 18-03-2009 14:08 » 

Код:
SELECT Человек FROM таблица где человек WHERE IDЧеловека in (SELECT HumanId FROM Таблица где действие WHERE Action = 'enter'
Записан

The CBO without stats is like a morning without coffee. (c) T.Kyte.
Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #3 : 18-03-2009 14:47 » 

тут ключевое слово
которые внутри, т.е. для которых последняя запись Action=enter

а по приведенным запросом
все кто когда-либо входил
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
McZim
Модератор

ru
Offline Offline
Пол: Мужской
Я странный


WWW
« Ответ #4 : 18-03-2009 18:49 » 

угу тогда Date проверять на сегодняшнее число, то есть на число когда выполняется запрос.
Записан

The CBO without stats is like a morning without coffee. (c) T.Kyte.
Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #5 : 18-03-2009 20:26 » 

1. select humanid, count(humanid) from table where action='enter' group by humanid
2. select humanid, count(humanid) from table where action='exit' group by humanid

3. select humanid from 1, 2  where 1.count>2.count

Но тут накладываются условия. Это частичное решение. Неверное.
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #6 : 19-03-2009 07:58 » 

а вот так будет наверное правильней

1. select humanid, max(date) from table where action='enter'
2.  select humanid, max(date) from table where action='exit'
3. select humanid from 1, 2 where 1.max>2.max

Вот еще вариант
развернуть таблицу в
humanid Date_enter Date_exit

типа такого

1. select humanid, case action when 'enter' then date else null, case action when 'exit' then date else null from table
2. select humanid from 1 where Date_exit is null
Но сильно сомневаюсь, что первый селект верный.
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 19-03-2009 17:10 » 

Если надо вывести пользователей, которые внутри, то задачу можно переформулировать.

Один вариант: последняя запись для пользователя 'enter'. Классическое решение: группировка с последующим join с исходной таблицей, чтобы добраться до агрегируемых полей. Подзапросом определяем последние даты для всех пользователей. Потом по этим датам и пользователям выбираем записи, и среди них оставляем лишь те, которые содержат Action='enter'
Код:
SELECT T.HumanId
FROM
 (
  SELECT ST.HumanId, MAX(ST.Date) AS LastDate
  FROM <table> ST
  GROUP BY ST.HumanId
 ) GT
  INNER JOIN <table> T
   ON GT.HumanId = T.HumanId AND GT.Date = T.Date
WHERE T.Action = 'enter'
У решения есть потенциальная проблема: если MAX(Date) соответствует несколько записей с одинаковой датой, то результат становится непредсказумемым, поскольку среди этих записей могут быть и 'enter' и 'exit', и фактический порядок событий не определить (ссылаться на автоинкрементируемый первичный ключ тоже ненадёжно). Если дата хранится со временем с высокой точностью (допустим, до 100 наносекунд), то вероятность ошибки практически отсутствует, и решение можно считать хорошим.

Другой вариант: известно, что для пользователя "внутри" количество 'enter' = количества 'exit' + 1.
Код:
SELECT T1.HumanId
FROM
 (
  SELECT T1.HumanId, COUNT(T1.Date) AS Enters
  FROM <table> T1
  WHERE T1.Action = 'enter'
  GROUP BY T1.HumanId
 ) GT1
  INNER JOIN
   (
    SELECT T2.HumanId, COUNT(T2.Date) AS Exits
    FROM <table> T2
    WHERE T2.Action = 'exit'
    GROUP BY T2.HumanId
   ) GT2
   ON GT1.HumanId = GT2.HumanId
WHERE GT1.Enters = GT2.Exits + 1
И у этого решения есть потенциальная проблема: если были обрывы соединений, то в базе будут висеть "вечные" сессии, что приведёт к невозможности использовать этот способ.

Работоспособность не проверял. Не исключено, что второй вариант можно упростить - надо подумать, а некогда.
« Последнее редактирование: 19-03-2009 17:12 от dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #8 : 19-03-2009 20:27 » 

dimka, я предлагал аналогичные варианты

для правильного отображения событий, на мой взгляд,
нужна таблица приведенная в посте 6
но тут опять возможны варианты
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines