同じテーブルを2回参照するSQLクエリがあり、テーブルを2つの別々のエイリアスにエイリアスする必要があります。これをKnexで構成する方法がよくわかりません。
「Words」テーブルと「Users」テーブルがあります。 Wordsテーブルには、Usersテーブルの「id」列を参照する2つの外部キー「author_id」と「winner_id」があります。
Knexで作成しようとしているSQLは次のとおりです。
SELECT w.*, ua.name, uw.name FROM Words AS w
INNER JOIN Users AS ua ON w.author_id = ua.id
LEFT JOIN Users AS uw ON w.winner_id = uw.id
Knexでこれを行う方法について少し迷っています。私の最初の試みはエイリアシングを含まなかったので、「テーブルが複数回使用されました」エラーが発生しました。 .as()メソッドを使用しようとすると、knexは、.from()句が欠落していると不平を言いました。 .as()メソッドはサブクエリのエイリアスにのみ使用されますか?テーブルのエイリアスに使用されるとは思わないのですか?
私はそれを理解したと思います。 knex.jsで、次のようなテーブルを指定するとします。
knex.select( '*' ).from( 'Users' )
次に、次のように、テーブル名の引用符の中にASキーワードを追加して、エイリアスを付けます。
knex.select( '*' ).from( 'Users AS u' )
..これを列名に対しても行うことができます。したがって、元のSQLはknex-landでは次のようになります。
knex.select( 'w.*', 'ua.name AS ua_name', 'uw.name AS uw_name' )
.innerJoin( 'Users AS ua', 'author_id', 'ua.id' )
.leftJoin( 'Users as uw', 'winner_id', 'uw.id' )
Knexの.as()メソッドの存在に戸惑いましたが、これは(現在理解している限り)テーブルや列名のエイリアスではなく、サブクエリのみを対象としています。
列名が等しい場合、互いに上書きせずにすべての結合テーブルからすべての列を選択する方法を理解しようとしたときにこの質問が見つかりました。これは私がやった方法で、それぞれに「tablename_」を付加します:
const columnToText = (table, column) => `${table}.${column} as ${table}_${column}`;
const prepareColumns = async (table) => {
const columnsInfo = await knex(table).columnInfo();
return Object.keys(columnsInfo).map(column => columnToText(table, column));
};
const selectColumns = (await Promise.all([
'joined_table1',
'joined_table2',
'main_table',
].map(prepareColumns)))
.reduce((acc, item) => ([...acc, ...item]), []);
const data = await knex('main_table')
.leftJoin('joined_table1', 'main_table.joined_table1_id', 'joined_table1.id')
.leftJoin('joined_table2', 'main_table.joined_table1_id', 'joined_table2.id')
.select(...selectColumns);