web-dev-qa-db-ja.com

Knex.jsを使用したselectステートメントのサブクエリ

Knexを使用してサブクエリで次のクエリを作成しようとしています。

SELECT 
  t.*, 
  (SELECT COUNT(*) FROM team_users tu WHERE TeamID = t.ID) AS UserCount,
  (SELECT COUNT(*) FROM team_access ta WHERE TeamID = t.ID) AS AppCount
FROM teams t WHERE OwnerUserID = _UserID;

結果は、異なるテーブル(team_users、team_access)からのUserCountとAppCountのカウント集計を含むteamsテーブルになります。

id | Name      | OwnerUserID   | UserCount | AppCount
-----------------------------------------------------
134| Team A    | 1538          | 7         | 6
135| Team B    | 1538          | 4         | 2
136| Team C    | 1538          | 12        | 1

同等のknex実装であると私が考えたのは次のとおりです。

var subquery1 = Knex.knex('team_users').count('*').where('TeamID', 'teams.ID').as('UserCount');
var subquery2 = Knex.knex('team_access').count('*').where('TeamID', 'teams.ID').as('AppCount');
Knex.knex.select('*', subquery1, subquery2).from('teams').where("OwnerUserID", ownerId).asCallback(dataSetCallback);

それを実行すると、返されたオブジェクトの「UserCount」列と「AppCount」列が取得されますが、サブクエリで「teams.ID」が識別されないため、常にゼロになります。

Knex.raw関数を使用してそれを解決することができました:

Knex.knex('teams')
    .select('*', Knex.knex.raw('(SELECT COUNT(*) FROM team_users WHERE TeamID = teams.ID) AS UserCount'), Knex.knex.raw('(SELECT COUNT(*) FROM team_access WHERE TeamID = teams.ID) AS AppCount'))
    .where("OwnerUserID", ownerId)
    .asCallback(dataSetCallback);

しかし、サブクエリオブジェクトを使用してこれを実現する方法を知りたいと思います。

8
Didi

_teams.ID_文字列を値として渡そうとしています。 .where('columnName', 'otherColumnName')を実行できるようにするには、 _knex.ref_ を使用してotherColumnNameを識別子として渡す必要があります。

_var teamsIdColumnIdentifier = knex.ref('teams.ID'); // <-- [1]

var subquery1 = Knex.knex('team_users').count('*')
  .where('TeamID', teamsIdColumnIdentifier).as('UserCount');
var subquery2 = Knex.knex('team_access').count('*')
  .where('TeamID', teamsIdColumnIdentifier).as('AppCount');

Knex.knex.select('*', subquery1, subquery2).from('teams')
  .where("OwnerUserID", ownerId).asCallback(dataSetCallback);
_

[1] _knex.ref_が 2018年5月 にKnexに追加される前は、次のように_knex.raw_を使用する必要がありました。

_var teamsIdColumnIdentifier = knex.raw('??', ['teams.ID']);
_
8
Mikael Lepistö