Propel:从别名连接表中选择列

Posted

技术标签:

【中文标题】Propel:从别名连接表中选择列【英文标题】:Propel: selecting columns from aliased join tables 【发布时间】:2013-10-22 17:30:40 【问题描述】:

我有以下两张表:

  table_a:
    id_table_a:  type: integer, primaryKey: true, autoIncrement: true, required: true 
    name:        type: varchar(255) 
    id_table_b:  type: integer, foreignTable: table_b, foreignReference: id_table_b 

  table_b: 
    id_table_b:  type: integer, primaryKey: true, autoIncrement: true, required: true 
    value_1:     type: varchar(255) 
    value_2:     type: integer 

我想使用 select 方法构建 SQL 查询以跳过水合,同时在连接表上使用别名:

 TableAQuery::create()
            ->useTableBQuery('a')
                // some filters methods
            ->endUse()
            ->useTableBQuery('b')
                // some filters methods
            ->endUse()
            ->select(array('a.value_1', 'b.value_2'))
            ->find();

现在问题来了。不断地将ab 别名更改为table_b,从而生成错误的SQL,如下所示:

SELECT table_b.value_1 AS "a.value_1", table_b.value_2 AS "b.value_2" FROM `table_a`
LEFT JOIN `table_b` `a` ON (table_a.id_table_b=a.id_table_b) 
LEFT JOIN `table_b` `b` ON (table_a.id_table_b=b.id_table_b)

而不是

SELECT a.value_1 AS value_1, b.value_2 AS value_2 FROM `table_a` 
LEFT JOIN `table_b` `a` ON (table_a.id_table_b=a.id_table_b) 
LEFT JOIN `table_b` `b` ON (table_a.id_table_b=b.id_table_b)

我该如何处理?我使用 Propel 1.6.9

更新

我也查了propel 1.7.1,没区别。

【问题讨论】:

有趣的问题,我也不知道答案;也许这是一个 Propel 错误。你还需要答案吗?如果你这样做,我会在它上面加一个赏金。如果是这样,请在 @halfer 上联系我。 @halfer 如果您能帮助引起对该主题的关注,那就太好了。我几乎每天都在使用 Propel,这不是我第一次因为这个问题而陷入困境。 我想我有同样的问题? ***.com/questions/20127660/…不知道有没有提交过bug? @KarasQ,让我知道你如何接受 jchamberlain 的建议。 @halfer jchamberlain 的建议与我的示例产生的结果相同。 【参考方案1】:

在我阅读了 jchamberlain 在他的回答下关于where caluse 的评论后,我做了一些研究,我得出结论

在推进函数中键入列名时,应始终使用UpperCamelCase 样式,即使不使用此样式有时也可以正常工作 解决方案取决于 Propel 版本

Propel Cannot fetch ColumnMap for undefined column: ID_TABLE_B Propel 异常结束。

对于 Propel >= 1.6.8,这将起作用:

如果您需要带有别名列的 数组 作为结果

TableAQuery::create()
  ->useTableBQuery('a')
      // some filters methods
  ->endUse()
  ->useTableBQuery('b')
      // some filters methods
  ->endUse()
  ->select(array('a.Value1', 'b.Value2')) // notice a.value_1 or b.value_2 won't work
  ->find();

如果您需要具有来自别名列的虚拟列的对象

TableAQuery::create()
  ->useTableBQuery('a')
      // some filters methods
  ->endUse()
  ->useTableBQuery('b')
      // some filters methods
  ->endUse()
  ->withColumn('a.Value1') // notice a.value_1 won't work
  ->withColumn('b.Value2') // notice b.value_2 won't work
  ->find();

【讨论】:

【参考方案2】:

你能改成这样吗?

TableAQuery::create()
        ->useTableBQuery('a')
            // some filters methods
        ->endUse()
        ->useTableBQuery('b')
            // some filters methods
        ->endUse()
        //->select(array('a.value_1', 'b.value_2'))
        ->addAsColumn('a.value_1', 'a.value_1')
        ->addAsColumn('b.value_2', 'b.value_2')
        ->find();

警告:我不是 Propel 用户。 我只是想知道自动生成的useXXXQuery() 是否两次都在同一个关系上设置表别名,或者类似的东西。

与上面的查询一样,将您的 select() 替换为两个 addAsColumn() 语句。这有点 hack,但我认为它可以达到您想要的结果。

我刚刚花了一些时间阅读 Propel 源代码,我得出的结论是,Propel 1 不是为了在同一个表上使用不同的别名而构建的,就像你尝试的那样多次连接。在ModelCriteria.php 中,使用$column->getFullyQualifiedName 可确保在选择联接表时使用全名(table.column),而不管别名如何。 (请参阅https://github.com/propelorm/Propel/blob/7ddb0956b699343d33ce0c94043fa5970cc719c1/runtime/lib/query/ModelCriteria.php#L2082。)我认为这确实是一个错误。

如果使用 addAsColumn() 方法而不是 select(),Propel 将使用您的文字 SQL 表达式,无论是别名和列还是其他任何内容。也就是说,我不确定这是它的预期用途。

【讨论】:

它抛出异常'Unknown relationship table_b on the TableA table',所以我将table_b更改为TableB,现在它在SQL select语句中生成与我的示例相同的错误别名。所以它不会改变任何东西。 有效!但它需要与select 结合使用,否则 Propel 返回空对象(未分配值)并产生大量警告和通知(未定义的偏移量),但它会生成我预期的 SQL。顺便说一句,即使同一个表上没有多个连接,也会出现问题。如果我尝试添加where 函数(e.g. ->where('a.value_1 = "xxx"'),你的hack 似乎也不起作用。 Propel 在那种情况下使用CROSS JOIN,并且在 WHERE 子句中不使用别名 - 很奇怪。更复杂的条件仍然可能是一个问题,但useXXXQuery 中的filterByXXX 工作正常。 很高兴你能成功!请参阅我对***.com/questions/20127660/… 的回答以解决 where() 问题。 我的印象是在 2.0 中清除了很多此类行为。像github.com/propelorm/Propel/pull/182 这样的讨论让我觉得升级是值得的。 @chamberlain 您对where 的解决方案实际上也适用于select。感谢您的支持。

以上是关于Propel:从别名连接表中选择列的主要内容,如果未能解决你的问题,请参考以下文章

使用 mysql 别名从 2 个表中选择列

PostgreSQL - 从连接表中选择聚合列并使用它来求和

2020年2月22日-日报

如何使用 Nhibernate 从连接两个具有所有 id 的表中选择只有一个不同列的多个列是 UNIQUEIDENTIFIER

在 SQL 视图中的列选择中使用左连接别名

使用 ActiveRecord 语法从 Rails 中的连接表中选择或按列排序