PHP版的QueryofQuery

时间:2014-07-03 18:49:51

标签: php oracle oci8

TL; DR:如何修改下面的queryOfQuery()函数以使用OCI8 / Oracle后端?

在寻找与CFML's query of queries等效的PHP时,我遇到了this question,它指向a function Tom Muck had written

function queryOfQuery($rs, // The recordset to query
  $fields = "*", // optional comma-separated list of fields to return, or * for all fields 
  $distinct = false, // optional true for distinct records
  $fieldToMatch = null, // optional database field name to match
  $valueToMatch = null) { // optional value to match in the field, as a comma-separated list

  $newRs = Array();
  $row = Array();
  $valueToMatch = explode(",",$valueToMatch);
  $matched = true;
  mysql_data_seek($rs, 0);
  if($rs) {
    while ($row_rs = mysql_fetch_assoc($rs)){
      if($fields == "*") {
        if($fieldToMatch != null) {
          $matched = false;
          if(is_integer(array_search($row_rs[$fieldToMatch],$valueToMatch))){ 
            $matched = true;
          }
        }
        if($matched) $row = $row_rs;
      }else{
        $fieldsArray=explode(",",$fields);
        foreach($fields as $field) {
          if($fieldToMatch != null) {
            $matched = false;
            if(is_integer(array_search($row_rs[$fieldToMatch],$valueToMatch))){ 
              $matched = true;
            }
          }
          if($matched) $row[$field] = $row_rs[$field];
        }
      } 
      if($matched)array_push($newRs, $row);
    };
    if($distinct) {
      sort($newRs);
      for($i = count($newRs)-1; $i > 0; $i--) {
        if($newRs[$i] == $newRs[$i-1]) unset($newRs[$i]);
      }
    }
  }
  mysql_data_seek($rs, 0);
  return $newRs;
}

我想调整此代码以适应我们的数据库环境(我们使用Oracle和OCI8 - 而不是MySQL,为其编写函数)。不幸的是,我新生的PHP技能让我不能胜任这项任务。具体来说,我可以看到mysql_data_seek()mysql_fetch_assoc()可能是其OCI8对手替代的候选者。什么是插件的等价物?还有什么我需要调整的吗?

1 个答案:

答案 0 :(得分:1)

修改函数以使用OCI是微不足道的,但遗憾的是,您无法重复从结果集中获取。

我已经发布了下面的完整功能,但只需要更改三行。我已经注释掉现有的行以显示更改的位置。

只需删除对mysql_data_seek()的来电。第一次调用将结果集指针重置为第一条记录,以防任何已经执行过任何提取。这可确保“子查询”获取所有适用的记录。第二次调用再次重置指针,以确保函数执行后的进一步处理将从结果集的开头开始。

我查看了OCI8 function list,但看不到重置指针的等效内容。我认为你可以使用游标,但我不知道PL / SQL所以不能在那里给你任何帮助。

