2015-08-17 10 views
5

Mam dwie tabele, jak poniżejPołączeń SQL. Jeden do wielu relacji

 
Table 1 
----------------------------------- 
UserID | UserName | Age | Salary 
----------------------------------- 
1  | foo  | 22 | 33000  
----------------------------------- 
 
Table 2 
------------------------------------------------ 
UserID | Age  | Salary  | CreatedDate 
------------------------------------------------ 
1  | NULL  | 35000  | 2015-01-01 
------------------------------------------------ 
1  | 28  | NULL  | 2015-02-01 
------------------------------------------------ 
1  | NULL | 28000  | 2015-03-01 
------------------------------------------------ 

muszę wynik takiego.

 
Result 
----------------------------------- 
UserID | UserName | Age | Salary 
----------------------------------- 
1  | foo  | 28 | 28000 
----------------------------------- 

To tylko przykład. W moim prawdziwym projekcie mam ponad 6 kolumn, takich jak Wiek i Wynagrodzenie w powyższych tabelach.

W tabeli 2 każdy rekord będzie miał tylko jedną wartość, np. Jeśli wiek ma wartość, wówczas wynagrodzenie będzie mieć wartość NULL i viceversa.

AKTUALIZACJA:

Tabela 2 zawiera kolumnę CreatedDate. Więc chcę uzyskać najnowszą wartość "NOTNULL" CELL zamiast maksymalnej wartości.

+0

Czy naprawdę * * dane mają takiego w Tabeli 2? Jeśli jest coś, co możesz z tym zrobić, najpierw przyjrzę się temu problemowi. A może nie rozumiem problemu - opublikuję odpowiedź. –

+0

Mam nadzieję, że dla tego samego użytkownika wstawiasz jedną informację po drugiej. Powinieneś wypróbować polecenie aktualizacji –

+1

Mysql serwera sql? –

Odpowiedz

3

Uwaga: Daje mi to korzyści z wątpliwości, że wiesz, co robisz, a po prostu nie powiedziałeś nam wszystkiego o swoim schemacie.

Wygląda na to, że Table 2 jest w rzeczywistości tabelą "aktualizacji", w której każdy wiersz zawiera różnicę zmian, które mają zastosowanie do jednostki podstawowej w Table 1. W takim przypadku można pobrać dane każdej kolumny za pomocą skorelowanego sprzężenia (technicznie zewnętrznie) i połączyć wyniki. Coś jak następuje:

select a.UserID, a.UserName, 
    coalesce(aAge.Age, a.Age), 
    coalesce(aSalary.Salary, a.Salary) 
from [Table 1] a 
outer apply (
    select Age 
    from [Table 2] x 
    where x.UserID = a.UserID 
    and x.Age is not null 
    and not exists (
     select 1 
     from [Table 2] y 
     where x.UserID = y.UserID 
     and y.Id > x.Id 
     and y.Age is not null 
    ) 
) aAge, 
outer apply (
    select Salary 
    from [Table 2] x 
    where x.UserID = a.UserID 
    and x.Salary is not null 
    and not exists (
     select 1 
     from [Table 2] y 
     where x.UserID = y.UserID 
     and y.Id > x.Id 
     and y.Salary is not null 
    ) 
) aSalary 

Należy pamiętać, jestem zakładając, że masz co najmniej kolumnę Id w Table 2 który jest monotonicznie rosnącą z każdym wkładki. Jeśli masz kolumnę "czas zmiany", użyj tego, aby uzyskać najnowszy wiersz, ponieważ jest lepszy.

+0

Jest to jedyna odpowiedź, która do tej pory próbuje nadać sens danym danym. –

+0

Znakomicie działa. Dzięki @Ic. Zamiast tylko kopiować powyższą odpowiedź i używać, chcę poznać tę koncepcję. Więc proszę nazwać to pojęcie? i pytanie. dlaczego linia 'i x.Salary nie ma wartości null'? bez tej linii możemy użyć tylko jednej zewnętrznej, aby zastosować tyle kolumn, ile potrzebujemy. –

+0

@JSantosh Cieszę się, że pomogło to. Nie jestem do końca pewien technicznej nazwy pojęcia, ale możesz nazwać "Tabelę 2" "tabelą zmian". Nie nazwałbym tego pełną tabelą "historii" lub "dziennika", ponieważ zawiera ona tylko deltę zmienionych właściwości, a nie pełną migawkę wiersza w czasie aktualizacji, ale koncepcja jest raczej podobna - śledzenie wszystkie wersje podmiotu w czasie. Powodem, dla którego musimy zrobić 'i x.Salary nie jest null' jest to, że 'null' jest specjalną wartością oznaczającą" bez zmian ", którą musimy usunąć z zestawu wyników niezależnie dla * każdej * właściwości. –

2

Aby uzyskać najnowszą wartość w oparciu o CreatedDate, można użyć ROW_NUMBER do filtrowania ostatnich rzędów. Tutaj partycja jest oparta na UserID i innych kolumnach, Age i Salary.

SQL Fiddle

;WITH Cte AS(
    SELECT 
     UserID, 
     Age = MAX(Age), 
     Salary = MAX(Salary) 
    FROM(
     SELECT *, Rn = ROW_NUMBER() OVER(
         PARTITION BY 
          UserID, 
          CASE 
           WHEN Age IS NOT NULL THEN 1 
           WHEN Salary IS NOT NULL THEN 2 
          END 
         ORDER BY CreatedDate DESC 
         ) 
     FROM Table2 
    )t 
    WHERE Rn = 1 
    GROUP BY UserID 
) 
SELECT 
    t.UserID, 
    t.UserName, 
    Age = ISNULL(c.Age, t.Age), 
    Salary = ISNULL(c.Salary, t.Salary) 
FROM Table1 t 
LEFT JOIN Cte c 
    ON t.UserID = c.UserID 
4

można uzyskać to zrobić za pomocą prostego MAX() i GROUP BY:

select t1.userid,t1.username, MAX(t2.Age) as Age, MAX(t2.Salary) as Salary 
from table1 t1 join 
    table2 t2 on t1.userid=t2.userid 
group by t1.userid,t1.username 

Wynik:

userid username Age Salary 
-------------------------------- 
1  foo   28 35000 

wynik próbki w SQL Fiddle

0

następujące zapytanie powinno działać (działa dobrze w MSSQL):

select a.userID,a.username,b.age,b.sal from <table1> a 
inner join 
(select userID,MAX(age) age,MAX(sal) sal from <table2> group by userID) b 
on a.userID=b.userID 
Powiązane problemy