2013-08-07 1 views
4

données: {{1,"a"},{2,"b"},{3,"c"}}
souhaitee:Convertir un tableau multidimensionnel aux dossiers

foo | bar 
-----+------ 
    1 | a 
    2 | b 
    3 | c 

Vous pouvez obtenir le résultat escompté avec la requête suivante; Cependant, il serait préférable d'avoir quelque chose qui s'adapte à la taille de la matrice.

SELECT arr[subscript][1] as foo, arr[subscript][2] as bar 
FROM (select generate_subscripts(arr,1) as subscript, arr 
     from (select '{{1,"a"},{2,"b"},{3,"c"}}'::text[][] as arr) input 
    ) sub; 
+0

Il n'y a aucun moyen de changer dynamicly le nombre de colonnes renvoyées par requête SQL. –

+0

La seule chose que je voulais faire était d'ajouter 'tag:' à un titre, une édition que vous aviez annulée. Merci de ne pas mettre de tags dans les titres. De votre commentaire d'édition, il semble que vous cherchez cette recherche: http://stackoverflow.com/search?q=infavorites%3A183181+[postgres]. Vous pouvez également utiliser infavorites: mine comme raccourci. – Flexo

+0

@Flexo: vous êtes incroyable. Oui, c'est quelque chose que je ne connaissais pas et que j'aurais probablement pu utiliser il y a quelques années. Peut-être que je devrais fréquenter Meta plus souvent.Vous gagnez :) – vol7ron

Répondre

1

Vous ne savez pas exactement ce que vous voulez dire en disant "il vaudrait mieux avoir quelque chose qui évolue avec la taille du tableau". Bien sûr, vous ne pouvez pas ajouter de colonnes supplémentaires au resultset lorsque la taille du tableau interne augmente, car postgresql doit connaître les colonnes exactes d'une requête avant l'exécution de (donc avant qu'il ne commence à lire la chaîne).

Mais je voudrais proposer la conversion de la chaîne en une représentation relationnelle normale de la matrice:

select i, j, arr[i][j] a_i_j from (
select i, generate_subscripts(arr,2) as j, arr from (
    select generate_subscripts(arr,1) as i, arr 
    from (select ('{{1,"a",11},{2,"b",22},{3,"c",33},{4,"d",44}}'::text[][]) arr) input 
) sub_i 
) sub_j 

Ce qui donne:

i | j | a_i_j 
--+---+------ 
1 | 1 | 1 
1 | 2 | a 
1 | 3 | 11 
2 | 1 | 2 
2 | 2 | b 
2 | 3 | 22 
3 | 1 | 3 
3 | 2 | c 
3 | 3 | 33 
4 | 1 | 4 
4 | 2 | d 
4 | 3 | 44 

Un tel résultat peut être assez utile dans le traitement ultérieur des données, je pense.

Bien sûr, une telle requête ne peut gérer qu'un tableau avec un nombre prédéfini de dimensions, mais toutes les tailles de tableau pour toutes ses dimensions peuvent être modifiées sans réécrire la requête, donc c'est une approche un peu plus flexible.

ADDITION: Oui, en utilisant with recursive on peut construire une requête ressemblante, capable de gérer un tableau avec des dimensions arbitraires. Néanmoins, il n'y a aucun moyen de surmonter la limitation provenant du modèle de données relationnel - l'ensemble exact de colonnes doit être défini lors de l'analyse de la requête, et aucun moyen de retarder cela jusqu'à l'exécution. Donc, nous sommes obligés de stocker tous les indices dans une colonne, en utilisant un autre tableau.

Voici la requête qui extrait tous les éléments de tableau multidimensionnel arbitraire le long de leur base zéro indices (stockés dans un autre tableau à une dimension):

with recursive extract_index(k,idx,elem,arr,n) as (
select (row_number() over())-1 k, idx, elem, arr, n from (
    select array[]::bigint[] idx, unnest(arr) elem, arr, array_ndims(arr) n 
    from (select '{{{1,"a"},{11,111}},{{2,"b"},{22,222}},{{3,"c"},{33,333}},{{4,"d"},{44,444}}}'::text[] arr) input 
) plain_indexed 
union all 
select k/array_length(arr,n)::bigint k, array_prepend(k%array_length(arr,2),idx) idx, elem, arr, n-1 n 
from extract_index 
where n!=1 
) 
select array_prepend(k,idx) idx, elem from extract_index where n=1 

Ce qui donne:

idx  | elem 
--------+----- 
{0,0,0} | 1 
{0,0,1} | a 
{0,1,0} | 11 
{0,1,1} | 111 
{1,0,0} | 2 
{1,0,1} | b 
{1,1,0} | 22 
{1,1,1} | 222 
{2,0,0} | 3 
{2,0,1} | c 
{2,1,0} | 33 
{2,1,1} | 333 
{3,0,0} | 4 
{3,0,1} | d 
{3,1,0} | 44 
{3,1,1} | 444 

Formellement, cela semble prouver le concept, mais je me demande quel usage pratique on pourrait en faire :)

+0

Mas, je ne suis pas sûr que ce soit vrai. Je pense que je pourrais combiner une syntaxe 'WITH RECURSIVE' en regardant les dims et les limites supérieures du tableau .. et avoir quelque chose de plus dynamique. Cependant, lors des tests, j'ai remarqué qu'il est très lent de transformer une chaîne en tableau, en utilisant cette syntaxe (mais c'est à côté du point - c'est une preuve de concept) – vol7ron

+0

Oui, une telle solution existe, mais elle ne l'est pas semble en quelque sorte pratique. SQL est juste un outil inadéquat pour faire de telles choses non relationnelles, donc toute solution SQL est condamnée à être lente et peu claire. –

+0

Je vais vérifier cela avec SQLFiddle plus tard – vol7ron

1

Cela fonctionne:

select key as foo, value as bar 
from json_each_text(
    json_object('{{1,"a"},{2,"b"},{3,"c"}}') 
); 

Résultat:

foo | bar 
-----+------ 
    1 | a 
    2 | b 
    3 | c 

Docs

Questions connexes