Dies mag eine dumme, einfache Frage sein, aber ich habe herumgestöbert und konnte keine Antwort finden.
Ich habe diese Abfrage mit einer Unterabfrage
return knex.raw(`
update gps_message gm
set status = 'PROCESSING'
from (
select id
from gps_message
where status = 'MATCHED'
order by id
limit ?
) sub
where gm.id = sub.id
returning *
`, [limit])
Aber wenn ich versuche, and id in (?)
so hinzuzufügen,
return knex.raw(`
update gps_message gm
set status = 'PROCESSING'
from (
select id
from gps_message
where status = 'MATCHED'
and id in (?)
order by id
limit ?
) sub
where gm.id = sub.id
returning *
`, [[1,2,3],limit])
Ich verstehe das
invalid input syntax for integer: "{"1","2","3"}"
Übersehe ich hier etwas?
Laufen in ein ähnliches Problem. Hast du jemals eine Lösung gefunden @rogerschlachter ?
Das scheint zu funktionieren ... Ich nehme an, dies ist ein weiterer Fall von undefiniertem Verhalten, das sich in Zukunft ändern könnte:
> knex.raw(`select 1 where id in (??) order by id limit ? )`, [[1,2,3],1]).toSQL()
{ method: 'raw',
sql: 'select 1 where id in (1, 2, 3) order by id limit ? )',
bindings: [ '1' ],
options: {},
__knexQueryUid: '0634182d-0282-401d-9da0-83b0fb7547d8' }
Mir ist kein offizieller Weg bekannt, außer dass Sie den Abfragegenerator verwenden, um Ihre Abfrage zu schreiben, und .whereIn()
in der Unterabfrage verwenden ...
BEARBEITEN:
Auch das funktioniert nicht mit Strings, weil sie als Bezeichner maskiert würden....
Ich bin mir nicht sicher, warum Array immer in '{"1","2","3"}'
konvertiert wird. Ich nehme an, es hat etwas mit der Syntax von https://www.postgresql.org/docs/9.1/static/arrays.html zu tun, und Knex Raw hat keine Möglichkeit, den Kontext zu kennen, in dem das Array gerendert wird. Ich weiß auch nicht, ob sogar der pg-Treiber die Übergabe von Arrays an seine Parameterbindungen erlauben würde.
Die ursprüngliche Rohabfrage funktioniert wie gewünscht für die anderen Treiber: mysql
, sqlite
, oracle
, mssql
. Dies ist definitiv ein pg
-spezifisches Problem. Es wandelt auch Zahlen in Strings um - was bei den anderen Treibern nicht vorkommt. Aus limit 10
wird also limit '10'
(siehe #1001).
Wenn die innere Abfrage mit Knex erstellt wird, funktioniert sie meistens - wiederum mit der Einschränkung, dass Zahlen in Zeichenfolgen umgewandelt werden. Hier ist eine kurze Demo von jedem zusammen mit der Ausgabe:
const limit = 10;
const raw = knex.raw(`update gps_message gm
set status = 'PROCESSING'
from (
select id
from gps_message
where status = 'MATCHED'
and id in (?)
order by id
limit ?
) sub
where gm.id = sub.id
returning *
`, [[1,2,3],limit]);
console.log('--raw:\n', raw.toString());
const inner = knex.from('gps_message')
.where('status', 'MATCHED')
.whereIn('id', [1, 2, 3])
.orderBy('id')
.limit(limit);
console.log('--inner:\n', inner.toString());
console.log();
const rawWithInner = knex.raw(`update gps_message gm
set status = 'PROCESSING'
from (?) sub
where gm.id = sub.id
returning *
`, [knex.raw(inner.toString())]);
console.log('--rawWithInner:\n', rawWithInner.toString());
Und die Ausgabe:
--raw:
update gps_message gm
set status = 'PROCESSING'
from (
select id
from gps_message
where status = 'MATCHED'
and id in ('{"1","2","3"}')
order by id
limit '10'
) sub
where gm.id = sub.id
returning *
--inner:
select * from "gps_message" where "status" = 'MATCHED' and "id" in ('1', '2', '3') order by "id" asc limit '10'
--rawWithInner:
update gps_message gm
set status = 'PROCESSING'
from (select * from "gps_message" where "status" = 'MATCHED' and "id" in ('1', '2', '3') order by "id" asc limit '10') sub
where gm.id = sub.id
returning *
In der Zwischenzeit können Sie stattdessen ANY() verwenden:
knex.raw('select 1 where id = ANY(?)', [[1, 2, 3, 'strings too']])
in vielen Fällen sind sie gleichwertig:
http://stackoverflow.com/questions/30263671/postgresql-in-vs-any
http://stackoverflow.com/questions/34627026/in-vs-any-operator-in-postgresql
Ich denke, dass die Dinge in erster Linie konsistent sein sollten - WHERE foo IN (?)
sollte auf die gleiche Weise erweitert werden, egal welche Plattform verwendet wird. Arrays sind kein grundlegender Datentyp, der von allen Plattformen unterstützt wird – sie sind eine spezifische Funktion von Postgres – wenn Sie also den Benutzer knex über seine Absicht informieren müssen, wenn ein Array übergeben wird, sollte das Standardverhalten dasjenige sein, das funktioniert auf allen Plattformen, und der Benutzer sollte das Array mit etwas wie knex.array(foo)
umschließen, wenn er das Array _type_ verwenden möchte.
Ich werde dies schließen, da der aktuelle Stand, wie dies unterstützt wird, bereits beantwortet ist. Das nächste wäre, eine entsprechende Funktionsanfrage zur Erweiterung der ?
-Parametererweiterung zu öffnen, um Arrays besser zu unterstützen, mit einem API-Vorschlag und einer Untersuchung, welche Art von Unterstützung für verschiedene Datenbanken erforderlich ist.
@jahudka default könnte wahrscheinlich nur eine durch Kommas getrennte Liste ohne Klammern sein, wie eine, die mit where in (?)
funktionieren könnte ... aber ich bin mir nicht sicher, ob selbst das für jeden Dialekt gültig ist, also könnte es sogar dialektspezifisch sein solange wie es einfach funktioniert. Wie auch immer, wie gesagt, eine ordnungsgemäße Feature-Anfrage wäre der nächste Schritt, um dies zu implementieren.
das ist meine lösung
const queryAll = _db .table('group_org_device') .leftJoin('group_org', function() {
this.on(
'group_org.org_id_str',
'group_org_device.org_id_str')
.on(
'group_org.ldap_id',
'group_org_device.ldap_id' );
})
.select('group_org_device.device_mark')
if(!toAll) {
queryAll.whereRaw('group_org.group_id in (' + allGroupIds.map(_ => '?').join(',') + ')', [...allGroupIds])
}
Hilfreichster Kommentar
In der Zwischenzeit können Sie stattdessen ANY() verwenden:
knex.raw('select 1 where id = ANY(?)', [[1, 2, 3, 'strings too']])
in vielen Fällen sind sie gleichwertig:
http://stackoverflow.com/questions/30263671/postgresql-in-vs-any
http://stackoverflow.com/questions/34627026/in-vs-any-operator-in-postgresql