MySQL вложенное левое соединение с внешними ссылками - PullRequest
5 голосов
/ 04 декабря 2011

Допустим, у нас есть эти (упрощенные из более сложных) примерные таблицы:

== st ==    == pr ===   == rn ===  <– tables
sta   pg    pg    rou   sta   rou  <– fields
========    =========   =========
H1    aa    aa    aaA   H1    aaA

H2    aa    aa    aaB   H2    aaB
H3    aa                H3    aaB

H4    aa    aa    aaC   H4    aaC
H5    aa                H5    aaC
H6    aa                H6    aaC

H7    aa

H8    bb    bb    NULL

Я хотел выполнить этот (также упрощенный) запрос с внутренним левым соединением:

SELECT st.*, pr.*, rn.*
FROM         st
INNER JOIN ( pr
LEFT  JOIN   rn  ON pr.rou = rn.rou
                AND          rn.sta = st.sta -- ERROR here
           )     ON pr.pg =           st.pg
-- filter out bad rows
WHERE ( rn.id )                          -- a: not null
   OR ( pr.rou ='aaC' AND rn.id IS NULL) -- b: no joinable rn found: choose
                                         --    by a predefined pr.rou value
   OR ( pr.rou IS NULL )                 -- c: no need to join

чтобы получить такой результат:

== st ==    == pr ===   == rn ===
sta   pg    pg    rou   sta   rou
========    =========   =========
H1    aa    aa    aaA   H1    aaA
H2    aa    aa    aaB   H2    aaB
H3    aa    aa    aaB   H3    aaB
H4    aa    aa    aaC   H4    aaC
H5    aa    aa    aaC   H5    aaC
H6    aa    aa    aaC   H6    aaC

H7    aa    aa    aaA   NULL  NULL \  H7 has no rn, so choose
H7    aa    aa    aaB   NULL  NULL  } 1 row of these at the
H7    aa    aa    aaC   NULL  NULL /  WHERE / b condition

H8    bb    bb    NULL  NULL  NULL

, но MySQL выдает эту ошибку: #1054 - Unknown column 'st.sta' in 'on clause'.

Я пытался решить эту проблему безуспешно, пока кто-то не опубликовал (и не удалил)хорошая идея присоединиться к столбцу rn дважды.Благодаря ему я смог создать рабочее решение:

SELECT st.*, pr.*, rn.*, rn2.*

FROM         st
INNER JOIN   pr         ON st.pg = pr.pg
LEFT  JOIN   rn         ON st.sta = rn.sta
LEFT  JOIN   rn AS rn2  ON pr.rou = rn2.rou -- the two rn's join order is important
                       AND rn.id  = rn2.id  -- if first exists, second must match or null, first null => second null
WHERE ( rn.id = rn2.id )                    -- a: both not null
   OR ( pr.rou ='aaC' AND rn.id IS NULL)    -- b: no joinable rn found: choose by predefined pr.rou value
   OR ( pr.rou IS NULL )                    -- c: no need to join

Пока этот запрос работает, для него требуются дубликаты соединений в правильном порядке, очень хрупкие и уродливые.

Можете ли вы дать более чистое решение, которое присоединяется к таблице rn только один раз?

Вот пример базы данных в sql для копирования, если вы хотите поиграть с ним:

DROP    TABLE IF     EXISTS st;
CREATE  TABLE IF NOT EXISTS st (
  id  int  AUTO_INCREMENT,
  sta varchar(9),
  pg  varchar(9),
  PRIMARY KEY ( id )
)  AUTO_INCREMENT=1;

DROP    TABLE IF     EXISTS pr;
CREATE  TABLE IF NOT EXISTS pr (
  id  int  AUTO_INCREMENT,
  pg  varchar(9),
  rou varchar(9),
  PRIMARY KEY ( id )
)  AUTO_INCREMENT=1;

DROP    TABLE IF     EXISTS rn;
CREATE  TABLE IF NOT EXISTS rn (
  id  int  AUTO_INCREMENT,
  sta varchar(9),
  rou varchar(9),
  PRIMARY KEY ( id )
)  AUTO_INCREMENT=1;


INSERT INTO st 
(sta , pg ) VALUES
('H1','aa'),
('H2','aa'),
('H3','aa'),
('H4','aa'),
('H5','aa'),
('H6','aa'),
('H7','aa'),
('H8','bb');
INSERT INTO pr
( pg , rou ) VALUES
('aa','aaA'),
('aa','aaB'),
('aa','aaC'),
('bb', NULL);
INSERT INTO rn
(sta , rou ) VALUES
('H1','aaA'),
('H2','aaB'),
('H3','aaB'),
('H4','aaC'),
('H5','aaC'),
('H6','aaC');

Ответы [ 5 ]

11 голосов
/ 07 декабря 2011

Мне кажется, я наконец-то понял:

SELECT st.*, pr.*, rn.*
FROM st
  LEFT JOIN rn ON st.sta = rn.sta
  LEFT JOIN pr ON st.pg  = pr.pg
              AND (rn.rou = pr.rou OR rn.rou IS NULL)
2 голосов
/ 04 декабря 2011
select st.*, pr.*, rn.*  
from st
left join  pr on pr.pg = st.pg
left  join   rn  on rn.sta = st.sta
1 голос
/ 08 декабря 2011

Этот запрос на 100% верный ...

Проверьте его .....

Select st.sta,st.pg,pr.pg,pr.rou,rn.sta,rn.rou from st
    Left join pr 
                     On pr.pg=st.pg
    Left join rn 
                     On rn.sta=st.sta

ваш результат получит эти запросы ...

ЕслиЕсли есть сомнения, ответьте как можно скорее.

1 голос
/ 07 декабря 2011

Я проверил это быстро, и оказалось, что оно работает. Я переименовал столбцы, чтобы показать контекст того, что они должны представлять, чтобы соответствовать ожидаемым результатам.

SELECT 
      st.sta,
      st.pg,
      MIN( COALESCE( prByRN.pg, pr.pg )) prpg,
      MIN( COALESCE( prByRN.rou, pr.rou )) prrou,
      MIN( rn.sta ) rnsta,
      MIN( rn.rou ) rnrou
   from
      st
         left join rn
            ON st.sta = rn.sta 
            LEFT JOIN pr prByrn
               ON rn.rou = prByrn.rou
         LEFT JOIN pr
            ON st.pg = pr.pg
   GROUP BY 
      st.sta,
      st.pg
0 голосов
/ 05 декабря 2011
SELECT st.*, pr.*, rn.*
FROM 
    st
  LEFT  JOIN 
      ( pr                          --- the parenthesis are
      LEFT  JOIN 
        rn 
          ON  pr.rou = rn.rou
      )                             --- there for clarity
    ON  rn.sta = st.sta 
    AND pr.pg =  st.pg
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...