Dan*_*mer 6 sql perl join dbix-class
我想从表中检索行,DBIx::Class并从同一个表中预取相应的行,其中列具有特定的其他值.我需要从计划A中获取所有作业(复制它们)并从计划B中检索所有相应的作业.
我已经编制了测试表,看起来像这样:
CREATE TABLE tasks (
id INTEGER
);
CREATE TABLE schedules (
id INTEGER
);
CREATE TABLE assignments (
id INTEGER,
scheduleId INTEGER,
taskId INTEGER,
worker TEXT,
FOREIGN KEY (scheduleId) REFERENCES schedules(id),
FOREIGN KEY (taskId) REFERENCES tasks(id)
);
Run Code Online (Sandbox Code Playgroud)
计划1有一些任务,计划2有一些任务:
INSERT INTO tasks (id) VALUES (1);
INSERT INTO tasks (id) VALUES (2);
INSERT INTO schedules (id) VALUES (1);
INSERT INTO schedules (id) VALUES (2);
INSERT INTO assignments (id,scheduleId,taskId,worker) VALUES (1,1,1,"Alice");
INSERT INTO assignments (id,scheduleId,taskId,worker) VALUES (2,1,2,"Bob");
INSERT INTO assignments (id,scheduleId,taskId,worker) VALUES (3,2,1,"Charly");
Run Code Online (Sandbox Code Playgroud)
这是一些返回所需结果的SQL:
SELECT * FROM assignments AS a1
LEFT OUTER JOIN assignments AS a2 ON
a2.scheduleId = 2 AND
a2.taskId = a1.taskId
WHERE a1.scheduleId = 1;
Run Code Online (Sandbox Code Playgroud)
在SQLite中,这可以按预期工作:结果显示了来自计划1的每个分配和来自计划2的相应分配的一行.
id|scheduleId|taskId|worker|id|scheduleId|taskId|worker
1|1|1|Alice|3|2|1|Charly
1|1|2|Bob|NULL|NULL|NULL|NULL
Run Code Online (Sandbox Code Playgroud)
到目前为止,我尝试使用DBIx :: Class不起作用.这是作业的类看起来像:
package MyApp::Schema::Result::Assignment;
...
__PACKAGE__->has_many(
inAllSchedules => 'MyApp::Schema::Result::Assignment',
{
'foreign.taskId' => 'self.taskId',
}
);
Run Code Online (Sandbox Code Playgroud)
以下代码正确连接行但仅返回计划1中的行,这些行实际上具有计划2中的相应行:
my $assignments = $schema->resultset('Assignment')->search({
'inAllSchedules.scheduleId' => 2,
}, {
prefetch => 'inAllSchedules',
});
Run Code Online (Sandbox Code Playgroud)
此代码也正确地correclty连接行并返回没有连接行的行,但我不知道如何过滤连接的行.我不想检索计划3等行或任何其他行......
my $assignments = $schema->resultset('Assignment')->search(undef, {
join_type => 'left outer',
prefetch => 'inAllSchedules',
});
Run Code Online (Sandbox Code Playgroud)
我无法编写特定的关系,因为时间表A或B的ID仅在运行时给出.
如何生成给定的SQL代码或以其他方式检索数据?
这看起来像是自定义连接条件的情况。下面的解决方案适用于您有限的示例,但可能需要针对您的实际应用程序进行调整。
__PACKAGE__->has_many(
'inAllSchedules' => "MyApp::Schema::Result::Assignment",
sub {
my $args = shift;
return {
"$args->{foreign_alias}.taskId" => { '-ident' => "$args->{self_alias}.taskId" },
"$args->{foreign_alias}.id" => { '<>' => { '-ident' => "$args->{self_alias}.id" } },
};
}
);
Run Code Online (Sandbox Code Playgroud)
你会像这样使用它:
my $assignments = $schema->resultset("Assignment")->search({
'me.scheduleId' => 1,
'inAllSchedules.scheduleId' => [ 2, undef ],
},
{
'prefetch' => "inAllSchedules",
});
Run Code Online (Sandbox Code Playgroud)