UNION ALL运算符的意外行为

时间:2016-05-12 07:35:34

标签: php mysql union union-all

我有以下MySql表。

tblUsg定义如下:

CREATE TABLE `tblUsg` (
`id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`ip` VARCHAR(46) NOT NULL,
`dtm` DATETIME NOT NULL,
`huid` BINARY(32) NOT NULL,
`licnm` VARCHAR(20) NOT NULL,
`lichld` VARCHAR(256) NOT NULL,
`flgs` INT NOT NULL,
`agnt` VARCHAR(256),

INDEX `ix_huid` (`huid`),
INDEX `ix_licnm` (`licnm`),
UNIQUE KEY `ix_lichuid` (`huid`, `licnm`)
) AUTO_INCREMENT=0 CHARACTER SET utf8 COLLATE utf8_unicode_ci;

tblLics定义如下:

CREATE TABLE `wosLics` (
`id` INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`licnm` VARCHAR(20) NOT NULL,
`desc` VARCHAR(256) NOT NULL,
`maxcpy` INT NOT NULL,
`dtmFrom` DATETIME,
`dtmTo` DATETIME,
`stat` INT NOT NULL,

UNIQUE KEY `ix_licnm` (`licnm`)
) AUTO_INCREMENT=0 CHARACTER SET utf8 COLLATE utf8_unicode_ci;

然后,当两个表都为空时,我会调用以下PHP脚本:

$link = @mysql_connect($HOSTNAME, $USERNAME, $PASSWD);
@mysql_select_db($DBNAME);
mysql_set_charset('utf8', $link);

$res = @mysql_query(
    "SELECT `maxcpy`, `stat`, `dtmFrom`, `dtmTo` FROM `tblLics` WHERE `licnm`='zbcdefghijklmnopqrsu'\n".
    "UNION ALL\n".
    "SELECT COUNT(*), NULL, NULL, NULL FROM `tblUsg` WHERE `licnm`='zbcdefghijklmnopqrsu'\n".
    "UNION ALL\n".
    "SELECT COUNT(*), NULL, NULL, NULL FROM `tblUsg` WHERE (`licnm`='zbcdefghijklmnopqrsu' AND `huid`='a871c47a7f48a12b38a994e48a9659fab5d6376f3dbce37559bcb617efe8662d')"
    , $link);
if($res)
{
    $row0 = @mysql_fetch_row($res);
    $row1 = @mysql_fetch_row($res);
    $row2 = @mysql_fetch_row($res);

    echo("<br/>0::<br/>");
    var_dump($row0);
    echo("<br/>1::<br/>");
    var_dump($row1);
    echo("<br/>2::<br/>");
    var_dump($row2);
}

哪个输出:

0::
array(4) { [0]=> string(1) "0" [1]=> NULL [2]=> NULL [3]=> NULL } 
1::
array(4) { [0]=> string(1) "0" [1]=> NULL [2]=> NULL [3]=> NULL } 
2::
bool(false)

我的问题是$row2 false$row1是数组的时候{{1}}为什么我会预料到的?

1 个答案:

答案 0 :(得分:1)

  

我的问题是,$row2假设$row1为数组的原因是错误的?

您希望从查询中返回3行,但它只返回2行。

您的查询UNION三个SELECT。最后两个SELECT中的每一个总是返回一行。第一个SELECT可以返回0行或更多行。因为表是空的,所以它只返回零行。

0+1+1。该查询会准确返回2行。

<强>更新

您希望按特定顺序返回行,但查询不需要任何排序。 SQL使用行集,而作为数学对象的集合是未排序的集合(这就是SQL处理它们的方式)。

如果查询中没有ORDER BY,则UNION返回的行不保证以任何顺序返回。甚至它们来自SELECT的订单也没有保留。

如果您想按照编写SELECT查询的顺序获取行,那么您必须添加一个额外的列来告诉订单并在ORDER BY子句中使用:

SELECT `maxcpy`, `stat`, `dtmFrom`, `dtmTo`, 1 AS tableNb
FROM `tblLics`
WHERE `licnm`='zbcdefghijklmnopqrsu'

UNION ALL

SELECT COUNT(*), NULL, NULL, NULL, 2 AS tableNb
FROM `tblUsg`
WHERE `licnm`='zbcdefghijklmnopqrsu'

UNION ALL

SELECT COUNT(*), NULL, NULL, NULL, 3 AS tableNb
FROM `tblUsg`
WHERE `licnm`='zbcdefghijklmnopqrsu'
  AND `huid`='a871c47a7f48a12b38a994e48a9659fab5d6376f3dbce37559bcb617efe8662d'

ORDER BY tableNb

通过这种方式,您可以了解查询的哪一部分生成了每个返回的行。

<强> 备注

您不需要第二个查询返回的行。它基本上告诉您第一个查询返回了多少行,但您也可以通过计算结果集中具有tableNb == 1的行来了解它。由于您希望计数 实际行后,它不需要对结果集进行额外遍历,因此可以在列出第一个查询中的行时完成。