2011-06-17 24 views
5

İşverenim, kullanıcılar tarafından gönderilen işleri işleyen bir toplu işlem kümesi vardır. SQL'de bir pivot-tablo-ish JOIN yapıyor

  1. işi kullanıcı toplu iş yönetimi yazılımı günlükleri bu adımların her ne

bildirildi

  • sonuçları bitmiş
  • ve günlük dosyası oluşur başladı: Her toplu iş üç adımdan oluşur bir tuple, işi yapan çalışanın bir kimlik koduna, hangi adımın meydana geldiğine ve ne zaman meydana geldiğine ilişkin bir zaman damgasına sahiptir. CSV'de, şu gibi görünür:

    Ve benzeri. Veri kümesinin bir diğer özelliği, çalışanlar arasında bir uyumun olması, ancak çalışanlar arasında bir fikir birliği olmamasıdır; Yani, her çalışanın, mevcut işlerinin bir sonraki iş başlamadan önce bildirmesini beklemek zorundadır. Dolayısıyla, tarihe göre sıralıyorum ve sonuçları tek bir çalışanla sınırladığım zaman, kayıtlar her zaman "başlangıç", "bitiş", "rapor" sırasına göre sıralanır.

    Her işi tek bir sıra halinde gruplandıran bir pivot tablo oluşturmak istiyorum. Yani yukarıdaki veriler haline gelir:

    employee-ID started finished reported 
    ----------- ------- -------- -------- 
    A   3533  3557  3603 
    B   3538  3549  3559 
    B   3611  3643  3657 
    C   3551  3602  3623 
    

    Yani, SQL için:

    SELECT 
        log.ID AS employee-ID, 
        start.timestamp AS started, 
        finish.timestamp AS finished, 
        report.timestamp AS reported 
    FROM 
        log 
    
        LEFT OUTER JOIN log start ON 
        log.ID = start.ID 
         AND start.step = 'start' 
    
        LEFT OUTER JOIN log finish ON 
        log.ID = finish.ID 
         AND finish.step = 'finish' 
         AND start.timestamp < finish.timestamp 
    
        LEFT OUTER JOIN log report ON 
        log.ID = report.ID 
         AND report.step = 'report' 
         AND finish.timestamp < report.timestamp 
    
    ORDER BY employee-ID,started,finished,reported; 
    

    Ben de başladı ama bitmiş değildi ya vardı işleri tespit etmek gerekir, çünkü SOL DIŞ JOIN gerekiyor bildirildi.

    Bu oldukça iyi çalışıyor. Bana ihtiyacım olan satırları veriyor. Ancak bana çok sayıda sahte satır veriyor, çünkü JOIN'ler mevcut işin yanı sıra aynı çalışanın gelecekteki işleri için finish ve report girişleriyle eşleşiyor.

    employee-ID started finished reported 
    ----------- ------- -------- -------- 
    A   3533  3557  3603 
    B   3538  3549  3559 
    B   3538  3549  3657 <-- spurious 
    B   3538  3643  3657 <-- spurious 
    B   3611  3643  3657 
    C   3551  3602  3623 
    

    Bu sahte satırları tanımak kolaydır: Yani rapor dışarı gibi bakıyor geliyor her iş sadece bir kez başladı alır, böylece sıralama göz önüne alındığında, doğru satır benzersiz ilk satırı olan değeri "başladı". Sahte sıralar sorunu etrafında şu anda uygulama düzeyinde sadece sahte satırların üzerinden atlayarak çalışıyorum, ama bu sadece iyi, inelegant gibi görünüyor. Ve bu masraflı: Bu çalışanlardan bazılarının gönderdiği düzinelerce iş var, bu yüzden şu anda sorgularımın sonuçları% 15 oranında meşru girişler ve% 85 oranında sahte. Bu sahte girdiler üzerinde atlayan çok fazla zaman harcanıyor. Her işin kendine özgü bir kimliği olsaydı iyi olurdu, ama bu verilere sahip değilim.

    JOIN'i bir şekilde kısıtlamak zorundayım, böylece her "başlatıldı" girişi için yalnızca bir "bitmiş" ve "raporlanan" girdisini alır: önceki adımın zaman damgasından daha büyük minimum zaman damgası olan tek giriş. Bunu, JOINing olduğum tablo olarak bir alt sorgu kullanarak yapmayı denedim, ancak ilişkili bir alt sorgu olmadan nasıl yapılacağını anlayamadım. Ayrıca "GROUP BY çalışan kimliği," kullanarak çalıştı, ama bu mutlaka "doğru" satır seçmedi. "GROUP BY" satırlarının çoğunun yanlış olduğu bildirildi.

    SQL gurusu, ihtiyacım olan satırları bildirmek mümkün mü? Ve eğer öyleyse, nasıl? Şu anda sqlite3 kullanıyorum, ancak gerekirse veritabanını MySQL'e aktarabilirim.

  • cevap

    2

    sorun finish için katılmadan konum ve report

    Sen start.timestamp < finish.timestamp Eğer gerçekten istediğiniz istemediğiniz nasıl bunu yapmak gerekir böylece çalışmıyor start.timestamp < MIN(finish.timestamp) Tabii

    katılmadan sonra.

    örn. o anlamda bir sürü yapmaz olarak

    SELECT 
        log.ID AS employee_ID, 
        start.timestamp AS started, 
        MIN(finish.timestamp) AS finished, 
        MIN(report.timestamp) AS reported 
    FROM 
        log 
    
    
    LEFT OUTER JOIN log start ON 
    log.ID = start.ID 
        AND start.step = 'start' 
    
    LEFT OUTER JOIN log finish ON 
    log.ID = finish.ID 
        AND finish.step = 'finish' 
        AND start.timestamp < finish.timestamp 
    
    LEFT OUTER JOIN log report ON 
    log.ID = report.ID 
        AND report.step = 'report' 
        AND finish.timestamp < report.timestamp 
    
    GROUP BY log.ID, 
        start.timestamp 
    ORDER BY 
        employee_ID,started,finished,reported 
    

    Ayrıca muhtemelen mükemmel çalışan bir başlangıcı

    +0

    olmadan bitirmek için bir iç için başlangıç ​​katılmak dönüştürmek olabilir! Sorguyu% 5'ten daha az yavaşlatır ve uygulama, filtrelemenin kendisini yapmak zorunda kalmayacak şekilde çok daha hızlı çalışır. Çok teşekkür ederim. – STH