如何从Knex.js中的连接表中选择特定列?

时间:2015-04-01 10:09:11

标签: node.js knex.js

我在SQL数据库工作了大约20年,似乎无法理解Knex映射查询的方式。有人可以帮我找到正确的代码吗?

我想在我的nodejs应用程序中使用这个SQL查询:

SELECT p.id, p.project_number, p.project_name, p.start_date, p.end_date,
   o.name, o.email_addr,
   c.company, c.email_addr AS company_email, c.first_name, c.last_name
FROM projects p
INNER JOIN owners o ON o.id = p.owner_id
INNER JOIN clients c ON c.id = p.client_id

KnexJS(0.7.5)文档显示了我的查询的示例:

knex.from('projects').innerJoin('owners', 'owners.id', 'projects.owner_id')
  .innerJoin('clients', 'clients.id', 'projects.client_id');

我在文档中找不到一些东西:

1)如何选择要包含的列?项目,客户和业主每个都有20到50列,我对所有这些都不感兴趣。从主表中选择列是明确的(使用 select()列()),但如何从已连接的表中选择列?

2)有些列具有相同的名称。如何避免名称冲突(即为其他表中的列添加一些前缀)?我查看了Knex可以生成列别名(... AS ...)的方式,我不确定它是否是更复杂查询的可行选项。 (即使是像上面那样相对简单的查询)

3 个答案:

答案 0 :(得分:8)

您可以尝试:

knex('projects').select(['projects.id', 'projects.project_number', 'projects.project_name', 'projects.start_date', 'projects.end_date',
    'owners.name', 'owners.email_addr as owner_email_addr',
    'clients.company', 'clients.email_addr as client_email_addr', 'clients.first_name', 'clients.last_name'])
.innerJoin('owners', 'owners.id', 'projects.owner_id')
.innerJoin('clients', 'clients.id', 'projects.client_id');

希望这有帮助!

答案 1 :(得分:2)

在这个答案中,我将讨论的范围不止于选择问题本身!

选择并避免名称冲突

选择的原则是使用select。通过重命名列(别名)可以避免名称冲突。 要创建别名(列重命名),只需在列名字符串中使用as,如下面的代码段所示:

knex
.select([
    'table_a.id',
    'table_b.id as b_id'  // --->  the way to create aliases (to avoid 
])                             //  columns overlapping and overriding
.from('table_a')
.leftJoin(
    'table_b',
    'table_a.table_b_id',
    'table_b.id'
);

它将产生此SQL:

SELECT 
  "table_a"."id",
  "table_b"."id" as "b_id"
FROM 
  "table_a" 
LEFT JOIN "table_b" ON 
  "table_a"."table_b_id" = "table_b"."id"

我们可以用不同的方式来表述。以下是一些有趣的内容:

knex('processes') // <-- wihtout using from (shorter) [less sql like though]
.select([ 
    'processes.id as processId',
    'processes.name as processName',
    'processes.description as processDescription',
    'processes.deleted as processDeleted',
    'processes.deleteTime as processDeleteTime',
    'rsp.runningSettingId',
    'rsp.value as settingValue',
    'rsp.startTime as settingStartTime'
])
.innerJoin(
   'runningSettings_processes as rsp',
   'processes.id',
   'rsp.processId'
);

多个联接示例(3个及更多)

const superJoinData = await knex( // i'm using async await for the promises
        knex<Process>('process')//__________________________from here
        .select([
            'processes.id as processId',
            'processes.name as processName', //--- conflict with rs.name
            'processes.description as processDescription', //-- conflict with rs.description
            'processes.deleted as processDeleted',
            'processes.deleteTime as processDeleteTime',
            'rsp.runningSettingId',
            'rsp.value as settingValue',
            'rsp.startTime as settingStartTime'
        ])
        .innerJoin(
            'runningSettings_processes as rsp',
            'processes.id',
            'rsp.processId'
        )//_______________________to here 
        .as('prsp') //            |first join. (result an equivalent of a table)
    ) // !!!!!!!!!!!!!!!!! notice how we nested a knex construct within another!!
    .select([ // select from the resulting table of the first join !!!!
        'prsp.processId',
        'prsp.processName',
        'prsp.processDescription',
        'prsp.processDeleted',
        'prsp.processDeleteTime',
        'prsp.runningSettingId',
        'prsp.settingValue',
        'prsp.settingStartTime',
        'rs.name as settingName',
        'rs.description as settingDescription'
    ])
    .innerJoin( // ______________second inner join
        'runningSettings as rs',
        'prsp.runningSettingId',
        'rs.id'
    );
  

请注意如何使用as()方法!

额外(与选择无关,但构造和联接)

使用以下位置进行过滤:

knex(
  knex('A').where('A.id',1).as('t1')
).leftJoin(
  knex('B').where('B.id', 2).as('t2'), 
  't1.c', 
  't2.d'
)

//or filter the resulting table of the join
knex('A')
.leftJoin(
  knex('B').where('B.id', 2).as('t2'), 
  't1.c', 
  't2.d'
)
.where('someColumn', 2);

使用回调进行进一步控制

knex
.select('*')
.from(function () {
     this.select('*').from('A')
     .where('id',1)
     .as('t1');
})
.leftJoin(
     knex('B').where('id',2).as('t2'), 
     function () {
          this.on('t1.c', '=', 't2.d'); // <--- notice also the use of function 
     }                                        // construct for the join condition
);

与上述相同,但没有函数构造(并且有多个加入条件作为奖励)

knex( // <--- notice the knex constructor (equivTo: knex.select().from())
      knex('A')   //NT: we already used that above when answering the question 
      .select('*')
     .where('id',1)
     .as('t1'); 
)
.leftJoin(
     knex('B').where('id',2).as('t2'), 
     function () { // <----- notice that in place of using the 2nd and 3d arg, we can have a function in the 2nd arg
          this.on('t1.c', '=', 't2.d').on('t1.s', '=', 't2.g'); // <-----| 
     }                             // plus: multiple on conditions______/
);

答案 2 :(得分:0)

如果您想从一个表中选择所有列,并从另一个表中选择特定列,您可以使用:

knex('projects').select(['projects.*', 'owners.email_addr as owner_email_addr', 'clients.email_addr as client_email_addr', 'clients.first_name', 'clients.last_name'])
.innerJoin('owners', 'owners.id', 'projects.owner_id')
.innerJoin('clients', 'clients.id', 'projects.client_id');

这将获取 projects 中的所有列、owners 中的一列和 clients 中的三列。

相关问题