tiny ‘n’ smart
database layer

Odkazy: dibi | API reference

Oznámení

Omlouváme se, provoz fóra byl ukončen

Postgre – dotaz s hranatými závorkami

před 3 lety

revoke
Člen | 30
+
0
-

Potřebuji vytvořit tento dotaz:

i.pocet_noci && '{3,5}'::SMALLINT[] AND i.strava && '{0,1,4,5}'::SMALLINT[]

Zkoušel jsem několik způsobů zápisu, nejnadějnější se zdál být asi ten nejméně hezký:

... i.pocet_noci && %sql", "'{".implode(',', $nights)."}'::SMALLINT[]", ' AND i.strava && %sql", "'{".implode(',', $food)."}'::SMALLINT[]", ,'...

Který funguje, pokud je v dotazu jen jedna podmínka. V případě dvou se z dotazu stane toto:

i.pocet_noci && '{3,5}'::SMALLINT"] AND i"."strava && '{0,1,4,5}'::SMALLINT["

Čili vnější hranaté závorky přeložil za uvozvky. Existuje nějaký způsob, jak escapovat hranaté závorky, aby se dalo zapsat column::INT[] ?
Díky za radu.

před 3 lety

Milo
Moderator | 1031
+
0
-

Dibi si s PostgreSQL poli moc nerozumí. Můžeš zkusit moji třídu PgsqlArray. S dibi ji používám takhle:

$a1 = Milo\Utils\PgsqlArray::toSql([3, 5]) . '::SMALLINT[]';
$a2 = Milo\Utils\PgsqlArray::toSql([0, 1, 4, 5]) . '::SMALLINT[]';

'i.pocet_noci && %SQL', $a1, 'AND i.strava && %SQL', $a2

Na implode() pozor. Musíš escapovat každou položku pole v kontextu pole a v kontextu řetězce.

před 3 lety

revoke
Člen | 30
+
0
-

Zkusil jsem, ale při použití dvou polí se to chová stejně špatně. S escapováním máš samozřejmě pravdu a ta tvá třída se na to hodí. Díky.

A k řešení problému: použitím odpovídajících si datových typů jsem si mohl dovolit vypustit z dotazu ::SMALLINT[]… což je a zároveň i není řešení ;-)

před 3 lety

Milo
Moderator | 1031
+
0
-

Co myslíš tím, že se to chová špatně při použití dvou polí?

před 3 lety

revoke
Člen | 30
+
0
-

Kód:

WHERE i.id_jazyk = %i', $this->jazykId(), '
%if ', !empty($params->stay), ' AND i.pocet_noci && %SQL', PgsqlArray::toSql($params->stay).'::SMALLINT[]', ' %end
%if ', !empty($params->food), ' AND i.strava && %SQL', PgsqlArray::toSql($params->food).'::SMALLINT[]', ' %end
%if ', $fullsearch, ' ORDER BY i.id_produkt %end

(předpokládám, že co je před tím a za tím už nemá vliv…)

Dibi vytvoří takovýto dotaz:

WHERE i.id_jazyk = 1
 AND i.pocet_noci && E'{5,7}'::SMALLINT"]
 AND i"."strava && E'{1,5}'::SMALLINT["
ORDER BY i.id_hlavni_produkt

Editoval revoke (3. 2. 2015 9:33)

před 3 lety

Milo
Moderator | 1031
+
0
-

Divné. Následující mi funguje:

$db->test('
    WHERE
        i.id_jazyk = %i', 111, '
        %if', TRUE, 'AND i.pocet_noci && %SQL', "'{1,2,3}'::SMALLINT[]", '%end
        %if', TRUE, 'AND i.strava && %SQL', "'{4,5,6}'::SMALLINT[]", '%end
        %if', TRUE, 'ORDER BY i.id_produkt %end
');

EDIT:
Teď mě napadlo… nepředáváš to někde dál přes modifikátor %sql (malé písmena)? Ten se ještě zpracovává. Cokoliv ale vyleze z DibiTranslator je už finálně escapované a mělo by se předávat přes %SQL.

Editoval Milo (4. 2. 2015 14:56)

před 3 lety

revoke
Člen | 30
+
0
-

Tou poznámkou jsi to vyřešil!
Pravděpodobně jsem to celé začal řešit kvůli jiné chybě, ale při dumpu dotazu jsem se upnul k řetězci, který mi vrátil dvakrát escapovaný dotaz:

\dibi::test(\dibi::$sql); ... opraveno na ... \dibi::test('%SQL', \dibi::$sql);

Mockrát díky!