用于动态创建的一组条件中的嵌套查询的 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_idsresults 的数组,我可以在我的控制器中轻松检索它,例如

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;
}