2016-03-26 1 views
3

Est-il possible de faire un 1 sur 1 concaténation tableau élément si j'ai une requête comme ceci:éléments du tableau Concaténer sur une table jointe PostgreSQL

EDIT: Les tableaux ont pas toujours le même nombre d'éléments. pourrait être que array1 a parfois 4 éléments et array2 8 éléments.

drop table if exists a; 
drop table if exists b; 
create temporary table a as (select 1 as id,array['a','b','c'] as array1); 
create temporary table b as (select 1 as id,array['x','y','z'] as array2); 

select 
a.id, 
a.array1, 
b.array2, 
array_concat--This has to be a 1 to 1 ordered concatenation (see     
      --example below) 
from a 
left join b on b.id=a.id 

Ce que je voudrais obtenir ici est une concaténation paire des deux tableaux 1 et 2, comme ceci:

id  array11   array2   array_concat 
1 ['a','b','c'] ['d','e','f'] ['a-d','b-e','c-f'] 
2 ['x','y','z'] ['i','j','k'] ['x-i','y-j','z-k'] 
3 ... 

J'ai essayé d'utiliser unnest mais je ne peux pas le faire fonctionner:

select 
    a.id, 
    a.array1, 
    b.array2, 
    array_concat 
    from table a 
    left join b on b.id=a.id 
    left join (select a.array1,b.array2, array_agg(a1||b2) 
         FROM unnest(a.array1, b.array2) 
          ab (a1, b2) 
      ) ag on ag.array1=a.array1 and ag.array2=b.array2 
; 

EDIT:

Cela fonctionne pour une seule table:

SELECT array_agg(el1||el2) 
FROM unnest(ARRAY['a','b','c'], ARRAY['d','e','f']) el (el1, el2); 

++ Merci à https://stackoverflow.com/users/1463595/%D0%9D%D0%9B%D0%9E

EDIT:

Je suis venu à une solution très proche, mais il mêle quelques-unes des valeurs intermédiaires une fois que la concaténation entre des réseaux se fait, jamais moins j'ai encore besoin d'une solution parfaite ...

L'approche que j'utilise maintenant est:

1) Création d'une table sur la base 2 les différents 2) agrégeant en utilisant latérale:

create temporary table new_table as 
SELECT 
    id, 
    a.a, 
    b.b 
    FROM a a 
    LEFT JOIN b b on a.id=b.id; 

SELECT id, 
     ab_unified 
     FROM pair_sources_mediums_campaigns, 
     LATERAL (SELECT ARRAY_AGG(a||'[-]'||b order by grp1) as ab_unified 
       FROM (SELECT DISTINCT case when a null 
            then 'not tracked' 
            else a 
            end as a 
         ,case when b is null 
            then 'none' 
            else b 
            end as b 
          ,rn - ROW_NUMBER() OVER(PARTITION BY a,b ORDER BY rn) AS grp1 

        FROM unnest(a,b) with ordinality as el (a,b,rn) 
       ) AS sub 
      ) AS lat1 
      order by 1; 
+0

Side note: JSON correcte est avec '" 'pas' ' ' – maraca

+0

Dans PostgreSQL, vous pouvez également définir la chaîne. contenant des tableaux comme: select array ['a', 'b', 'c'] comme array1; – johan855

Répondre

1

Quelque chose comme ça .

with a_elements (id, element, idx) as (
    select a.id, 
     u.element, 
     u.idx 
    from a 
    cross join lateral unnest(a.array1) with ordinality as u(element, idx) 
), b_elements (id, element, idx) as (
    select b.id, 
     u.element, 
     u.idx 
    from b 
    cross join lateral unnest(b.array2) with ordinality as u(element, idx) 
) 
select id, 
     array_agg(concat_ws('-', a.element, b.element) order by idx) as elements 
from a_elements a 
    full outer join b_elements b using (id, idx) 
group by coalesce(a.id, b.id); 

L'opérateur de jointure using (..) prendra automatiquement la valeur non nulle des tables jointes. Cela supprime le besoin d'utiliser par ex. coalesce(a.id, b.id) .n

Ce n'est pas joli et certainement pas efficace pour les grandes tables, mais semble faire tout ce que vous voulez.

Pour les tableaux qui n'ont pas la même quantité d'éléments, le résultat n'aura que l'élément de l'un des tableaux.

Pour cet ensemble de données:

insert into a 
    (id, array1) 
values 
    (1, array['a','b','c','d']), 
    (2, array['d','e','f']); 

insert into b 
    (id, array2) 
values 
    (1, array['x','y','z']), 
    (2, array['m','n','o','p']); 

Il renvoie ce résultat:

id | elements  
---+---------------- 
1 | {a-x,b-y,c-z,d} 
2 | {d-m,e-n,f-o,p} 
+0

fonctionne très bien, merci! – johan855

0

Je pense que vous pensiez trop loin, essayer (SQLFiddle):

select 
    a.id, 
    a.array1, 
    b.array2, 
    array[a.array1[1] || '-' || b.array2[1], 
     a.array1[2] || '-' || b.array2[2], 
     a.array1[3] || '-' || b.array2[3]] array_concat 
from 
    a inner join 
    b on b.id = a.id 
; 
+0

J'ai édité la question, Le problème est que je n'ai pas toujours la même quantité d'éléments dans chaque tableau. – johan855

+0

Voulez-vous joindre uniquement les tableaux avec une quantité égale d'éléments? C'est moche, mais vous pourriez faire ce qui précède pour 4 et 8 éléments avec un cas quand. – maraca

+0

Si c'est ['a', 'b', 'c', 'd'] avec ['x', 'y', 'z'] le résultat devrait être ['a-x', 'b-y ',' c-z ',' d- '] ou [' a-x ',' b-y ',' c-z ',' d-null ']] – johan855