web-dev-qa-db-fra.com

Convertir un tableau PostgreSQL en PHP tableau

J'ai du mal à lire les tableaux Postgresql en PHP. J'ai essayé explode (), mais cela casse les tableaux contenant des virgules dans strings et str_getcsv (), mais c'est aussi inutile, car PostgreSQL ne cite pas les chaînes japonaises.

Ne fonctionne pas:

explode(',', trim($pgArray['key'], '{}'));
str_getcsv( trim($pgArray['key'], '{}') );

Exemple:

// print_r() on PostgreSQL returned data: Array ( [strings] => {または, "some string without a comma", "a string, with a comma"} )

// Output: Array ( [0] => または [1] => "some string without a comma" [2] => "a string [3] => with a comma" ) 
explode(',', trim($pgArray['strings'], '{}'));

// Output: Array ( [0] => [1] => some string without a comma [2] => a string, with a comma ) 
print_r(str_getcsv( trim($pgArray['strings'], '{}') ));
29
EarthMind

Si vous avez PostgreSQL 9.2, vous pouvez faire quelque chose comme ceci:

SELECT array_to_json(pg_array_result) AS new_name FROM tbl1;

Le résultat retournera le tableau en JSON

Puis sur le côté php:

$array = json_decode($returned_field);

Vous pouvez également reconvertir. Voici les Fonctions JSON page

68
michaelbn

Comme aucune de ces solutions ne fonctionne avec tableaux multidimensionnels , je vous propose ici ma solution récursive qui fonctionne avec des tableaux de toute complexité :

function pg_array_parse($s, $start = 0, &$end = null)
{
    if (empty($s) || $s[0] != '{') return null;
    $return = array();
    $string = false;
    $quote='';
    $len = strlen($s);
    $v = '';
    for ($i = $start + 1; $i < $len; $i++) {
        $ch = $s[$i];

        if (!$string && $ch == '}') {
            if ($v !== '' || !empty($return)) {
                $return[] = $v;
            }
            $end = $i;
            break;
        } elseif (!$string && $ch == '{') {
            $v = pg_array_parse($s, $i, $i);
        } elseif (!$string && $ch == ','){
            $return[] = $v;
            $v = '';
        } elseif (!$string && ($ch == '"' || $ch == "'")) {
            $string = true;
            $quote = $ch;
        } elseif ($string && $ch == $quote && $s[$i - 1] == "\\") {
            $v = substr($v, 0, -1) . $ch;
        } elseif ($string && $ch == $quote && $s[$i - 1] != "\\") {
            $string = false;
        } else {
            $v .= $ch;
        }
    }

    return $return;
}

Je ne l'ai pas trop testé, mais on dirait que cela fonctionne. Voici mes tests avec les résultats: 

var_export(pg_array_parse('{1,2,3,4,5}'));echo "\n";
/*
array (
  0 => '1',
  1 => '2',
  2 => '3',
  3 => '4',
  4 => '5',
)
*/
var_export(pg_array_parse('{{1,2},{3,4},{5}}'));echo "\n";
/*
array (
  0 => 
  array (
    0 => '1',
    1 => '2',
  ),
  1 => 
  array (
    0 => '3',
    1 => '4',
  ),
  2 => 
  array (
    0 => '5',
  ),
)
*/
var_export(pg_array_parse('{dfasdf,"qw,,e{q\"we",\'qrer\'}'));echo "\n";
/*
array (
  0 => 'dfasdf',
  1 => 'qw,,e{q"we',
  2 => 'qrer',
)
*/
var_export(pg_array_parse('{,}'));echo "\n";
/*
array (
  0 => '',
  1 => '',
)
*/
var_export(pg_array_parse('{}'));echo "\n";
/*
array (
)
*/
var_export(pg_array_parse(null));echo "\n";
// NULL
var_export(pg_array_parse(''));echo "\n";
// NULL

P.S .: Je sais que c'est un très vieux billet, mais je n'ai trouvé aucune solution pour postgresql pre 9.2

8
dmikam

Fonction fiable pour analyser le littéral de tableau PostgreSQL (unidimensionnel) dans le tableau PHP, à l'aide d'expressions régulières:

