1

我从一个很长的查询中得到了一个奇怪的结果,我将在这里简化:

DROP TEMPORARY TABLE IF EXISTS table1;
CREATE TEMPORARY TABLE table1 AS
(SELECT 
parent.id as parent_id,
times.a_time,
times.sequence,
FROM times
LEFT JOIN parent ON times.parent_id=parent.id
WHERE times.stop_id=10);

DROP TEMPORARY TABLE IF EXISTS table2;
CREATE TEMPORARY TABLE table2 AS
(SELECT 
parent.id as parent_id,
times.b_time,
times.sequence,
FROM times
LEFT JOIN parent ON times.parent_id=parent.id
WHERE times.stop_id=15 );

--here comes PDO->exec();

SELECT table1.*, table2.b_time
FROM table1
LEFT JOIN table2 ON table1.parent_id=table2.parent_id
WHERE table2.parent_id IS NOT NULL AND table1.sequence<table2.sequence
ORDER BY table1.a_time

我正在使用 EMS MySQL Manager 2007 测试查询,而在 PHP 中我正在使用 PDO 查询。

为了获得最终结果,(我知道 PDO 不支持一次运行此完整查询并返回结果集),我PDO->exec()在创建临时表后运行(请参阅查询中的注释),然后继续PDO->query()运行最后一个SELECT

$db = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME, DB_USER, DB_PASS);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

$tempTablesSQL='DROP TEMPORARY TABLE IF EXISTS...'; //create temporary tables
$db->exec($tempTablesSQL);

$sql='SELECT table1.*, table2.b_time ...'; //JOIN and SELECT the results
$results=array();
foreach($db->query($sql) as $row){
  $results[]=$row;
}

print_r($results);

在 MySQL Manager 中,我一次运行整个查询,对于那些特定的 ID,我得到 29 行作为结果(这是正确的,因为记录是从以前解析的文件中插入的,并且通过将结果与我知道的文件进行比较他们很好)。

但在 PHP 中,我只得到 25 个结果,而且b_time.

所以,我的问题是:

  • 为什么我会得到错误的结果?

  • 我调用此查询的方法是否错误(在 PHP 中)?

任何帮助表示赞赏。

--编辑--

这不仅仅是 PDO,我尝试使用 mysqli_multi_query,我得到了同样的错误结果。

我注意到的一件重要的事情是:如果我使用常规表而不是临时表,结果很好。

4

1 回答 1

0

让我尝试对您问题的第二部分提出一些建议,这是我将此查询称为错误的方法吗?

首先,看起来您不需要创建任何临时表。根据您展示的内容,整个事情可以是一个单一的查询,例如

SELECT q1.parent_id, q1.a_time, q1.sequence, q2.b_time
  FROM
(
    SELECT p.id parent_id, t.a_time, t.sequence
      FROM times t LEFT JOIN parent p
        ON t.parent_id=p.id
     WHERE t.stop_id = ?
 ) q1 LEFT JOIN
(
    SELECT p.id as parent_id, t.b_time, t.sequence
      FROM times t LEFT JOIN parent p
        ON t.parent_id=parent.id
     WHERE t.stop_id = ?
) q2 ON q2.parent_id IS NOT NULL 
    AND q1.sequence < q2.sequence
 ORDER BY q1.a_time

并将其作为准备好的语句执行

...
$sql = 'SELECT ...'; // the whole thing from above
$query = $db->prepare($sql);
$query->execute(array($stop_id1, $stop_id2));
$result = $query->fetchAll(PDO::FETCH_ASSOC);

var_dump($result);

现在,即使由于某种原因您必须使用临时表并在返回结果集之前执行一些操作,那么我建议将其包装为存储过程

DELIMITER $$
CREATE PROCEDURE sp_myproc (IN stop_id1 INT, IN stop_id2 INT, ...)
BEGIN
    DROP TEMPORARY TABLE IF EXISTS table1;
    CREATE TEMPORARY TABLE table1 AS
    ...
    WHERE times.stop_id = stop_id1;

    DROP TEMPORARY TABLE IF EXISTS table1;
    CREATE TEMPORARY TABLE table1 AS
    ...
    WHERE times.stop_id = stop_id2

    -- return the resultset
    SELECT table1.*, table2.b_time
    FROM table1
    ...
END$$
DELIMITER ;

并从 php 调用一次您的程序

...
$sql = 'CALL sp_myproc(?, ?)';
$query = $db->prepare($sql);
$query->execute(array($stop_id1, $stop_id2));
$result = $query->fetchAll(PDO::FETCH_ASSOC);

var_dump($result);

现在关于您问题的第一部分,为什么我会得到错误的结果? OUTER连接可能会很棘手,尤其是在链接它们时。您可以轻松过滤掉一些行或生成额外的行(这种情况最常发生)。

您删除的那几个连接可能是原因。

无论如何,提供的信息不足以得出结论性的答案。

但我建议不要返回列,因为table1.*明确指定所有列,并为在作为连接的一部分的不同表中具有相同名称的列提供明确的别名。

于 2013-06-17T01:02:46.340 回答