总而言之,您可以“查询查询”,但有两点需要注意:

  1. 将不包括在调用函数之前获取的任何行。
  2. 在函数运行后无法从结果集中获取。

  3. function queryOfQuery($rs, // The recordset to query
      $fields = "*", // optional comma-separated list of fields to return, or * for all fields 
      $distinct = false, // optional true for distinct records
      $fieldToMatch = null, // optional database field name to match
      $valueToMatch = null) { // optional value to match in the field, as a comma-separated list
    
      $newRs = Array();
      $row = Array();
      $valueToMatch = explode(",",$valueToMatch);
      $matched = true;
      //mysql_data_seek($rs, 0);
      if($rs) {
        //while ($row_rs = mysql_fetch_assoc($rs)){
        while ($row_rs = oci_fetch_assoc($rs)){
          if($fields == "*") {
            if($fieldToMatch != null) {
              $matched = false;
              if(is_integer(array_search($row_rs[$fieldToMatch],$valueToMatch))){ 
                $matched = true;
              }
            }
            if($matched) $row = $row_rs;
          }else{
            $fieldsArray=explode(",",$fields);
            foreach($fields as $field) {
              if($fieldToMatch != null) {
                $matched = false;
                if(is_integer(array_search($row_rs[$fieldToMatch],$valueToMatch))){ 
                  $matched = true;
                }
              }
              if($matched) $row[$field] = $row_rs[$field];
            }
          } 
          if($matched)array_push($newRs, $row);
        };
        if($distinct) {
          sort($newRs);
          for($i = count($newRs)-1; $i > 0; $i--) {
            if($newRs[$i] == $newRs[$i-1]) unset($newRs[$i]);
          }
        }
      }
      //mysql_data_seek($rs, 0);
      return $newRs;
    }
    

    编辑: 我已经深入研究了这一点,我认为由于术语和方法之间的差异,这对CFML开发人员来说是误导性的PHP和CFML。 Tom Muck似乎误解了这些差异,因此无意中歪曲了他的功能如何运作。

    阅读CFML help doc you linked后,我认为CFML 中的查询隐式将所有行提取到Web服务器内存中。这样就可以在不与数据库服务器通信的情况下再次“查询”结果集。

    在PHP中,开发人员选择函数控制此行为(因此他/她做出了显式选择)。标准行为(简化为简洁):

    1. 打开与数据库的连接
    2. 执行查询
    3. 检索结果集
    4. 通常,迭代地执行步骤3;一次从数据库中提取和处理一行(与Tom的函数完全相同)。但是也可以将整个结果集提取到Web服务器内存中,然后进行处理。对于OCI,这将是oci_fetch_all(),它返回一个2D数组。这正是Tom误解PHP行为的地方。

      这意味着原始函数不提供与CFML开发人员描述或预期相同的功能。要做到这一点,您需要将所有数据提取到一个数组中然后迭代它。最后,这取决于开发人员的偏好以及潜在的性能优化。你:

      • 获取并处理每一行,保持较低的内存使用率,但由于不断从数据库服务器接收,可能会导致性能下降。
      • 获取所有行,可能使用大量内存,但也可以直接从Web服务器内存中查看可能的性能改进。

      最后,除非您以非常大的规模运行Web应用程序,否则我会说性能差异可以忽略不计。


      编辑2:

      这个调整过的queryOfQuery函数没有绑定到任何特定的数据库;它遍历给定的数组(rs),无论它是如何生成的:

      function queryOfQuery(
          $rs, // The recordset to query
          $fields = "*", // optional comma-separated list of fields to return, or * for all fields 
          $distinct = false, // optional true for distinct records
          $fieldToMatch = null, // optional database field name to match
          $valueToMatch = null // optional unless $fieldToMatch is specified; value to match in the field, as a comma-separated list
      ) {
      
          $newRs = Array();
          $row = Array();
          $valueToMatch = explode(",",$valueToMatch);
          $matched = true;
          if($rs) {
              // $issue$ this loop over the results should be moved to lines 20 and 31
      
              foreach($rs AS $row_rs){
                  if($fields == "*") {
                      if($fieldToMatch != null) {
                          $matched = false;
                          if(is_integer(array_search($row_rs[$fieldToMatch],$valueToMatch))){ 
                              $matched = true;
                          };
                      };
                      if($matched) $row = $row_rs;
                  }
                  else {
                      $fieldsArray=explode(",",$fields);
                      foreach($fieldsArray as $field) {
                          if($fieldToMatch != null) {
                              $matched = false;
                              if(is_integer(array_search($row_rs[$fieldToMatch],$valueToMatch))){ 
                                  $matched = true;
                              };
                          };
                          if($matched) $row[$field] = $row_rs[$field];
                      };
                  };
                  if($matched)array_push($newRs, $row);
              };
      
              if($distinct) {
                  sort($newRs);
                  for($i = count($newRs)-1; $i > 0; $i--) {
                      if($newRs[$i] == $newRs[$i-1]) unset($newRs[$i]);
                  };
              };
          };
          return $newRs;
      };