function pg_array_parse($literal)
{
    if ($literal == '') return;
    preg_match_all('/(?<=^\{|,)(([^,"{]*)|\s*"((?:[^"\\\\]|\\\\(?:.|[0-9]+|x[0-9a-f]+))*)"\s*)(,|(?<!^\{)(?=\}$))/i', $literal, $matches, PREG_SET_ORDER);
    $values = [];
    foreach ($matches as $match) {
        $values[] = $match[3] != '' ? stripcslashes($match[3]) : (strtolower($match[2]) == 'null' ? null : $match[2]);
    }
    return $values;
}

print_r(pg_array_parse('{blah,blah blah,123,,"blah \\"\\\\ ,{\100\x40\t\daő\ő",NULL}'));
// Array
// (
//     [0] => blah
//     [1] => blah blah
//     [2] => 123
//     [3] =>
//     [4] => blah "\ ,{@@ daőő
//     [5] =>
// )

var_dump(pg_array_parse('{,}'));
// array(2) {
//   [0] =>
//   string(0) ""
//   [1] =>
//   string(0) ""
// }

print_r(pg_array_parse('{}'));
var_dump(pg_array_parse(null));
var_dump(pg_array_parse(''));
// Array
// (
// )
// NULL
// NULL

print_r(pg_array_parse('{または, "some string without a comma", "a string, with a comma"}'));
// Array
// (
//     [0] => または
//     [1] => some string without a comma
//     [2] => a string, with a comma
// )
3
user2829228

Si vous pouvez prévoir quel type de données de texte vous pouvez vous attendre dans ce champ, vous pouvez utiliser la fonction array_to_string. Il est disponible en 9.1

Par exemple. Je sais exactement que mon champ de tableau labes n'aura jamais le symbole '\n'. Je convertis donc le tableau labes en chaîne à l'aide de la fonction array_to_string

SELECT 
  ...
  array_to_string( labels, chr(10) ) as labes
FROM
  ...

Maintenant, je peux scinder cette chaîne en utilisant PHP function explode:

$phpLabels = explode( $pgLabes, "\n" );

Vous pouvez utiliser n'importe quelle séquence de caractères pour séparer les éléments du tableau.

SQL:

SELECT
  array_to_string( labels, '<--###DELIMITER###-->' ) as labes

PHP:

$phpLabels = explode( $pgLabes, '<--###DELIMITER###-->' );
1
Nicolai

J'ai essayé la réponse array_to_json, mais malheureusement, cela entraîne une erreur de fonction inconnue. L'utilisation du constructeur de requêtes dbal sur une base de données Postgres 9.2 avec quelque chose comme ->addSelect('array_agg(a.name) as account_name'), j'ai comme résultat une chaîne telle que { "name 1", "name 2", "name 3" }

Il n’existe que des guillemets autour des éléments du tableau s’ils contiennent des caractères spéciaux tels que des espaces ou des signes de ponctuation.

Donc, s'il y a des guillemets, je fais de la chaîne une chaîne json valide, puis j'utilise la fonction d'analyse json intégrée. Sinon j'utilise exploser.

$data = str_replace(array("\r\n", "\r", "\n"), "", trim($postgresArray,'{}'));
if (strpos($data, '"') === 0) {
    $data = '[' . $data . ']';
    $result = json_decode($data);
} else {
    $result = explode(',', $data);

}

1
user3733839

Si vous avez le contrôle de la requête qui frappe la base de données, pourquoi ne pas simplement utiliser unnest() pour obtenir les résultats sous forme de lignes au lieu de Postgres-arrays? À partir de là, vous pouvez obtenir nativement un tableau PHP.

$result = pg_query('SELECT unnest(myArrayColumn) FROM someTable;');
if ( $result === false ) {
    throw new Exception("Something went wrong.");
}
$array = pg_fetch_all($result);

Ceci évite les problèmes de maintenance et de maintenance que vous rencontriez en essayant de convertir vous-même la représentation sous forme de chaîne du tableau.

0
koyae

Je peux voir que vous utilisez explode(',', trim($pgArray, '{}'));

Mais explode est utilisé pour diviser une chaîne par chaîne (et vous lui fournissez un tableau !!). quelque chose comme ..

$string = "A string, with, commas";
$arr = explode(',', $string);

Qu'essayez-vous de faire avec array? si vous voulez concaténer jeter un oeil sur imploser

OU vous ne savez pas s'il est possible de spécifier un délimiteur autre qu'une virgule? array_to_string (anyarray, text)

0
TigerTiger