Преобразуйте эту таблицу. С чем-то вроде «Coalasce» для «Group by»? - PullRequest
0 голосов
/ 22 июля 2011

Скажите, что у меня есть следующая таблица (id_a, id_b, type на самом деле целые числа, данные на самом деле xml):

id_a   id_b    type     data
-----+------+--------+--------
  1     1       X        X1
  1     1       Y        Y1
  7    17       Y        Y2
  7    99       X        X2
  9    20       Z        Z1

Сочетание id_a, id_b и type уникально.Теперь программа, которую я пишу, получает в качестве входных данных список типов, которые мне нужны.Предположим, что этот список содержит X и Y. Теперь я хочу сделать несколько SQL-Magic, которые в итоге приведут к следующему результату:

id_a   id_b      X        Y
-----+------+--------+--------
  1      1      X1        Y1
  7      17     NULL      Y2
  7      99     X2        NULL

Другими словами: я хочу строку, которая содержит все данные для id_a и id_b, перечисляя данные в столбцах.

Мне удалось самостоятельно найти запрос, который заканчивается следующей таблицей:

table:
id_a   id_b   data_x   data_y
-----+------+--------+--------
  1     1       X1      NULL
  1     1       NULL       Y1
  7    17       NULL       Y2
  7    99       X2       NULL

Запрос:

select
  id_a,
  id_b,
  case when type = 'X' then data
  end data_x,
  case when type = 'Y' then data
  end data_y,
from
  mytable
order by
  id_a,id_b

В этой таблице гарантируется, что

  • Максимум один из data_x или data_y может быть не NULL (оба NULL тоже в порядке, но это, конечно, может быть легко отфильтровано с помощью where data_x is not null or data_y is not null)
  • data_x и data_y уникальны для комбинации id_a и id_b.

И если бы я мог теперь сделать select coalesce(case ... data_y),coalesce(case ... data_y) from ... group by id_a,id_b, то я бы сказал, что я был бы там, где я хочуда, но, к сожалению, coalesce - это не агрегатная функция, а скалярная функция.

В моем клиентском приложении (написанном на Java) я, конечно, могу перебирать строки, объединяя строки, но это выглядит не очень элегантно;-).Есть ли "симпатичный" способ решить эту проблему?

Я использую DB2 V9.7, но я бы предпочел портативное решение ...

Ответы [ 3 ]

2 голосов
/ 22 июля 2011

Использовать MAX?

SELECT
  id_a,
  id_b,
  MAX(CASE WHEN type = 'X' THEN data END) AS data_x,
  MAX(CASE WHEN type = 'Y' THEN data END) AS data_y
FROM
  myTable
GROUP BY
  id_a,
  id_b

EDIT

Если вы не можете использовать агрегатные функции, соответствует ли что-то подобное вашим потребностям?

SELECT
  map.id_a,
  map.id_b,
  myTableX.data AS data_x,
  myTableY.data AS data_y
FROM
  (SELECT id_a, id_b FROM myTable GROUP BY id_a, id_b) AS map
LEFT JOIN
  myTable AS myTableX
    ON  myTalbeX.id_a = map.id_a
    AND myTableX.id_b = map.id_b
    AND myTableX.type = 'X'
LEFT JOIN
  myTable AS myTableY
    ON  myTalbeY.id_a = map.id_a
    AND myTableY.id_b = map.id_b
    AND myTableY.type = 'Y'
1 голос
/ 22 июля 2011

Это дает желаемый результат:

create table myTable (
    id_a int not null,
    id_b int not null,
    type char(1) not null,
    data varchar(10),
    unique (id_a, id_b, type)
);

insert into myTable values (1, 1, 'X', 'X1');
insert into myTable values (1, 1, 'Y', 'Y1');
insert into myTable values (7, 17, 'Y', 'Y2');
insert into myTable values (7, 99, 'X', 'X2');
insert into myTable values (9, 20, 'Z', 'Z1');

select coalesce(X.id_a, Y.id_a) as id_a, coalesce(X.id_b, Y.id_b) as id_b, 
        X.data as X, Y.data as Y
    from (select * from myTable where type = 'X') X 
        full outer join (select * from myTable Y where type = 'Y') Y 
            on X.id_a = Y.id_a and X.id_b = Y.id_b

результат

 ID_A ID_B X    Y
 ---- ---- ---- ----
    1    1 X1   Y1
    7   17 NULL Y2
    7   99 X2   NULL
0 голосов
/ 22 июля 2011

Вам все еще нужно что-то сделать, чтобы привести данные, которые появляются в разных записях, в одну и ту же запись набора результатов. Для этого вам нужно использовать агрегатную функцию, например, Макс, мин У меня нет доступа к DB2, но во многих отношениях он очень похож на Oracle. Следующее прекрасно работает в Oracle.

with tmp as 
 (select 1 id_a, 1  id_b, 'X' type_, 'X1' data_ from dual union
  select 1 id_a, 1  id_b, 'Y' type_, 'Y1' data_ from dual union
  select 7 id_a, 17 id_b, 'Y' type_, 'Y2' data_ from dual union
  select 7 id_a, 99 id_b, 'X' type_, 'X2' data_ from dual union
  select 9 id_a, 20 id_b, 'Z' type_, 'Z1' data_ from dual)
select distinct 
       id_a, 
       id_b,
       max(decode(type_, 'X', data_, null)) data_x,
       max(decode(type_, 'Y', data_, null)) data_y  
  from tmp  
 group by id_a, id_b  

EDIT: Для неагрегированной версии вы можете использовать это:

    with tmp as 
     (select 1 id_a, 1  id_b, 'X' type_, 'X1' data_ from dual union
      select 1 id_a, 1  id_b, 'Y' type_, 'Y1' data_ from dual union
      select 7 id_a, 17 id_b, 'Y' type_, 'Y2' data_ from dual union
      select 7 id_a, 99 id_b, 'X' type_, 'X2' data_ from dual union
      select 9 id_a, 20 id_b, 'Z' type_, 'Z1' data_ from dual)
    select nvl(x.id_a, y.id_a) id_a, nvl(x.id_b, y.id_b) id_b, x.data_, y.data_ 
      from tmp x
           full outer join tmp y
             on (    x.id_a = y.id_a
                 and x.id_b = y.id_b
                 and x.type_ = 'X'
                 and y.type_ = 'Y')
 where x.data_ like 'X%' or  y.data_ like 'Y%'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...