2010-03-23 7 views
18

Mam dwie tabele. indRailType zawiera listę nazw skojarzonych z wartością identyfikatora używaną w innych tabelach do wskazania rodzaju szyny. WO_BreakerRail zawiera kolumnę z datą i kolumnę kodu kolejowego, która odpowiada temu samemu kodowi w indRailType i kilku innych danych. W przypadku każdej czynności na każdym typie szyny istnieje wiersz dla każdej daty. Mógłbym mieć 3 wiersze datowane na 3/19/2010, każdy wiersz wskazuje inny kod szyny i co się stało.LEFT OUTER JOIN z klauzul WHERE

Kiedy używam poniższego LEFT OUTER JOIN, otrzymuję stół ze wszystkimi rodzajami szyn, z zerami w rzędach, gdzie nic się nie wydarzyło w dniu 19. Teraz działa to tylko dlatego, że mam tylko jedną datę reprezentowaną w tabeli WO_BreakerRail teraz, 19. Kiedy dodaję więcej wierszy z różnymi datami, wszystko pójdzie szaleństwem.

To jest moja instrukcja SQL, która teraz daje mi dokładnie wyniki chcę:

SELECT WO_BreakerRail.ID, indRailType.RailType, WO_BreakerRail.CreatedPieces, 
    WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, 
    WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop 
FROM indRailType 
LEFT OUTER JOIN WO_BreakerRail 
    ON indRailType.RailCode = WO_BreakerRail.RailCode 

Teraz, kiedy dodać w WHERE WO_BreakerRail.Date = @Date klauzuli I utracić wszystkie wiersze w JOIN których nic się nie stało. Nie chcę tego. Od czytania do góry, to brzmi jak PEŁNA OUTER JOIN jest to, czego chcę, ale SQL Server Compact Edition nie obsługuje FULL OUTER JOIN s. Czy jest jakiś sposób obejścia tego, czy też szukam czegoś zupełnie innego?

Odpowiedz

35

Wypróbuj:

SELECT WO_BreakerRail.ID, indRailType.RailType, WO_BreakerRail.CreatedPieces, 
    WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, 
    WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop 
FROM indRailType 
LEFT OUTER JOIN WO_BreakerRail ON indRailType.RailCode = WO_BreakerRail.RailCode 
      AND WO_BreakerRail.Date = @Date 

Zatem dodanie AND WO_BreakerRail.Date = @Date na przyłączenia

+1

Nie zapomnij o uwzględnieniu części "czasu" @Date. Jeśli wartości mogą się różnić między północą a północą, będziesz musiał użyć pewnej formy między klauzulami. –

+0

Ta odpowiedź działała doskonale, dziękuję. Philip: Dzięki za ten wskaźnik, chociaż wpadłem na ten problem wcześniej w tym projekcie, który wprawiał mnie w zakłopotanie przez jakiś czas, ale skończyło się na tym, że naprawiłem go w moim kodzie C#, usuwając wszystkie porcje czasu, domyślnie każdą datę do północy. – Wesley

+1

@Wesley, najlepiej jest "posadzić" datetime typy danych, aby usunąć czas, więc czas jest 00: 00: 00.000, a nie północ. –

2

dodać WO_BreakerRail.Date = @Date na rachunku LEFT OUTER JOIN a nie WHERE:

SELECT 
    WO_BreakerRail.ID, indRailType.RailType, WO_BreakerRail.CreatedPieces, WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop 
    FROM indRailType 
     LEFT OUTER JOIN WO_BreakerRail ON indRailType.RailCode = WO_BreakerRail.RailCode AND WO_BreakerRail.Date = @Date 

lub można go dodać do gdzie:

SELECT 
    WO_BreakerRail.ID, indRailType.RailType, WO_BreakerRail.CreatedPieces, WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop 
    FROM indRailType 
     LEFT OUTER JOIN WO_BreakerRail ON indRailType.RailCode = WO_BreakerRail.RailCode 
    WHERE (WO_BreakerRail.Date = @Date OR WO_BreakerRail.Date IS NULL) 
5

Można użyć tego gdzie klauzuli:

WHERE WO_BreakerRail.Date = @Date OR WO_BreakerRail.Date IS NULL 
+3

Podczas pracy z sprzężenia zewnętrzne, to najlepiej f actor wszelkie "isnull work" w klauzuli ON, a nie w miejscu gdzie klauzula –

15

Stan orzeczenie musi być w klauzuli On do łączenia, w przypadkach, gdy nie punktu. Sposób, w jaki łączenie zewnętrzne działa, jest po przeanalizowaniu warunków łączenia, wszystkie wiersze od "strony zewnętrznej", które nie pasują do strony wewnętrznej, są dodawane z powrotem .... Jednak wszystko to dzieje się przed przetworzeniem klauzuli where. Jeśli więc klauzula where określa filtry dla atrybutu po zewnętrznej stronie sprzężenia zewnętrznego, wszystkie te wiersze zostaną ponownie usunięte ... (Wszystkie są zerowe). Umieścić predykat w stanie przyłączyć zamiast, to dostanie oceniane przed brakujące wiersze są dodawane z powrotem w ...

SELECT b.ID, t.RailType, b.CreatedPieces, 
     b.OutsideSource, b.Charged, b.Rejected, 
     b.RejectedToCrop 
FROM indRailType t 
    LEFT JOIN WO_BreakerRail b 
     ON t.RailCode = b.RailCode 
      And b.Date = @Date 
0

Co chcesz jest do filtrowania WO_BreakerRail do żądanej daty przed dołączeniem go LEWO do indRailType. Jeśli po prostu dodasz instrukcję WHERE, robi się to na odwrót, co powoduje problem, który opisałeś.

Rozwiązania przewidziane dotychczas powinien działać (przenieść warunek w LEFT JOIN), ale chciałbym zaproponować alternatywę: Można użyć podzapytania, aby określić kolejność, w której wszystko powinno być zrobione:

SELECT R.ID, indRailType.RailType, R.CreatedPieces, R.OutsideSource, R.Charged, R.Rejected, R.RejectedToCrop 
    FROM indRailType LEFT OUTER JOIN 
     (SELECT * FROM WO_BreakerRail WHERE Date = @Date) R 
     ON indRailType.RailCode = R.RailCode 

(Nietestowane, ale o ile wiem, SQL Server CE obsługuje podzapytania.)

1

lub można go dodać do WHERE:

SELECT WO_BreakerRail.ID, indRailType.RailType, 
    WO_BreakerRail.CreatedPieces, 
    WO_BreakerRail.OutsideSource, WO_BreakerRail.Charged, 
    WO_BreakerRail.Rejected, WO_BreakerRail.RejectedToCrop 
FROM indRailType, WO_BreakerRailCode 
WHERE indRailType.RailCode = WO_BreakerRail.RailCode(+) 
AND WO_BreakerRail.Date (+) [email protected] 
+0

'(+)' jest operatorem łączenia Oracle i OP używa serwera SQL. Również ta składnia dla sprzężeń zewnętrznych nie jest zalecana do użytku, ponieważ jest bardziej ograniczona i trudniejsza do odczytania niż standardowa składnia "Left Join". [Oracle Docs: Joins] (https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries006.htm) – Wayne