2016-05-10 3 views
1

У меня есть таблица, которая что-то вроде нижеSQL, как объединить записи Oracle

Key CL EmailAddress CT Product1 Product2 Product3 Product4 Product5 
1 X [email protected] A 12   null  null  null  null 
2 X [email protected] B 123   22   null  null  null 

Для каждой строки я могу иметь максимум 5 продуктов. Каждая запись будет иметь минимум 1, но менее 5 продуктов.

Также адрес электронной почты может повторяться через один и тот же CL.

Я бы написать запрос, чтобы найти, если адрес электронной почты, повторяется через тот же CL и если он делает

Я бы объединить productids на тот же адрес электронной почты.

При выполнении слияния, если у меня есть 5 продуктов, мне нужно остановить и исключить остальные продукты.

Таким образом, выход для приведенного выше примера должен выглядеть примерно так

Key CL EmailAddress CT Product1 Product2 Product3 Product4 Product5 
1 X [email protected] gmail.com A+B 12   123   22   null  null 

Можем ли мы сделать что-то вроде этого в запросе Oracle SQL?

+0

выход не имеет никакого смысла. Я не вижу в этом никакой логики. –

+0

Логика вашего нужного результата не ясна. Пожалуйста, объясните, какова должна быть идея такого результата; для чего вы groupin? mail и CL? Key = 1, потому что это минимальное значение? почему product1 = 12, product2 = 123 и product3 = 22? – Aleksej

ответ

3

В качестве альтернативы провер МТО в тренер, вы могли бы UNPIVOT данных из таблицы:

select * 
from your_table 
unpivot (product for pos in (product1 as 1, product2 as 2, product3 as 3, 
    product4 as 4, product5 as 5)); 

     KEY CL EMAILADDRESS CT   POS PRODUCT 
---------- -- ------------- --- ---------- ---------- 
     1 X [email protected] A   1   12 
     2 X [email protected] B   1  123 
     2 X [email protected] B   2   22 

использовать, чтобы подобрать ключ и генерировать значение CT (бесстыдно зажимая регулярное выражение МТА для удаления дубликатов), и генерация нового значения позиции:

with t as (
    select * 
    from your_table 
    unpivot (product for pos in (product1 as 1, product2 as 2, product3 as 3, 
    product4 as 4, product5 as 5)) 
) 
select min(key) over (partition by cl, emailaddress) as key, 
    cl, 
    emailaddress, 
    regexp_replace(
    listagg(ct, '+') within group (order by key) over (partition by cl, emailaddress), 
    '(.)(\+\1)+', '\1') as ct, 
    rank() over (partition by cl, emailaddress order by key, pos) as pos, 
    product 
from t; 

     KEY CL EMAILADDRESS CT   POS PRODUCT 
---------- -- ------------- --- ---------- ---------- 
     1 X [email protected] A+B   1   12 
     1 X [email protected] A+B   2  123 
     1 X [email protected] A+B   3   22 

И, наконец, повернуть его обратно:

with t as (
    select * 
    from your_table 
    unpivot (product for pos in (product1 as 1, product2 as 2, product3 as 3, 
    product4 as 4, product5 as 5)) 
) 
select key, cl, emailaddress, ct, a_product as product1, b_product as product2, 
    c_product as product3, d_product as product4, e_product as product5 
from (
    select min(key) over (partition by cl, emailaddress) as key, 
    cl, 
    emailaddress, 
    regexp_replace(
     listagg(ct, '+') within group (order by key) over (partition by cl, emailaddress), 
     '(.)(\+\1)+', '\1') as ct, 
    rank() over (partition by cl, emailaddress order by key, pos) as pos, 
    product 
    from t 
) 
pivot (max(product) as product for (pos) in (1 as a, 2 as b, 3 as c, 4 as d, 5 as e)); 

     KEY CL EMAILADDRESS CT PRODUCT1 PRODUCT2 PRODUCT3 PRODUCT4 PRODUCT5 
---------- -- ------------- --- ---------- ---------- ---------- ---------- ---------- 
     1 X [email protected] A+B   12  123   22      

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

3

Oracle Setup

