2013-10-01 2 views
0

Я пытаюсь объединить данные из двух совершенно разных источников. Один источник содержит информацию о расписании сотрудника, а другой отслеживает, что они на самом деле работали (например, какое время они на самом деле приняли обед или перерыв). Проблема в том, что программа расписания дает время как BREAK1, BREAK2, BREAK3 и LUNCH, в то время как программа отслеживания просто перечисляет их как Lunch and Break. Я могу присоединиться к данным и получить обеды просто отлично, но перерывы отбрасывают меня. Если я конвертирую BREAK1, BREAK2 и BREAK3 в «Break», я получаю слишком много сегментов, потому что он сопоставляет каждый экземпляр с любым другим экземпляром. Есть ли способ, который каждый может придумать, чтобы присоединиться к этим двум частям информации? Спасибо.Присоединение к полю с различными значениями

EDIT По вашему желанию, здесь некоторые примерные данные:

Это Запланированные Times:

EMP_ID NOM_DATE SEG_CODE START_MOMENT STOP_MOMENT 
626009 26-Sep-13 BREAK2   9/26/13 5:00 PM 9/26/13 5:15 PM 
625650 26-Sep-13 BREAK2   9/26/13 4:30 PM 9/26/13 4:45 PM 
638815 26-Sep-13 BREAK2   9/26/13 4:00 PM 9/26/13 4:15 PM 
621649 26-Sep-13 BREAK2   9/26/13 3:30 PM 9/26/13 3:45 PM 
567005 26-Sep-13 BREAK2   9/26/13 3:30 PM 9/26/13 3:45 PM 
626009 26-Sep-13 LUNCH   9/26/13 2:30 PM 9/26/13 3:30 PM 
625650 26-Sep-13 LUNCH   9/26/13 1:30 PM 9/26/13 2:30 PM 
638815 26-Sep-13 LUNCH   9/26/13 1:30 PM 9/26/13 2:30 PM 
621649 26-Sep-13 LUNCH   9/26/13 12:30 PM 9/26/13 1:30 PM 
567005 26-Sep-13 LUNCH   9/26/13 12:30 PM 9/26/13 1:30 PM 
626009 26-Sep-13 BREAK1   9/26/13 11:45 AM 9/26/13 12:00 PM 
625650 26-Sep-13 BREAK1   9/26/13 11:30 AM 9/26/13 11:45 AM 
638815 26-Sep-13 BREAK1   9/26/13 11:45 AM 9/26/13 12:00 PM 
621649 26-Sep-13 BREAK1   9/26/13 9:30 AM 9/26/13 9:45 AM 
567005 26-Sep-13 BREAK1 9/26/13 9:30 AM 9/26/13 9:45 AM 

Это фактическое время

EMP_ID Seg_Code Start_Time Stop_Time 
625650 Break   9/26/2013 17:54 9/26/2013 17:55 
567005 Break   9/26/2013 14:56 9/26/2013 14:59 
567005 Break   9/26/2013 15:32 9/26/2013 15:44 
638815 Break   9/26/2013 16:34 9/26/2013 16:47 
567005 Break   9/26/2013 10:08 9/26/2013 10:21 
626009 Break   9/26/2013 17:01 9/26/2013 17:15 
625650 Break   9/26/2013 11:31 9/26/2013 11:45 
626009 Break   9/26/2013 11:52 9/26/2013 12:07 
621649 Break   9/26/2013 9:34 9/26/2013 9:48 
621649 Break   9/26/2013 15:31 9/26/2013 15:45 
638815 Break   9/26/2013 11:46 9/26/2013 12:02 
625650 Break   9/26/2013 16:35 9/26/2013 16:51 
567005 Lunch   9/26/2013 12:31 9/26/2013 13:29 
625650 Lunch   9/26/2013 13:31 9/26/2013 14:30 
626009 Lunch   9/26/2013 14:31 9/26/2013 15:30 
638815 Lunch   9/26/2013 13:31 9/26/2013 14:30 
621649 Lunch   9/26/2013 12:31 9/26/2013 13:30 

Я пытаюсь t o получить разницу (в минутах) между тем, когда они запланированы, и когда они фактически совершают перерывы. Правильный пример:

Badge Seg_Code Scheduled Start  Scheduled Stop  Actual Start   Actual Stop  Difference  Seg_Duration 
192329 Lunch  9/26/13 8:15 AM  9/26/13 9:15 AM  9/26/2013 8:18:27 AM 9/26/2013 9:17:59 AM  3  0:00:59:32 

Еще раз спасибо

+0

RANK в течение дня в течение дня? – zimdanen

+5

Можете ли вы включить структуру таблиц и образцы данных в скрипт SQL? Затем дайте нам ожидаемый результат, и мы сможем сделать это за вас. – Vulcronos

