2

我有 2 张桌子。表格具有相同的列,我需要比较它们。简单的联接查询无法解决我的问题,因为 table2 可以包含许多适合表 1 的行,但我需要选择最合适的行。例如 :

表格1

期间; 价格; 数字;
1个;3;5个;


表 2

期间; 价格; 数字;
1个;3.1;5个;
1个;3.01; 5个;

我需要将 table1 中的 row1 与表 2 中的 row1 和 row2 进行比较,然后选择最合适的(例如 row2 是最合适的)并将 row2 标记为已比较,下次不要进行比较。我正在使用 FIREBIRD 数据库和 ADODB php 库。我写了一些代码,但是当我在表中有很多记录时,它可以工作很长时间。如何优化我的代码以更快地完成这项任务?

代码:

$this->connect->BeginTrans();
        $sourceResult = $this->connect->Execute( "SELECT SC_PHONE_NUMBER, SC_CALL_START, SC_DURATION, SC_RATE, SC_ID  FROM ". $this->sourceTableName . " WHERE sc_comparing_id = " . $this->insertedId );

        if ( $sourceResult ) {

            while ( !$sourceResult->EOF ) {
                $result = array();

                $comparationResult = $this->connect->Execute(
                    "SELECT CC_PHONE_NUMBER, CC_CALL_START, CC_DURATION, CC_RATE, CC_ID  FROM " . $this->comparableTableName . " WHERE cc_comparing_id = " . $this->insertedId
                    .   " AND cc_is_compared  = 0"
                    .   " AND cc_phone_number = " . $sourceResult->fields['SC_PHONE_NUMBER']
                    .   " AND " .  $sourceResult->fields['SC_CALL_START'] . " BETWEEN cc_call_start - " . TIME_RANGE . " AND " . " cc_call_start + " . TIME_RANGE
                );


                if ( $comparationResult ) {

                    while ( !$comparationResult->EOF ) {

                        $callStartRating = TIME_RANGE / ( TIME_RANGE + abs( $sourceResult->fields['SC_CALL_START'] - $comparationResult->fields['CC_CALL_START'] ) );
                        $durationRating = 0;
                        $rateRating = 0;

                        if ( $sourceResult->fields['SC_DURATION'] > $comparationResult->fields['CC_DURATION'] ) {
                            $durationRating = $comparationResult->fields['CC_DURATION'] / $sourceResult->fields['SC_DURATION'];
                        } else {
                            $durationRating = $sourceResult->fields['SC_DURATION'] / $comparationResult->fields['CC_DURATION'];
                        }

                        if ( $sourceResult->fields['SC_RATE'] > $comparationResult->fields['CC_RATE'] ) {
                            $rateRating = $comparationResult->fields['CC_RATE'] / $sourceResult->fields['SC_RATE'];
                        } else {
                            $rateRating = $sourceResult->fields['SC_RATE'] / $comparationResult->fields['CC_RATE'];
                        }

                        $totalRating = $rateRating + $durationRating + $callStartRating;
                        $result[]  =  array(
                            'sc_id' =>  $sourceResult->fields['SC_ID'],
                            'cc_id' =>  $comparationResult->fields['CC_ID'],
                            'rating' => $totalRating
                        );
                        $comparationResult->MoveNext();
                    }

                    $resArray = null;

                    if ( count( $result ) >= 1 ) {

                        $resArray = $result[0];

                        foreach ( $result as $row ) {
                            if ( $resArray['rating'] < $row['rating'] ) {
                                $resArray = $row;
                            }
                        }
                        $query = "UPDATE source_cdr SET sc_cc_key = " . $row['cc_id'] . " WHERE sc_id = " . $row['sc_id'];

                        $this->connect->_Execute( $query );
                        $this->connect->_Execute( "UPDATE comparable_cdr SET cc_is_compared = 1 WHERE cc_id = " . $resArray['cc_id'] );

                    }
                }
                $this->connect->CommitTrans();
                $sourceResult->MoveNext();
            }
4

2 回答 2

1

不是您想要的答案,但为了使其更快,您应该尝试在 SQL 中回答这个问题。在您的顶级示例中,您会执行类似的操作

Select FIRST 1 duration, price, number
from tablea a
join tableb b on a.duration=b.duration and a.number = b.number
where b.price>=a.price

现在我确信你的表结构和比较更复杂,也许你可以分享更多的数据结构和比较规则,这里的人可以提供帮助。

另一种可能会有所帮助但并不理想的方法是,确保您正在订购数据,如果发生最小比较,请退出循环。

于 2013-09-19T14:07:48.677 回答
1

您只需一个查询即可从可比较表中获得“最佳”条目。

SELECT *
  FROM `comparable_table`
  ORDER BY ABS(CAST("3.00" AS DECIMAL) - `price`)
  LIMIT 1

值“3.00”来自源表中的一行。

对于大型表,此查询很慢。

如果你有一张大桌子试试这个:

SELECT *
  FROM
  (
    (
      SELECT *
        FROM `comparable_table`
        WHERE `price` >= CAST("3.00" AS DECIMAL)
        ORDER BY `price`
        LIMIT 1
    )  
    UNION DISTINCT
    (
      SELECT *
        FROM `comparable_table`
        WHERE `price` <= CAST("3.00" AS DECIMAL)
        ORDER BY `price` DESC
        LIMIT 1
    )
  ) AS `min_max`
  ORDER BY ABS(CAST("3.00" AS DECIMAL) - `price`)
  LIMIT 1

如果您在price此查询上添加索引,请使用它,它在大型表上应该更快。

于 2013-09-19T14:19:23.257 回答