用于动态创建的一组条件中的嵌套查询的 Perl DBIC
Perl DBIC for nested queries in a dynamically created set of conditions
简介
我正在处理一个复杂的表单来对相当大的数据库执行自定义查询。因为用户可以使用一个或多个字段来搜索,所以我决定让条件动态化,比如:
my $where{};
if($some_param && some_param ne ''){
push @{ $attr->{join} }, { 'aref' => { 'a_deeper_ref' => 'a_much_deeper_ref' }};
$where->{a_much_deeper_ref.field} = [-and => $some_param, {'!=', undef}];
}
if($another_param && $another_param ne '') {
... # same thing: do the join > build the condition.
}
my $rs = $model->search ($where, $attr);
大约有 40-50 个字段,虽然我可以像上面那样处理其中的大部分,但有几个字段有点棘手......
**问题**
我将使用有问题的示例使其更清楚。假设你有一个 laboratory_exams
table,其中的行说明给定的 subject/patient [subject
table] 的外键已经针对给定的临床检查进行了测试[外键 clinical_exam
table] 并存储该测试的结果。
现在,当用户想知道哪些受试者已经接受过 HIV 和丙型肝炎检测,并且 HIV 检测结果为阴性而丙型肝炎检测结果为阳性时;表单提交将创建一个包含 exam_ids
和 results
的数组,我可以在我的控制器中轻松检索它,例如
my $params = $c->req->parameters;
my @labexams = ref $params->{exam_ids} ? @{$params->{exam_ids}} : $params->{exam_ids};
my @results = ref $params->{results} ? @{$params->{results}} : $params->{results};
当然,当我尝试在 $where
散列循环数组中保存条件时,它会覆盖前一个,我最终只得到数组中的最后一个元素,因为...
foreach my $i (0 .. $#labexams){
$where->{'labexams.exam_id'} = $labexams[$i];
$where->{'labexams.result'} = $results[$i];
}
... 我一直在 'labexams.exam_id' 或 'labexams.result' 上写下我的条件,它们是静态的。
请注意,我需要结果 SQL 类似于
... WHERE (labexams.exam_id = $labexam[$i] AND labexams.result = $result[$i]) AND ... #repeat for every exam/result pair
实际问题
我到底怎样才能做到这一点?
使用 ResultSet 搜索链接功能,而不是自己构造复杂的 where 参数。
my $rs = ResultSet('Foo')->search(...);
$rs = $rs->search(...);
我最终为子查询构建了一个 SQL 表达式,并将其作为对 $where 哈希的引用传递。像魅力一样工作 <3
if ($params->{labexam} && $params->{labexam} ne '' ){
my @labexams = ref $params->{labexam} ? @{$params->{labexam}} : $params->{labexam};
my @labexam_res = ref $params->{labexam_result} ? @{$params->{labexam_result}} : $params->{labexam_result};
my $exp_sql;
push @{ $attr->{join} }, 'laboratory_exams';
foreach my $i (0 .. $#labexams){
if($i == 0) {
$exp_sql .= ' IN ';
} else {
$exp_sql .= ' AND laboratory_exams.subject_id IN ';
}
$exp_sql .= '(SELECT subject_id FROM laboratory_exams WHERE exam_id = "'.$labexams[$i].'" AND value = "'.$labexam_res[$i].'")';
$i++;
}
$where->{'laboratory_exams.subject_id'} = $exp_sql;
}
简介
我正在处理一个复杂的表单来对相当大的数据库执行自定义查询。因为用户可以使用一个或多个字段来搜索,所以我决定让条件动态化,比如:
my $where{};
if($some_param && some_param ne ''){
push @{ $attr->{join} }, { 'aref' => { 'a_deeper_ref' => 'a_much_deeper_ref' }};
$where->{a_much_deeper_ref.field} = [-and => $some_param, {'!=', undef}];
}
if($another_param && $another_param ne '') {
... # same thing: do the join > build the condition.
}
my $rs = $model->search ($where, $attr);
大约有 40-50 个字段,虽然我可以像上面那样处理其中的大部分,但有几个字段有点棘手......
**问题**
我将使用有问题的示例使其更清楚。假设你有一个 laboratory_exams
table,其中的行说明给定的 subject/patient [subject
table] 的外键已经针对给定的临床检查进行了测试[外键 clinical_exam
table] 并存储该测试的结果。
现在,当用户想知道哪些受试者已经接受过 HIV 和丙型肝炎检测,并且 HIV 检测结果为阴性而丙型肝炎检测结果为阳性时;表单提交将创建一个包含 exam_ids
和 results
的数组,我可以在我的控制器中轻松检索它,例如
my $params = $c->req->parameters;
my @labexams = ref $params->{exam_ids} ? @{$params->{exam_ids}} : $params->{exam_ids};
my @results = ref $params->{results} ? @{$params->{results}} : $params->{results};
当然,当我尝试在 $where
散列循环数组中保存条件时,它会覆盖前一个,我最终只得到数组中的最后一个元素,因为...
foreach my $i (0 .. $#labexams){
$where->{'labexams.exam_id'} = $labexams[$i];
$where->{'labexams.result'} = $results[$i];
}
... 我一直在 'labexams.exam_id' 或 'labexams.result' 上写下我的条件,它们是静态的。
请注意,我需要结果 SQL 类似于
... WHERE (labexams.exam_id = $labexam[$i] AND labexams.result = $result[$i]) AND ... #repeat for every exam/result pair
实际问题
我到底怎样才能做到这一点?
使用 ResultSet 搜索链接功能,而不是自己构造复杂的 where 参数。
my $rs = ResultSet('Foo')->search(...); $rs = $rs->search(...);
我最终为子查询构建了一个 SQL 表达式,并将其作为对 $where 哈希的引用传递。像魅力一样工作 <3
if ($params->{labexam} && $params->{labexam} ne '' ){
my @labexams = ref $params->{labexam} ? @{$params->{labexam}} : $params->{labexam};
my @labexam_res = ref $params->{labexam_result} ? @{$params->{labexam_result}} : $params->{labexam_result};
my $exp_sql;
push @{ $attr->{join} }, 'laboratory_exams';
foreach my $i (0 .. $#labexams){
if($i == 0) {
$exp_sql .= ' IN ';
} else {
$exp_sql .= ' AND laboratory_exams.subject_id IN ';
}
$exp_sql .= '(SELECT subject_id FROM laboratory_exams WHERE exam_id = "'.$labexams[$i].'" AND value = "'.$labexam_res[$i].'")';
$i++;
}
$where->{'laboratory_exams.subject_id'} = $exp_sql;
}