2016-01-23 3 views
3

У меня есть таблица логинов, который выглядит следующим образом: Таблицавыбрать столбцы в строки сгруппированы по столбцам значения

логинов

Emp_ID Created    | Action 
1  20/01/2016 10:44:42 AM  login 
1  20/01/2016 4:45:49 PM  logout 
1  20/01/2016 6:30:13 PM  logout 
1  21/01/2016 8:46:28 AM  login 
1  21/01/2016 9:46:42 AM  login 
1  21/01/2016 1:46:46 PM  logout 
1  22/01/2016 8:49:21 AM  login 
1  22/01/2016 1:49:27 PM  logout 
1  22/01/2016 2:29:53 PM  login 
1  22/01/2016 2:30:13 PM  logout 
3  22/01/2016 2:42:06 PM  login 
1  22/01/2016 9:57:22 PM  login 
1  22/01/2016 10:22:23 PM  logout 
1  23/01/2016 8:01:47 AM  login 
1  23/01/2016 9:01:58 AM  logout 
3  23/01/2016 8:02:06 AM  login 
3  23/01/2016 9:02:28 AM  logout 

Стол сотрудников

| ID | Fname | Lname | 
|----|-------|-------| 
| 1 | James | Brown | 
| 2 | Mark | Bond | 
| 3 | Kemi | Ojo | 

В результате я получил

| created | login | logout | Employee | Emp_ID | 
|------------|----------|----------|-------------|--------| 
| 2016-01-20 | 10:44:42 | 18:30:13 | James Brown |  1 | 
| 2016-01-21 | 08:46:28 | 13:46:46 | James Brown |  1 | 
| 2016-01-22 | 08:49:21 | 22:22:23 | James Brown |  1 | 
| 2016-01-22 | 14:42:06 | 22:22:23 | Kemi Ojo |  3 | 
| 2016-01-23 | 08:01:47 | 09:02:28 | James Brown |  1 | 
| 2016-01-23 | 08:02:06 | 09:02:28 | Kemi Ojo |  3 | 

что я пробовал:

SELECT 
    CAST(LI.created AS DATE) AS created, 
    MIN(CAST(LI.created AS TIME)) AS login, 
    MAX(CAST(LO.created AS TIME)) AS logout, 
    e.fname+' '+e.lname Employee, li.Emp_ID 

FROM 
    Logins LI 
LEFT OUTER JOIN Logins LO ON 
    LO.action = 'logout' AND 
    CAST(LO.created AS DATE) = CAST(LI.created AS DATE) 
    JOIN dbo.Employees AS E ON E.ID = li.Emp_ID 

WHERE 
    LI.action = 'login' 
GROUP BY 
    CAST(LI.created AS DATE), E.fname + ' ' + E.lname, li.Emp_ID 

Но результат неправильный.

  1. Обратите внимание, что последние два результата для разных пользователей одинаковы. например 09:02:28 появляется вместо 9:01:58

  2. Также у меня есть проблемы с логином без выхода из системы emp_id = 3. Это происходит, когда приложение неожиданно отключается.

3, как я могу поместить 00:00:00 в случае, когда нет выхода из системы 4. Или что бы ваше предложение о том, что делать в этом случае?

нужно выбрать результирующий набор, который выглядит следующим образом:

| created | login | logout | Employee | Emp_ID | 
|------------|----------|----------|-------------|--------| 
| 2016-01-20 | 10:44:42 | 18:30:13 | James Brown |  1 | 
| 2016-01-21 | 08:46:28 | 13:46:46 | James Brown |  1 | 
| 2016-01-22 | 08:49:21 | 22:22:23 | James Brown |  1 | 
| 2016-01-22 | 14:42:06 | 00:00:00 | Kemi Ojo |  3 | 
| 2016-01-23 | 08:01:47 | 09:01:58 | James Brown |  1 | 
| 2016-01-23 | 08:02:06 | 09:02:28 | Kemi Ojo |  3 | 