CREATE TABLE table_name (
    "Key"  INT PRIMARY KEY, 
    CL   CHAR(1), 
    EmailAddress VARCHAR2(100), 
    CT   VARCHAR2(100), 
    Product1  INT, 
    Product2  INT, 
    Product3  INT, 
    Product4  INT, 
    Product5  INT 
); 

INSERT INTO table_name 
SELECT 1, 'X', '[email protected]', 'A', 12, null, null, null, null FROM DUAL 
UNION ALL 
SELECT 2, 'X', '[email protected]', 'B', 123, 22, null, null, null FROM DUAL; 

CREATE TYPE stringlist AS TABLE OF VARCHAR2(100); 
/

CREATE OR REPLACE FUNCTION nth_item(
    collection STRINGLIST, 
    n   INT 
) RETURN VARCHAR2 DETERMINISTIC 
AS 
BEGIN 
    IF collection IS NULL OR n < 1 OR n > collection.COUNT THEN 
    RETURN NULL; 
    END IF; 
    RETURN collection(n); 
END; 
/

Запрос:

SELECT "Key", 
     CL, 
     EmailAddress, 
     CT, 
     Nth_Item(products, 1) AS Product1, 
     Nth_Item(products, 2) AS Product2, 
     Nth_Item(products, 3) AS Product3, 
     Nth_Item(products, 4) AS Product4, 
     Nth_Item(products, 5) AS Product5 
FROM (
    SELECT MIN("Key") AS "Key", 
     CL, 
     EmailAddress, 
     REGEXP_REPLACE(
      LISTAGG(CT, '+') WITHIN GROUP (ORDER BY CT), 
      '(.)(\+\1)+', 
      '\1' 
     ) AS CT, 
     CAST(COLLECT(COLUMN_VALUE) AS stringlist) AS products 
    FROM table_name t, 
     TABLE(
      STRINGLIST(
      t.Product1, 
      t.Product2, 
      t.Product3, 
      t.Product4, 
      t.Product5 
      ) 
     ) 
    WHERE COLUMN_VALUE IS NOT NULL 
    GROUP BY CL, EmailAddress 
); 

Выход:

Key CL EMAILADDRESS CT PRODUCT1 PRODUCT2 PRODUCT3 PRODUCT4 PRODUCT5 
--- -- ------------- --- -------- -------- -------- -------- -------- 
    1 X [email protected] A+B  12  22  123 
2

Другой вариант:

with test_data(Key1, CL, EmailAddress, CT, Product1, Product2, Product3, Product4, Product5) 
as (
select 1, 'X', '[email protected]', 'A', 12 , null, null, null, null from DUAL union all 
select 2, 'X', '[email protected]', 'B', 12 , 123, null, null, null from DUAL 
) 

select 
    min(KEY1) as KEY1, 
    CL, 
    EmailAddress, 
    case when instr(min(CT1), '+', 1, 5) = 0 
     then min(CT1) 
     else substr(min(CT1), 1, instr(min(CT1), '+', 1, 5)-1) 
    end CT, 
    max(PRODUCT1) PRODUCT1, 
    max(PRODUCT2) PRODUCT2, 
    max(PRODUCT3) PRODUCT3, 
    max(PRODUCT4) PRODUCT4, 
    max(PRODUCT5) PRODUCT5 
from 
(
    select * from 
    (
     select t.*, 
     row_number() over (partition by CL,EmailAddress order by key1) RN 
     FROM 
     (
     select * from 
     ( 
      select temp.*, 
        listagg(CT,'+') within group (order by key1) over (partition by CL, EmailAddress) CT1 
      from test_data temp 
     ) 
     unpivot 
     (prod FOR col in (PRODUCT1,PRODUCT2,PRODUCT3,PRODUCT4,PRODUCT5)) 
     order by KEY1 
    ) t 
    ) t1 
    where RN <=5 
) 
    pivot 
    (
    min(prod) 
    for RN in (1 as PRODUCT1,2 as PRODUCT2,3 as PRODUCT3,4 as PRODUCT4,5 as PRODUCT5) 
)  
group by CL, EmailAddress 
;