在 Knex 中为表命名

Posted

技术标签:

【中文标题】在 Knex 中为表命名【英文标题】:Alias a table in Knex 【发布时间】:2015-04-06 02:11:11 【问题描述】:

我有一个 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 中执行此操作有点迷茫。我的第一次尝试不涉及别名,所以我得到了一个“表多次使用”错误。当我尝试使用 .as() 方法时,knex 抱怨缺少 .from() 子句。 .as() 方法是否仅用于给子查询起别名,我不应该期望它用于给表起别名?

【问题讨论】:

【参考方案1】:

我想我明白了。在 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() 方法的存在感到困惑,该方法(据我目前的理解)仅用于子查询,而不用于别名表或列名。

【讨论】:

【参考方案2】:

有two ways 来声明标识符(表或列)的别名。可以直接给出标识符的 aliasName 后缀(例如 identifierName 作为 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"

【讨论】:

2020 年更新 - 当我最初问这个问题时,我不确定 Knex 中是否存在这种机制,但现在这似乎是给表起别名的正确方法。谢谢!【参考方案3】:

在尝试弄清楚如何在列名相等的情况下从所有连接表中选择所有列而不相互覆盖时发现了这个问题。我就是这样做的,在每个前面加上它的“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);

【讨论】:

希望这是相关的,并会帮助某人【参考方案4】:

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

【讨论】:

我可能是错的,但这听起来有点像您的答案一般适用于 SQL,但不适用于 knex.js。我知道我的 SQL 是正确的,但我试图弄清楚它在 knex-speak 中的表达方式。 如何使用它来给列名取别名? .column('x').as('y')table 别名为 'y',not 'x'。 它的完成方式与表名相同,并且在我上面的答案中有一个别名列的示例。 (“用户”是一个列名,我将其别名为“ua”。)抱歉回复晚了,哈!

以上是关于在 Knex 中为表命名的主要内容,如果未能解决你的问题,请参考以下文章

在 PHP 中为 stdClass 对象设置命名空间

如何在 SonarLint 中为 PascalCase 命名规则指定例外

如何在 jpa 中为 EmbeddedId 编写选择命名查询?

我无意中为命名空间和类名使用了相同的名称,并且需要重命名其中一个的所有实例

如何在 Meteor 中为全局变量创建自己的命名空间?

如何在 html 表中为未知数量的输入命名?