SQL Join Игнорировать несколько совпадений (нечеткие результаты в порядке) - PullRequest
4 голосов
/ 29 июня 2010

Я даже не знаю, как называется моя проблема, поэтому я просто добавлю несколько примеров данных. Я не возражаю против нечетких результатов (это лучший способ выразить это. Я не против, если я пропущу некоторые данные, это для приблизительной оценки, а не для подробного учета, если это имеет смысл). Но мне нужна каждая запись в ТАБЛИЦЕ 1, и я хотел бы избежать нуля, указанного ниже.

ЭТО ВОЗМОЖНО?

TABLE 1
acctnum sub fname  lname  phone
 12345   1   john   doe   xxx-xxx-xxxx
 12346   0   jane   doe   xxx-xxx-xxxx
 12347   0   rob    roy   xxx-xxx-xxxx
 12348   0   paul  smith  xxx-xxx-xxxx

TABLE 2
acctnum sub division
 12345   1   EAST
 12345   2   WEST
 12345   3   NORTH
 12346   1   TOP
 12346   2   BOTTOM
 12347   2   BALLOON
 12348   1   NORTH

Так что, если мы сделаем "обычное внешнее" соединение, мы получим некоторые результаты, подобные этому, так как суб 0 не соответствуют второй таблице:

TABLE AFTER JOIN
acctnum sub fname  lname  phone         division
 12345   1   john   doe   xxx-xxx-xxxx   EAST
 12346   0   jane   doe   xxx-xxx-xxxx   null
 12347   0   rob    roy   xxx-xxx-xxxx   null
 12348   0   paul  smith  xxx-xxx-xxxx   null

Но я бы лучше получил

TABLE AFTER JOIN
acctnum sub fname  lname  phone         division
 12345   1   john   doe   xxx-xxx-xxxx   EAST
 12346   0   jane   doe   xxx-xxx-xxxx   TOP
 12347   0   rob    roy   xxx-xxx-xxxx   BALLOON
 12348   0   paul  smith  xxx-xxx-xxxx   NORTH

И я стараюсь избегать:

TABLE AFTER JOIN
acctnum sub fname  lname  phone         division
 12345   1   john   doe   xxx-xxx-xxxx   EAST
 12345   1   john   doe   xxx-xxx-xxxx   WEST
 12345   1   john   doe   xxx-xxx-xxxx   NORTH
 12346   0   jane   doe   xxx-xxx-xxxx   TOP
 12346   0   jane   doe   xxx-xxx-xxxx   BOTTOM
 12347   0   rob    roy   xxx-xxx-xxxx   BALOON
 12348   0   paul  smith  xxx-xxx-xxxx   NORTH

Так что я решил пойти с использованием союза и двух условий. Я приму ноль для условий, в которых дополнительный аккаунт определен в таблице 1, но не в таблице 2, а для всего остального я просто сопоставлю мин.

Ответы [ 4 ]

3 голосов
/ 29 июня 2010

Если я правильно понимаю, похоже, что вы пытаетесь присоединиться к столбцу sub, если он совпадает.Если на sub нет совпадений, то вы хотите, чтобы он выбрал «первую» строку для этого acctnum.Правильно ли это?

Если это так, вам нужно будет выполнить левое соединение при полном совпадении, а затем выполнить другое левое соединение с оператором select, который определяет division, который соответствует наименьшему subзначение для этого acctnum.Функция row_number() может помочь вам в этом, например:

select
    t1.acctnum, 
    t1.sub, 
    t1.fname, 
    t1.lname, 
    t1.phone, 
    isnull(t2_match.division, t2_first.division) as division

from table1 t1

left join table2 t2_match on t2_match.acctnum = t1.acctnum and t2_match.sub = t1.sub
left join 
(
    select 
        acctnum, 
        sub, 
        division,
        row_number() over (partition by acctnum order by sub) as rownum

    from table2
) t2_first on t2_first.acctnum = t1.acctnum

РЕДАКТИРОВАТЬ

Если вас не волнует , который записав, что вы вернетесь из таблицы 2, когда соответствующего сабвуфера не существует, вы можете объединить два разных запроса (один, который соответствует сабвуферу, а другой - с делением min или max) с union.

select
    t1.acctnum, 
    t1.sub, 
    t1.fname, 
    t1.lname, 
    t1.phone, 
    t2.division

from table1 t1

join table2 t2 on t2.acctnum = t1.acctnum and t2.sub = t1.sub

union

select
    t1.acctnum, 
    t1.sub, 
    t1.fname, 
    t1.lname, 
    t1.phone, 
    min(t2.division)

from table1 t1

join table2 t2 on t2.acctnum = t1.acctnum
left join table2 t2_match on t2_match.acctnum = t1.acctnum and t2_match.sub = t1.sub

where t2_match.acctnum is null

Лично я не нахожу синтаксис union более убедительным, и теперь вам нужно поддерживать запрос в двух местах.По этой причине я бы предпочел подход row_number().

2 голосов
/ 29 июня 2010

попробуйте использовать

SELECT     MIN(Table_1.acctnum) as acctnum , MIN(Table_1.sub) as sub,MIN( Table_1.fname) as fname, MIN(Table_1.lname) as name, MIN(Table_1.phone) as phone, MIN(Table_2.division) as division 
FROM Table_1 INNER JOIN   Table_2 ON Table_1.acctnum = Table_2.acctnum AND Table_1.sub = Table_2.sub
where Table_1.sub>0
group by Table_1.acctnum 
union 
SELECT     MIN(Table_1.acctnum) as acctnum , MIN(Table_1.sub) as sub,MIN( Table_1.fname) as fname, MIN(Table_1.lname) as name, MIN(Table_1.phone) as phone, MIN(Table_2.division) as division 
FROM Table_1 INNER JOIN   Table_2 ON Table_1.acctnum = Table_2.acctnum 
where Table_1.sub=0
group by Table_1.acctnum

это результат

12345   1   john        doe         xxxxxxxxxx  EAST      
12346   0   jane        doe         xxxxxxxxxx  BOTTOM    
12347   0   rob         roy         xxxxxxxxxx  BALLOON   
12348   0   paul        smith       xxxxxxxxxx  NORTH  

если вы измените мин на макс, ТОП будет добавлен снизу во второй строке

1 голос
/ 29 июня 2010

Это также может работать для вас:

SELECT  t1.acctnum, t1.sub, t1.fname, t1.lname, t1.phone, 
ISNULL(MAX(t2.division),MAX(t3.division)) as division
FROM table_1 t1
LEFT JOIN table_2 t2 ON (t2.acctnum = t1.acctnum AND t1.sub = t2.sub)
LEFT JOIN table_2 t3 ON (t3.acctnum = t1.acctnum)
GROUP BY  t1.acctnum, t1.sub, t1.fname, t1.lname, t1.phone
1 голос
/ 29 июня 2010

Это даст желаемый результат, точно (для показанных данных):

Обновлено , чтобы не предполагать, что всегда есть значение sub == 1:

SELECT
    T1.acctnum,
    T1.sub,
    T1.fname,
    T1.lname,
    T1.phone,
    T2.division
FROM
    TABLE_1 T1
LEFT JOIN
    TABLE_2 T2  ON T1.acctnum = T2.acctnum
AND
    T2.sub  = (SELECT MIN(T3.sub) FROM TABLE_2 T3  WHERE T1.acctnum = T3.acctnum)
ORDER BY
    T1.lname,
    T1.fname,
    T1.acctnum
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...