Разделить столбец на два столбца на основе кода типа в третьем столбце

#sql #oracle11g

#sql #oracle11g

Вопрос:

Мой SQL очень ржавый. Я пытаюсь преобразовать эту таблицу:

  ---- ----- -------------- ------- 
| ID | SIN |   CONTACT    | TYPE  |
 ---- ----- -------------- ------- 
|  1 | 737 | b@bacon.com  | email |
|  2 | 760 | 250-555-0100 | phone |
|  3 | 737 | 250-555-0101 | phone |
|  4 | 800 | 250-555-0102 | phone |
|  5 | 850 | l@lemon.com  | email |
 ---- ----- -------------- ------- 
  

В эту таблицу:

  ---- ----- -------------- ------------- 
| ID | SIN |    PHONE     |    EMAIL    |
 ---- ----- -------------- ------------- 
|  1 | 737 | 250-555-0101 | b@bacon.com |
|  2 | 760 | 250-555-0100 |             |
|  4 | 800 | 250-555-0102 |             |
|  5 | 850 |              | l@lemon.com |
 ---- ----- -------------- ------------- 
  

Я написал этот запрос:

 SELECT *
  FROM (SELECT *
          FROM people
         WHERE TYPE = 'phone') phoneNumbers
       FULL JOIN (SELECT *
                    FROM people
                   WHERE TYPE = 'email') emailAddresses
          ON phoneNumbers.SIN = emailAddresses.SIN;
  

Который выдает:

  ---- ----- -------------- ------- ------ ------- ------------- -------- 
| ID | SIN |   CONTACT    | TYPE  | ID_1 | SIN_1 |  CONTACT_1  | TYPE_1 |
 ---- ----- -------------- ------- ------ ------- ------------- -------- 
|  2 | 760 | 250-555-0100 | phone |      |       |             |        |
|  3 | 737 | 250-555-0101 | phone |    1 |   737 | b@bacon.com | email  |
|  4 | 800 | 250-555-0102 | phone |      |       |             |        |
|    |     |              |       |    5 |   850 | l@lemon.com | email  |
 ---- ----- -------------- ------- ------ ------- ------------- -------- 
  

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

Как я могу создать свою целевую таблицу (ID, SIN, PHONE, EMAIL)?

Редактирование и уточнение: я благодарен за ответы, которые я получил до сих пор, но, как новичок в SQL, я не знаком с методами, которые вы используете (операторы case, условная агрегация и поворот). Это нельзя сделать с помощью JOIN и SELECT? Пожалуйста, извините мое невежество в этом вопросе. (Дело не в том, что меня не интересуют превосходные методы, но я не хочу двигаться слишком быстро слишком рано.)

Комментарии:

1. Я некоторое время возился с этим, и единственной другой вещью, которая могла бы работать для этого, было бы несколько объединений, и это может даже не подходить для этого сценария. Ваш самый простой вариант — использовать CASE , который является просто циклом IF для SQL.

Ответ №1:

Один из способов приблизиться к этому — условная агрегация:

 select min(ID), SIN, 
       max(case when type = 'phone' then contact end) as phone,
       max(case when type = 'email' then contact end) as email
from people t
group by sin;
  

Ответ №2:

Кажется, сводный (oracle.com ) здесь было бы легко работать.

 SELECT ID, SIN, PHONE, EMAIL
FROM PEOPLE
PIVOT (
    MAX(CONTACT)
    FOR TYPE IN ('EMAIL', 'PHONE')
)
  

Ответ №3:

Я понимаю, что это менее элегантно, чем все опубликованные решения, но здесь это так или иначе, решение, использующее только JOIN и SELECT:

 SELECT sins.SIN, phone, email
  FROM ((SELECT SIN email_sin, contact email
           FROM people
          WHERE TYPE = 'email') email
        FULL JOIN (SELECT SIN phone_sin, contact phone
                     FROM people
                    WHERE TYPE = 'phone') phone
           ON email.email_sin = phone.phone_sin)
       RIGHT JOIN (SELECT DISTINCT SIN FROM people) sins
          ON sins.SIN = phone_sin OR sins.SIN = email_sin;
  

Здесь отсутствует столбец ID.