2011-03-17 3 views
0

У меня есть вызов, с которым я не могу найти ответы на любые обычные способы. Я хочу сделать как можно больше в одном запросе, потому что моя единственная альтернатива - это сценарий этой функции, а foreach - цикл с бесчисленными подзапросами.Сопряжение элементов в SQL и вычитание результата

Итак, у меня есть таблица протоколирования на сервере MySQL, он имеет следующие столбцы: Key, USERID, даты-времени и положение позиция может быть «начать», «вход» и «конец».

Я хочу узнать разницу между «стартом», «login» и «end» для каждого события входа. У кого-нибудь есть идея SQL-запроса, который я мог бы использовать? Я думаю, что это как-то связано с запросом в запросе, но я могу найти только JOINs?

Я полагаю, что сначала я бы выбрал события «start», а затем для каждого события «start» он должен искать следующее первое событие входа для «UserID» (после времени «start», но меньше время следующего «запуска» для того же «UserID»), затем DATE_SUB(), чтобы узнать разницу. Было бы важно отфильтровать события «входа» или «завершения», которые произойдут после будущего «стартового» события, если это не произойдет.

Я был бы очень признателен, если бы кто-нибудь мог спасти меня, делая это в Excel, потому что тогда я могу избежать ощущения слишком грязного с тысячами vlookup. Я рассматриваю это в PHP или Perl и просто создаю цикл с операторами LIMIT 1 SQL, но это может создать тысячи SQL-запросов по сравнению с одним достойным оператором SQL SELECT.

+1

Можете ли вы показать нам примерную таблицу с 5 записями и какой результат вы ищете, учитывая, что эти 5 штук? – Matt

+1

Почему бы не обновить три даты в одной строке? Если вы точно знаете, что у каждого пользователя будет время начала, время входа в систему и время окончания, может быть, вам лучше со стола, например, tbl (key, uid, start, login, end)? – Jai

ответ

0

Вот базовый подход, если у вас только даты начала и окончания. Я не совсем понимаю, как вписывается позиция входа в систему, поэтому вам нужно будет более четко объяснить, какой результат вы хотите, или задать вопрос в соответствии с вашим удовлетворением. Кроме того, запрос находится на SQL-сервере, поскольку у меня нет MySQL - извините!

CREATE TABLE LogTable 
(
    id int IDENTITY, 
    userId nvarchar(20), 
    logDate datetime, 
    position nvarchar(5)  
) 
GO 

INSERT INTO LogTable (userId, logDate, position) VALUES ('User1', '2001-01-01', 'start') 
INSERT INTO LogTable (userId, logDate, position) VALUES ('User1', '2001-01-02', 'end') 
INSERT INTO LogTable (userId, logDate, position) VALUES ('User1', '2001-01-05', 'start') 
INSERT INTO LogTable (userId, logDate, position) VALUES ('User1', '2001-01-08', 'end') 
INSERT INTO LogTable (userId, logDate, position) VALUES ('User2', '2001-01-01', 'start') 
INSERT INTO LogTable (userId, logDate, position) VALUES ('User2', '2001-01-03', 'end') 
INSERT INTO LogTable (userId, logDate, position) VALUES ('User2', '2001-01-06', 'start') 
INSERT INTO LogTable (userId, logDate, position) VALUES ('User2', '2001-01-07', 'end') 
GO 

SELECT log1.userId, log1.logDate AS [start], log2.logDate AS [end], 
     DATEDIFF(d, log1.logDate, log2.logDate) AS [Diff. in Days] 
FROM LogTable log1 JOIN 
     LogTable log2 ON log1.userId = log2.userId 
WHERE log1.position = 'start' 
AND  log2.position = 'end' 
AND  log2.logDate > log1.logDate 
AND  NOT EXISTS (
    SELECT * 
    FROM LogTable logDateCheck 
    WHERE logDateCheck.userId = log1.userId 
    AND  logDateCheck.logDate >= log1.logDate 
    AND  logDateCheck.logDate <= log2.logDate 
    AND  logDateCheck.id NOT IN (log1.id, log2.id)) 
GO 

Выход:

Output from query

1

Я не уверен, что MySQL. В MS SQL Server Я хотел бы попробовать что-то вроде следующего:

SELECT Key, UserID, DateTime, Position, 
    (DateTime - (SELECT MAX(DateTime) FROM <table> t1 
       WHERE t1.UserID=UserID AND t1.DateTime < DateTime)) AS DiffToLastEvent 
FROM <table> 

Я на самом деле не пробовал, но вот что я хотел бы начать с. Это должно выбрать все столбцы из таблицы <table> с дополнительным полем, которое содержит разницу во времени текущего элемента, к самому младшему элементу, созданному для пользователя до текущего элемента.

+0

Этот подход не будет работать, если один и тот же пользователь может войти в систему несколько раз, что я предполагаю, так это (вопрос на этом не ясен). –

+1

Конечно. Он вычисляет время между текущим и последним событием, независимо от того, что * событие. Если разрешено несколько логинов для одного и того же пользователя, вы в какой-то момент получаете разницу во времени между текущим и последним входами. Я не претендовал на вычисление «вошедшего в систему» ​​времени. –

+1

Извинения - вы совершенно правы. По-видимому, синтаксический анализатор SQL в моей голове нуждается в уточнении ...;) –

Смежные вопросы