UNION ALL 运算符的意外行为
Unexpected behavior of UNION ALL operator
我有以下 MySql tables.
Table 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;
和table 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 脚本,例如,两个 table 都是空的:
$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
是我预期的数组?
My question is why my $row2
is false when $row1
is the array as I would've expected?
您希望从查询中返回 3 行,但它只有 returns 2 行。
您的查询 UNION
三 SELECT
。最后两个 SELECT
中的每一个总是 return 恰好一行。第一个 SELECT
可以 return 0 行或更多。因为 table 是空的,所以 return 正好是零行。
0+1+1
。查询 return 恰好 2
行。
更新:
您希望按特定顺序 return 编辑行,但查询不需要任何排序。 SQL 处理行集合,作为数学对象,集合是 未排序的 集合(这就是 SQL 处理它们的方式)。
在查询中不存在 ORDER BY
的情况下,return 由 UNION
编辑的行不能保证按任何顺序 return 编辑。甚至它们来自 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
这样您就知道查询的哪一部分生成了每个 returned 行。
备注
您不需要第二个查询 return 编辑的行。它基本上告诉您第一个查询 return 编辑了多少行,但您也可以通过计算结果集中具有 tableNb == 1
的行数来知道这一点。因为你想要在实际行之后,它不需要额外遍历结果集,它可以在列出第一个查询的行时完成。
我有以下 MySql tables.
Table 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;
和table 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 脚本,例如,两个 table 都是空的:
$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
是我预期的数组?
My question is why my
$row2
is false when$row1
is the array as I would've expected?
您希望从查询中返回 3 行,但它只有 returns 2 行。
您的查询 UNION
三 SELECT
。最后两个 SELECT
中的每一个总是 return 恰好一行。第一个 SELECT
可以 return 0 行或更多。因为 table 是空的,所以 return 正好是零行。
0+1+1
。查询 return 恰好 2
行。
更新:
您希望按特定顺序 return 编辑行,但查询不需要任何排序。 SQL 处理行集合,作为数学对象,集合是 未排序的 集合(这就是 SQL 处理它们的方式)。
在查询中不存在 ORDER BY
的情况下,return 由 UNION
编辑的行不能保证按任何顺序 return 编辑。甚至它们来自 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
这样您就知道查询的哪一部分生成了每个 returned 行。
备注
您不需要第二个查询 return 编辑的行。它基本上告诉您第一个查询 return 编辑了多少行,但您也可以通过计算结果集中具有 tableNb == 1
的行数来知道这一点。因为你想要在实际行之后,它不需要额外遍历结果集,它可以在列出第一个查询的行时完成。