2015-09-06 6 views
0

Скажем, у меня есть таблица 1 с:Карта 2 столбца на 2 строки в 1 колонке?

stuff | sender_id | recipient_id 

и у меня есть таблица 2 с:

id | name 

Я хочу вернуться:

stuff | sender_name | recipient_name

или

stuff | sender_id | sender_name | recipient_id | recipient_name

Прямо сейчас я смотрю на что-то вроде: SELECT * FROM table1 INNER JOIN table2 ON id=sender_id OR id=recipient_id, но это возвращает дубликаты материала в виде строки, заполняющей оба условных выражения.

Есть ли способ получить информацию, которую я хочу получить в 1 запросе?

+0

Для которого RDBMS это ?Пожалуйста, добавьте соответствующий тег - спасибо –

+1

Вам нужно будет сделать два соединения, так как вы хотите получить два разных результата оттуда –

ответ

1

Способ заключается в использовании внутренней выборки на так:

SELECT stuff, sender_id 
    , (SELECT name FROM table2 WHERE id = sender_id) AS sender_name 
    , recipient_id 
    , (SELECT name FROM table2 WHERE id = recipient_id) AS recipient_name 
FROM table1; 
0

А другой способ используют двойное соединение.

SELECT 
     t1.stuff, 
     tA.id sender_id, 
     tA.name sender_name, 
     tB.id recipient_id, 
     tB.name recipient_name 
FROM 
    table1 t1 
inner join table2 tA 
    on t1.sender_id = tA.id 
inner join table2 tB 
    on t1.sender_id = tB.id 

Было бы интересно сравнить как запрос с использованием explain или analyze

1

Решение с одной ссылкой на table2:

select t1.stuff 
    , max(case when t1.sender_id = t2.id then t2.name end) as sender_name 
    , max(case when t1.recipient_id = t2.id then t2.name end) as recipint_name 
from t1 
join t2 
    on t2.id in (t1.sender_id, t1.recipient_id) 
group by t1.stuff; 

Это немного грязный, но бывают ситуации, когда это будет удобно ,

я создал таблицы и засунул их с 10000 строк каждый (DB2 Express-C, 10,5 FixPak 1):

db2 "create table t1 (stuff int not null primary key, sender_id int not null, recipient_id int not null)" 
db2 "create table t2 (id int not null primary key, name varchar(10) not null); 
db2 "insert into t1 with t (n) as (values 0 union all select n+1 from t where n+1 < 10000) select n, 2*n, 2*n+1 from t" 
db2 "insert into t2 with t (n) as (values 0 union all select n+1 from t where n+1 < 10000) select 2*n, 'C' || rtrim(cast(2*n as char(10))) from t" 
db2 runstats on table t1 with distribution and sampled detailed indexes all 
db2 runstats on table t2 with distribution and sampled detailed indexes all 

и проверил план для различных запросов. Я добавил, где положение

Два суб-выбирает:

db2 "explain plan for SELECT stuff    , (SELECT name FROM t2 WHERE id = sender_id) AS sender_name, (SELECT name FROM t2 WHERE id = recipient_id) AS recipient_name FROM t1 where t1.id between 500 and 600" 
db2exfmt -d sample -g -1 -o sub.exfmt 

Два присоединяется:

db2 "explain plan for SELECT t1.stuff, tA.name as sender_name, tB.name as recipient_name from t1 join t2 as tA on t1.sender_id = tA.id join t2 as tB on t1.sender_id = tB.id where t1.stuff between 500 and 600" 
db2exfmt -d sample -g -1 -o dualjoin.exfmt 

и, наконец, вариант с агрегатами и случай:

db2 "explain plan for SELECT t1.stuff, max(case when t1.sender_id = t2.id then t2.name end) as sender_name, max(case when t1.recipient_id = t2.id then t2.name end) as recipint_name from t1 join t2 on t2.id in (t1.sender_id, t1.recipient_id) group by t1.stuff" 
db2exfmt -d sample -g -1 -o singlejoin.exfmt 

В соответствии с этим довольно ненаучный тест, решение @Juan Carlos Oropeza является самым дешевым:

