TL;DR:我如何修改下面的queryOfQuery()
函数以与OCI8/Oracle后端一起工作?
在寻找与CFML的查询的查询相同的PHP时,我遇到了这个问题,它指向Tom Muck写的一个函数:
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替代。代入的等价物是什么?还有什么需要调整的吗?
修改函数以使用OCI是微不足道的,但不幸的是,您失去了从结果集中重复获取的能力。
我已经在下面发布了完整的函数,但只有三行需要改变。我已经注释掉了现有的行,以显示更改的位置。
对mysql_data_seek()
的调用被简单地移除。如果已经执行了任何提取,第一个调用将结果集指针重置为第一个记录。这确保"子查询"获得所有适用的记录。第二次调用再次重置指针,以确保函数执行后的进一步处理将从结果集的开头开始。
我查看了OCI8函数列表,但看不到重置指针的任何等效函数。我认为你可以使用游标,但我不懂PL/SQL,所以不能给你任何帮助。
总之,你可以"查询一个查询",但有两个注意事项:
- 在调用函数之前获取的任何行将不包括在内。
- 不能在函数运行后从结果集中获取。
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在术语和方法上存在差异。汤姆·穆克似乎误解了这些区别,因此无意中歪曲了他的函数是如何工作的。
阅读完CFML帮助文档后,我相信CFML 中的查询隐式将所有行获取到web服务器内存中。这就是允许结果集被再次"查询"而不与数据库服务器通信的原因。
在PHP中,开发人员选择的函数控制这个行为(所以s/他做了一个显式的选择)。标准行为将是(为了简洁而简化):
- 打开数据库连接
- 执行查询
- 检索结果集
步骤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;
};