SQL fiddle

+1

Это очень хороший вопрос: очистить, образцы данных, ваши собственные попытки, неправильный вывод, ожидаемый результат. Thx для этого, +1 с моей стороны! – Shnugo

+1

Да. Ссылка на этот вопрос должна быть указана в разделе «как задавать вопрос» специально для вопросов SQL. – Utsav

ответ

3

Прежде всего, cudos для префекта вопрос. Структура таблицы, демонстрация скриптов и ожидаемый результат помогают.

Теперь я попробовал это, и он работает в скрипке. Пожалуйста, перепроверьте и дайте мне знать.

select t_login.emp_id,t_login.dt_created as created,t_login.login, 
case when t_logout.logout is null 
    then cast('00:00:00' as time) 
else t_logout.logout end as logout, 
e.fname+' '+e.lname Employee 
from 
    (select emp_id,CAST(created AS DATE) AS dt_created, 
    MIN(CAST(created AS TIME)) as login 
    from logins 
    where action='login' 
    group by emp_id,CAST(created AS DATE)) t_login 
left join 
    (select emp_id,CAST(created AS DATE) AS dt_created, 
    max(CAST(created AS TIME)) as logout 
    from logins 
    where action='logout' 
    group by emp_id,CAST(created AS DATE)) t_logout 
     on t_login.emp_id=t_logout.emp_id 
     and t_login.dt_created=t_logout.dt_created 
inner join 
    employees e 
     on e.id=t_login.emp_id 

PS: Это не будет заботиться о тех случаях, когда нет Войти на конкретный день и только выход из системы. Если вы этого хотите, используйте full outer join и используйте тот же оператор case, как я использовал во внешнем select.

Смотрите скрипку демо здесь

http://sqlfiddle.com/#!3/465f0/34

Ouput

+---------+-------------+-------------------+-------------------+-------------+ 
| emp_id | created |  login  |  logout  | Employee | 
+---------+-------------+-------------------+-------------------+-------------+ 
|  1 | 2016-01-20 | 10:44:42.0000000 | 18:30:13.0000000 | James Brown | 
|  1 | 2016-01-21 | 08:46:28.0000000 | 13:46:46.0000000 | James Brown | 
|  1 | 2016-01-22 | 08:49:21.0000000 | 22:22:23.0000000 | James Brown | 
|  3 | 2016-01-22 | 14:42:06.0000000 | 00:00:00.0000000 | Kemi Ojo | 
|  1 | 2016-01-23 | 08:01:47.0000000 | 09:01:58.0000000 | James Brown | 
|  3 | 2016-01-23 | 08:02:06.0000000 | 09:02:28.0000000 | Kemi Ojo | 
+---------+-------------+-------------------+-------------------+-------------+ 
+1

Хорошее решение. Это технически тот же подход, что и мой, разница в том, что вы используете вложенные подвыборки, пока я их упаковывал в CTE. +1 с моей стороны – Shnugo

+0

Я предложил изменить, чтобы избавиться от CASE КОГДА во внешнем SELECT. :) –

+1

Привет @DavidBachmannJeppesen - оцените свои усилия, предлагая редактировать. Операция 'case' работает во всех РСУБД. Однако я не уверен в 'isnull'. Пожалуйста, не возражайте. Спасибо за это в любом случае. Хороший день :) – Utsav

2

Вы пропускаете JOIN между таблицей LO и таблицы LI:

AND LO.Emp_ID = LI.Emp_ID 

Я думаю, вы можете сделать это, не используя самообучение и используя CASE WHEN вместо этого, я думаю, будет красивее, но попробуйте это дополнение.

EDIT от комментариев: Просто замените: MAX (CAST (LO.Created AS Time)) ... с: MAX (CAST (IsNull (LO.Created, '00: 00: 00') AS Время))

+0

это работает, но не заботится о логинах в дате без выхода из системы в этот день – Smith

3