Access Plan: 
----------- 
     Total Cost:    132.657 
     Query Degree:   1 

         Rows 
         RETURN 
         ( 1) 
         Cost 
         I/O 
         | 
         101.808 
         ^NLJOIN 
         ( 2) 
         132.657 
         53 
       /-------+--------\ 
      101.808     1 
      TBSCAN    FETCH 
      ( 3)    ( 7) 
      13.6735    13.6215 
       2     2 
       |    /---+----\ 
      101.808   1   10000 
      SORT   IXSCAN TABLE: LELLE 
      ( 4)   ( 8)   T2 
      13.6733  6.81423  Q1 
       2    1 
       |    | 
      101.808   10000 
      FETCH  INDEX: SYSIBM 
      ( 5) SQL150906110744470 
      13.6625   Q1 
       2 
      /---+----\ 
     101.808  10000 
     IXSCAN TABLE: LELLE 
     ( 6)   T1 
     6.84113  Q2 
      1 
     | 
     10000 
    INDEX: SYSIBM 
SQL150906110646160 
     Q2 

Использование двух суб-выбирает, как в @ shA.t будет немного дороже:

Access Plan: 
----------- 
     Total Cost:    251.679 
     Query Degree:   1 

            Rows 
           RETURN 
           ( 1) 
            Cost 
            I/O 
            | 
           101.808 
           >^NLJOIN 
           ( 2) 
           251.679 
           103.99 
          /-------+--------\ 
         101.808     1 
         TBSCAN    FETCH 
         ( 3)    ( 12) 
         132.695    13.6215 
         52.9898     2 
         |    /---+----\ 
         101.808   1   10000 
         SORT   IXSCAN TABLE: LELLE 
         ( 4)   ( 13)   T2 
         132.691  6.81423  Q1 
         52.9898   1 
         |    | 
         101.808   10000 
         >^NLJOIN INDEX: SYSIBM 
         ( 5) SQL150906110744470 
         132.67   Q1 
         52.9898 
       /-------+--------\ 
      101.808     1 
      TBSCAN    FETCH 
      ( 6)    ( 10) 
      13.6881    13.6215 
       2     2 
       |    /---+----\ 
      101.808   1   10000 
      SORT   IXSCAN TABLE: LELLE 
      ( 7)   ( 11)   T2 
      13.6839  6.81423  Q2 
       2    1 
       |    | 
      101.808   10000 
      FETCH  INDEX: SYSIBM 
      ( 8) SQL150906110744470 
      13.6625   Q2 
       2 
      /---+----\ 
     101.808  10000 
     IXSCAN TABLE: LELLE 
     ( 9)   T1 
     6.84113  Q3 
      1 
     | 
     10000 
    INDEX: SYSIBM 
SQL150906110646160 
     Q3 

Мои решения является самым дорогим:

Access Plan: 
----------- 
     Total Cost:    758.822 
     Query Degree:   1 

          Rows 
          RETURN 
          ( 1) 
          Cost 
          I/O 
          | 
          10000 
          GRPBY 
          ( 2) 
          758.139 
          124.996 
          | 
          20000 
          NLJOIN 
          ( 3) 
          756.923 
          124.996 
       /----------+----------\ 
       10000      2 
      FETCH      FETCH 
      ( 4)     ( 6) 
      122.351     27.0171 
       49      3.96667 
      /---+----\    /---+----\ 
     10000  10000   2   10000 
     IXSCAN TABLE: LELLE  RIDSCN TABLE: LELLE 
     ( 5)   T1   ( 7)   T2 
     58.1551  Q2   13.6291  Q1 
     21       2 
     |     /-------+-------\ 
     10000   1.0016    1.0016 
    INDEX: SYSIBM  SORT    SORT 
SQL150906110646160 ( 8)    ( 10) 
     Q2   6.81465    6.81465 
          1     1 
         |     | 
         1.0016    1.0016 
         IXSCAN    IXSCAN 
         ( 9)    ( 11) 
         6.81423    6.81423 
          1     1 
         |     | 
         10000    10000 
        INDEX: SYSIBM  INDEX: SYSIBM 
       SQL150906110744470 SQL150906110744470 
         Q1     Q1 
+0

двойное внутреннее соединение FTW. Хорошая работа с тестом. –

Смежные вопросы