概括
我有一张成对的物品表。我想自己加入它,这样我就可以在一个查询中检索这对的两边。这是有效的 SQL(我认为),SQLite 引擎确实接受它,但我无法让 DBIx::Class 硬着头皮。
最小的例子
package Schema::Half;
use parent 'DBIx::Class';
__PACKAGE__->load_components('Core');
__PACKAGE__->table('half');
__PACKAGE__->add_columns(
whole_id => { data_type => 'INTEGER' },
half_id => { data_type => 'CHAR' },
data => { data_type => 'TEXT' },
);
__PACKAGE__->has_one(dual => 'Schema::Half', {
'foreign.whole_id' => 'self.whole_id',
'foreign.half_id' => 'self.half_id',
# previous line results in a '='
# I'd like a '<>'
});
package Schema;
use parent 'DBIx::Class::Schema';
__PACKAGE__->register_class( 'Half', 'Schema::Half' );
package main;
unlink 'join.db';
my $s = Schema->connect('dbi:SQLite:join.db');
$s->deploy;
my $h = $s->resultset('Half');
$h->populate([
[qw/whole_id half_id data /],
[qw/1 L Bonnie/],
[qw/1 R Clyde /],
[qw/2 L Tom /],
[qw/2 R Jerry /],
[qw/3 L Batman/],
[qw/3 R Robin /],
]);
$h->search({ 'me.whole_id' => 42 }, { join => 'dual' })->first;
最后一行生成以下 SQL:
SELECT me.whole_id, me.half_id, me.data
FROM half me
JOIN half dual ON ( dual.half_id = me.half_id AND dual.whole_id = me.whole_id )
WHERE ( me.whole_id = ? )
我正在尝试使用 DBIx::Class 连接语法在and<>
之间获取运算符,但到目前为止还没有成功。dual.half_id
me.half_id
我尝试过的事情
文档提示 SQL::Abstract-like 语法。
我试着has_one
这样写关系:
__PACKAGE__->has_one(dual => 'Schema::Half', {
'foreign.whole_id' => 'self.whole_id',
'foreign.half_id' => { '<>' => 'self.half_id' },
});
# Invalid rel cond val HASH(0x959cc28)
stringref 后面的直接 SQL 也不行:
__PACKAGE__->has_one(dual => 'Schema::Half', {
'foreign.whole_id' => 'self.whole_id',
'foreign.half_id' => \'<> self.half_id',
});
# Invalid rel cond val SCALAR(0x96c10b8)
解决方法以及为什么它们对我来说不够
我可以通过复杂的search()
调用生成正确的 SQL,并且没有定义的关系。它非常难看,有(太多)硬编码的 SQL。对于遍历关系的每个特定情况,它必须以不可分解的方式进行模仿。
我可以通过添加一other_half_id
列并加入其中=
来解决这个问题。这显然是冗余数据。
CREATE VIEW AS SELECT *, opposite_of(side) AS dual FROM half...
我什至试图通过专用视图search()
(最后我没有足够的勇气让它工作。
希望的 SQL
这是我正在寻找的那种 SQL。请注意,这只是一个示例:我真的希望它通过关系完成,因此Half
除了search()
'join
子句之外,我也可以将它用作 ResultSet 访问器。
sqlite> SELECT *
FROM half l
JOIN half r ON l.whole_id=r.whole_id AND l.half_id<>r.half_id
WHERE l.half_id='L';
1|L|Bonnie|1|R|Clyde
2|L|Tom|2|R|Jerry
3|L|Batman|3|R|Robin
旁注
在我的完整扩展案例中,我真的加入了自我,但我很确定这不是问题。我把它保留在这里是为了减少大小写,因为它也有助于保持代码的大小。
我坚持加入/关系路径而不是复杂路径,search()
因为我有多种用途用于关联,而且我没有找到任何“一刀切”的搜索表达式。
延迟更新
两年后回答我自己的问题,它曾经是一个缺失的功能,此后一直在实施。