Tek bir tabloda var olmayan satırlara sahip satırları göstermek için SQL birleştirme sorgusu


12

Çalışanların zaman kayıtları için bazı raporlar hazırlamaya çalışıyorum.

Bu soru için özel olarak iki tablonuz var. Çalışanlar Memberstabloda listelenir ve her gün yaptıkları işin zaman girişlerini girerler ve Time_Entrytabloda saklanırlar .

SQL Fiddle ile örnek kurulum: http://sqlfiddle.com/#!3/e3806/7

Ben gidiyorum Sonuçta gösterileri tablodur TÜMMembers sütun listesinde ve daha sonra diğer sütunlarda sorgulanan tarih için onların toplamı saat gösterecektir.

Sorun şu ki, Time_Entrybelirli bir üye için tabloda satır yoksa, o üye için şimdi satır vardır. Birkaç farklı birleştirme türleri denedim (Sol, Sağ, İç, Dış, Tam Dış, vb) ama hiçbiri bana (SQL Fiddle'daki son örneğe dayanarak) ne istediğimi veriyor gibi görünüyor:

/*** Desired End Result ***/

Member_ID   | COUNTTime_Entry | TIMEENTRYDATE | SUMHOURS_ACTUAL | SUMHOURS_BILL
ADavis      | 0               | 11-10-2013    | 0               | 0
BTronton    | 0               | 11-10-2013    | 0               | 0
CJones      | 0               | 11-10-2013    | 0               | 0
DSmith      | 0               | 11-10-2013    | 0               | 0
EGirsch     | 1               | 11-10-2013    | 0.92            | 1
FRowden     | 0               | 11-10-2013    | 0               | 0

Şu anda 11-1 belirli tarih için sorgulamak ne alıyorum:

Member_ID   | COUNTTime_Entry | TIMEENTRYDATE | SUMHOURS_ACTUAL | SUMHOURS_BILL
EGirsch     | 1               | 11-10-2013    | 0.92            | 1

Hangi EGirsch için 11-10-2013 tarihli bir Zaman Giriş satırına dayalı doğru, ama raporları almak için diğer üyeler için sıfırlar ve sonunda bu bilgi için bir web kontrol paneli / rapor görmek gerekir.

Bu benim ilk sorum ve Ben katılma sorguları, vb ararken Dürüst olmak gerekirse bu işlev ne denir emin değilim, bu yüzden umarım bu bir kopya değildir ve başkalarının da bir çözüm bulmaya çalışırken yardımcı olacaktır benzer sorunlar.

Yanıtlar:


11

SQLfiddle ve örnek veriler için teşekkür ederiz! Bu şekilde daha fazla soru başlatılmasını dilerim.

Tüm üyelerin o tarih için bir girişleri olup olmadıklarına bakılmaksızın, a LEFT OUTER JOIN. Bu versiyona çok yaklaştınız, ancak dış birleşimlerle ilgili küçük bir hile, cümledeki dış tabloya bir filtre eklerseniz WHERE, bir dış birleşimi bir iç birleşime çevirirsiniz, çünkü o NULLtaraftaki satırları hariç tutar ( NULLfiltreyle eşleşip eşleşmeyeceğini bilmediği için).

Her üye için bir satır almak için ilk sorguyu değiştirdim:

SELECT Members.Member_ID
      ,Time_Entry.Date_Start
      ,Time_Entry.Hours_Actual
      ,Time_Entry.Hours_Bill
FROM dbo.Members
  LEFT OUTER JOIN dbo.Time_Entry
--^^^^ changed from FULL to LEFT
  ON Members.Member_ID = Time_Entry.Member_ID
  AND Time_Entry.Date_Start = '20131110';
--^^^ changed from WHERE to AND

Okuyucunun oradan alması ve diğer sütunları, biçimlendirmeyi COALESCEvb. Eklemesi için bir egzersiz olarak bırakacağım .

Diğer bazı notlar:


Aaron, geri bildiriminiz için çok teşekkürler. SQL burada acemi ve hiçbir fikri arasındaki fark vardı WHEREve AND. Başlangıçta takma adlar kullanmıştım, ancak sqlfiddle hoşuna gitmedi, bu yüzden tam formatta gittim. Diğer SQL ipuçları için de teşekkürler. Eğer tavsiye eder ISNULLya da COALESCEveri yapmak için 0 yerine NULL? Tekrar teşekkürler!
farewelldave

1
@farewelldave COALESCE'yi tercih ediyorum çünkü standart ve diğer dillerdeki işlevlerinden sapmıyor (örneğin ISNULL'un SQL Server ve VB'de nasıl çalıştığını karşılaştırın). Neredeyse tüm durumlarda, bir tanesi hariç, performans farkı önemsizdir. Burada daha fazla ayrıntı var .
Aaron Bertrand

4

Geçmişte bu tür bir sorunla karşılaştığımda , eksik satırlarla başa çıkmak için bir "sayılar" tablosu oluşturdum .

Özellikle tarihlerle başa çıkmak için numaralar tablomu oluşturdum:

CREATE TABLE Dates
(
    dDate DATETIME NOT NULL CONSTRAINT PK_Dates PRIMARY KEY CLUSTERED
);

INSERT INTO Dates (dDate)
SELECT TOP(73049) DATEADD(d, -1, ROW_NUMBER() OVER (ORDER BY o.object_id)) AS dDate
FROM master.sys.objects o, master.sys.objects o1, master.sys.objects o2

Bu, 1900-01-01 ve 2099-12-31 arasındaki her tarih için tek bir satır içeren bir tablo oluşturur. TOP(73049)Örneğimde oluşturulan tarih aralığını bu tarihlerle sınırlamak için kullanıyorum - farklı bir tarih aralığıyla çalışıyorsanız, bu sayıyı ayarlayabilirsiniz.

Daha sonra, dDatesher sorgu için istenen aralıktaki her tarih için bir satır döndürülmesi için sorguma tablo eklerim member_id. Sonuç daha sonra aşağıdaki Time_Entrygibi tabloya birleştirilir :

SELECT MD.Member_ID,
    MD.dDate,
    T.Date_Start,
    T.Hours_Actual,
    T.Hours_Bill
FROM 
    (
        SELECT M.Member_ID, D.dDate
        FROM dbo.Dates D, dbo.Members M
        WHERE D.dDate >= '20131110' AND D.dDate < '20131112'
    ) AS MD
    LEFT JOIN dbo.Time_Entry T ON MD.Member_ID = T.Member_ID AND MD.dDate = T.Date_Start
ORDER BY MD.Member_ID, MD.dDate

Bu, rapor için bir tarih aralığı belirlemenizi sağlar.

Aşağıdakileri ekleyerek COALESCE(...)ve aşağıdakilere göre sonuçları daha da daraltabilirsiniz SUM(...):

SELECT MD.Member_ID,
    MD.dDate,
    T.Date_Start,
    SUM(COALESCE(T.Hours_Actual, 0)) AS TotalHoursActual,
    SUM(COALESCE(T.Hours_Bill, 0)) AS TotalHoursBill
FROM 
    (
        SELECT M.Member_ID, D.dDate
        FROM dbo.Dates D, dbo.Members M
        WHERE D.dDate >= '20131110' AND D.dDate < '20131112'
    ) AS MD
    LEFT JOIN dbo.Time_Entry T ON MD.Member_ID = T.Member_ID AND MD.dDate = T.Date_Start
GROUP BY MD.Member_ID, MD.dDate, T.Date_Start
ORDER BY MD.Member_ID, MD.dDate

Bu, örnek verileriniz için aşağıdaki çıktıyla sonuçlanır:

resim açıklamasını buraya girin


Teşekkürler, Max. "Sayı tablosu" yerine "taksit tablosu" arayarak bu teknik hakkında birçok bilgi bulabilirsiniz. İmleçler / döngüler kullanarak işlemleri kümeler kullanarak işlemlere dönüştürerek performansı artırmak için mükemmeldirler. İlişkisel veritabanları kümeleri tercih eder.
Suncat2000

1
@ Suncat2000 - katılıyorum, çünkü taksitli ek ima anlamına gelir ve benim deneyim, bu desen nadiren matematiksel işlemler için kullanılır. Pek çok şey için harikadır, ancak kesinlikle elde edebileceğiniz en büyük performans geliştirmelerinden biri, bir RBAR yaklaşımından, bir sayı tablosu kullanarak set tabanlı bir yaklaşıma geçmektir.
Max Vernon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.