Это мое предложение (быть в курсе культуры конкретной даты литералов. Я должен был установить язык, чтобы получить правильный преобразование даты):

SET LANGUAGE GERMAN; 

DECLARE @logins TABLE(Emp_ID INT,Created DATETIME, Action VARCHAR(100)); 
INSERT INTO @logins VALUES 
(1,'20/01/2016 10:44:42 AM','login') 
,(1,'20/01/2016 4:45:49 PM','logout') 
,(1,'20/01/2016 6:30:13 PM','logout') 
,(1,'21/01/2016 8:46:28 AM','login') 
,(1,'21/01/2016 9:46:42 AM','login') 
,(1,'21/01/2016 1:46:46 PM','logout') 
,(1,'22/01/2016 8:49:21 AM','login') 
,(1,'22/01/2016 1:49:27 PM','logout') 
,(1,'22/01/2016 2:29:53 PM','login') 
,(1,'22/01/2016 2:30:13 PM','logout') 
,(3,'22/01/2016 2:42:06 PM','login') 
,(1,'22/01/2016 9:57:22 PM','login') 
,(1,'22/01/2016 10:22:23 PM','logout') 
,(1,'23/01/2016 8:01:47 AM','login') 
,(1,'23/01/2016 9:01:58 AM','logout') 
,(3,'23/01/2016 8:02:06 AM','login') 
,(3,'23/01/2016 9:02:28 AM','logout'); 

DECLARE @employees TABLE(ID INT,Fname VARCHAR(100),Lname VARCHAR(100)); 
INSERT INTO @employees VALUES 
(1,'James','Brown') 
,(2,'Mark','Bond') 
,(3,'Kemi','Ojo'); 

WITH Logins AS 
(
    SELECT 
     MIN(PureDate) AS Created 
     ,MIN(CAST(l.Created AS TIME)) AS LoginTime 
     ,l.Emp_ID 
    FROM @logins AS l 
    CROSS APPLY(SELECT CAST(l.Created AS DATE) PureDate) AS Created 
    WHERE l.Action ='login' 
    GROUP BY l.Emp_ID,PureDate 
) 
,Logouts AS 
(
    SELECT 
     MAX(PureDate) AS Created 
     ,MAX(CAST(l.Created AS TIME)) AS LogoutTime 
     ,l.Emp_ID 
    FROM @logins AS l 
    CROSS APPLY(SELECT CAST(l.Created AS DATE) PureDate) AS Created 
    WHERE l.Action ='logout' 
    GROUP BY l.Emp_ID,PureDate 
) 
SELECT Logins.Created 
     ,Logins.LoginTime 
     ,ISNULL(Logouts.LogoutTime,'00:00:00') 
     ,e.Lname 
     ,e.ID 
FROM Logins 
INNER JOIN @employees AS e ON e.ID = Logins.Emp_ID 
LEFT JOIN Logouts ON Logins.Emp_ID = Logouts.Emp_ID 
       AND Logins.Created = Logouts.Created 
ORDER BY Created,LoginTime 

Результат

2016-01-20 10:44:42 18:30:13 Brown 1 
2016-01-21 08:46:28 13:46:46 Brown 1 
2016-01-22 08:49:21 22:22:23 Brown 1 
2016-01-22 14:42:06 00:00:00 Ojo  3 
2016-01-23 08:01:47 09:01:58 Brown 1 
2016-01-23 08:02:06 09:02:28 Ojo  3 
+0

Я мог проверить ваш код на скрипке, но должен был занять время, чтобы заставить его работать в коде, которого у меня нет – Smith

+0

@Smith. Для проверки это очень просто: просто вставьте всю партию в пустое окно запроса и выполнить. Это работает с объявленными переменными таблицы (они начинаются с '@'), поэтому вам не нужны какие-либо существующие структуры для его проверки ... Для его использования требуется не что иное, как изменить переменные таблицы на фактические таблицы, которые хотите прочитать из. – Shnugo

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