在Knex中给表起别名

36

我有一个SQL查询涉及同一张表两次,我需要将该表别名为两个不同的别名。但我无法弄清如何在Knex中组合它。

有一个“Words”表和一个“Users”表。Words表有两个外键,“author_id”和“winner_id”,引用了Users表的“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中,我有点不知道如何做。我的第一次尝试没有涉及别名(aliasing),因此我得到了一个“表格被多次使用”的错误。当我尝试使用.as()方法时,Knex抱怨缺少了.from()子句。.as()方法只用于给子查询起别名吗?我不应该期望它用于给表格起别名吗?

4个回答

72

我想我弄清楚了。在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()方法迷惑了,据我目前的理解,它仅用于子查询,而不是用于别名表或列名。


请注意,这里不支持使用简写别名语法Users us,必须提供AS关键字。 - jirkamat

45

声明标识符(表或列)的别名有两种方式:可以直接将别名作为标识符的后缀,例如:identifierName as aliasName;也可以传递一个对象{aliasName: 'identifierName'}。

因此,以下代码:

 knex.select('w.*', 'ua.name', 'uw.name')
  .from({ w: 'Words' })
  .innerJoin({ ua: 'Users' }, 'w.author_id', '=', 'ua.id')
  .leftJoin({ uw: 'Users' }, 'w.winner_id', '=', 'uw.id')
  .toString()

将编译为:

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"

1
更新2020 - 我不确定在我最初提出这个问题时Knex是否存在这种机制,但现在似乎这是别名表的正确方式。谢谢! - Bobby Circle Ciraldo
1
Knex 更新了他们的文档并打破了父级评论中的链接,现在应该指向这里 - Schleicher

1

在尝试弄清楚如何从所有连接表中选择所有列而不覆盖彼此的情况下找到了这个问题,如果列名相同。 这就是我做的,用其“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);

希望这是相关的,并且能够帮助到某些人。 - Dmitriy Botov

-2

别名.as()方法不仅用于子查询,还可用于别名列名和表。在您的情况下,您需要对表使用别名,因为您使用了该表两次。在第一次尝试中,它出现错误,因为您的SQL语句混淆了。通过在两次使用的表上放置别名,您为其提供了一个标识,即ua.Users表现在与uw.Users表不同。希望这可以帮助您。


1
我可能说错了,但是听起来你的回答似乎是普遍适用于SQL,而不是特指knex.js。我知道我的SQL是正确的,但我正在尝试弄清楚它在knex中是如何表达的。 - Bobby Circle Ciraldo
你如何使用它来别名列名?.column('x').as('y')表格别名为“y”,而不是“x”。 - mpen
它的处理方式与表名相同,在我上面的回答中有一个列别名的示例。(“Users”是一个列名,我将其别名为“ua”)。抱歉回复晚了,哈! - Bobby Circle Ciraldo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接