+0

@zimdanen - Я не совсем уверен, что вы говорите? – Dantalion88

ответ

0

Предполагая, что SQL Server:

;WITH Actual_Ranked AS 
(
    SELECT 
     ROWNUM = CASE Seg_Code 
       WHEN 'Break' THEN CAST(ROW_NUMBER() OVER (PARTITION BY EMP_ID, Seg_Code, CAST(Start_Time AS DATE) ORDER BY Start_Time) AS VARCHAR(1)) 
       ELSE '' 
      END, 
     EMP_ID, 
     Seg_Code, 
     Start_Time, 
     Stop_Time 
    FROM 
     #Actual 
) 
SELECT 
    ISNULL(sched.EMP_ID, act.EMP_ID) AS Badge, 
    ISNULL(sched.SEG_CODE, (act.SEG_CODE + ROWNUM)) AS Seg_Code, 
    CONVERT(VARCHAR, sched.START_MOMENT, 22) AS [Scheduled Start], 
    CONVERT(VARCHAR, sched.STOP_MOMENT, 22) AS [Scheduled Stop], 
    CONVERT(VARCHAR, act.Start_Time, 22) AS [Actual Start], 
    CONVERT(VARCHAR, act.Stop_Time, 22) AS [Actual Stop], 
    DATEDIFF(minute, sched.START_MOMENT, act.Start_Time) AS [Difference] 
FROM 
    #Scheduled sched 
    FULL JOIN Actual_Ranked act ON sched.EMP_ID = act.EMP_ID 
     AND sched.SEG_CODE = (act.SEG_CODE + ROWNUM); 

Заменить имена таблиц по мере необходимости.

Ключ в том, что я получаю номер строки перерыва и добавляю это, чтобы сделать работу соединения.

Я не включил Seg_Duration, чтобы сохранить ответ простым, но вы можете показать продолжительность в предпочитаемом вами формате, посмотрев ответы на this question.

SQL Fiddle here.

+0

Благодарим вас за ответ. Когда я запускаю ваш код и изменяю таблицы, в столбцах «Запланированный старт» и «Запланированная стоп» есть значения NULL или поля «Фактический старт» и «Фактическая остановка». Я думаю, это потому, что по какой-то причине он превращает «Фактические» поля в дату 1899 года. Я попытался это исправить, но не могу точно видеть, где это происходит. Я думаю, что это может быть CAST. Еще раз спасибо. – Dantalion88

+0

@ Dantalion88: Используя ваши данные образца, есть две строки, которые будут иметь 'NULL', но они будут находиться только в столбцах «Запланированный старт», «Запланированный стоп» и «Разница». Я приведу SqlFiddle, чтобы продемонстрировать код. Если у вас есть данные, которые не работают, мне нужно будет увидеть их, чтобы помочь вам исправить это. – zimdanen

+0

@ Dantalion88: Добавлен скрипт SQL. Не стесняйтесь меняться, чтобы включить данные, с которыми вы столкнулись, поэтому я могу это увидеть. – zimdanen

0

Хотя в целом не очень хорошая идея в запросах, которые выполняются часто, вы можете использовать строковые функции в условии соединения. Например, в MySQL это будет выглядеть следующим образом:

CREATE TABLE test1 (
    worktype VARCHAR(20) 
); 
INSERT INTO test1 VALUES ('BREAK1'); 
INSERT INTO test1 VALUES ('BREAK2'); 

CREATE TABLE test2 (
    worktype VARCHAR(20) 
); 
INSERT INTO test2 VALUES ('Break'); 

SELECT t1.worktype 't1', t2.worktype 't2' 
FROM test1 t1 
JOIN test2 t2 ON LEFT(t1.worktype, LENGTH(t2.worktype)) = LOWER(t2.worktype); 

В зависимости от вашего приложения это может быть оправдано - например, если вы бежите, что один раз в неделю в пакетном задании, чтобы скопировать данные из источника, над которым у вас нет контроль.

Что касается вашего второго вопроса: если в таблицах нет других данных, которые вы можете использовать в соединении, нет способа избавиться от проблемы, когда «Разрыв» соединен с «BREAK1», и " BREAK2 "и т. Д. - другими словами, энтропия, или плотность информации, просто низкая. Вам нужно придумать «тай-брейкер», чтобы решить, какой из строк («BREAK1», «BREAK2») вы хотите отобразить. Например, вы можете использовать это правило: «всегда используйте BREAK1 над BREAK2». В вашем сообщении недостаточно информации, чтобы придумать правило для вас.

+0

Извините, что не делайте это ясно. Поле EMP_ID также используется для обеспечения соответствия правильных сотрудников каждому источнику. Спасибо. – Dantalion88

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