2016-05-12 37 views
0

我有以下MySql表。UNION ALL运算符的意外行为

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) 

我的问题是,为什么我的$row2false$row1是因为我会一直期待的阵列?

+1

是吗?你有没有满足第一个查询中的where条件的记录?对于空结果和两个记录集,每个记录有1条记录,您的预期输出是什么? – Pred

+0

@Pred:不,表格最初是空的。在那种情况下,我希望我的'$ row0'是'false'。情况并非如此吗? – c00000fd

+0

为什么?空+某物=某物。 SQL不会仅仅因为你在某个地方有一个空集而重新索引结果。 SQL应该如何知道第一个查询是否应该返回1或2或者没有或10k记录?它应该在何处重新索引记录(并在第一条记录之前填写所有内容)? – Pred

回答

1

我的问题是,为什么我的$row2是假的时$row1在阵列,因为我会一直期待?

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

您的查询UNION s三SELECT s。最后两个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的行进行计数来知道。由于您希望之后的实际行数为,因此不需要额外遍历结果集,因此可以在列出第一个查询中的行时完成。

+0

谢谢。我想我误解了'UNION ALL'中的'ALL'的含义。我的假设是它也会包含NULL。坏了。所以我的建筑几乎没用。所以我必须把它分成3个独立的'mysql_query'调用。螺杆并发。 – c00000fd

+0

“UNION ALL”的“ALL”部分不会删除重复的行。但是第一个'SELECT'不返回任何行。如果它返回一行充满NULL的行,那行就会被返回到最终结果集中。 – axiac