【问题标题】:Unexpected behavior of UNION ALL operatorUNION ALL 运算符的意外行为
【发布时间】:2016-05-12 07:35:33
【问题描述】:

我有以下 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)

我的问题是为什么我的$row2false$row1 是我所期望的数组?

【问题讨论】:

  • 是吗?您是否有记录满足第一个查询中的 where 条件?对于一个空结果和两个记录集,每个记录集有 1 条记录,您的预期输出是什么?
  • @Pred:不,表格最初是空的。在这种情况下,我希望我的$row0false。不是这样吗?
  • 为什么?空+东西=东西。 SQL 不会仅仅因为您在某处有一个空集而重新索引结果。 SQL 应该如何知道第一个查询应该返回 1 条还是 2 条或没有或 10k 条记录?它应该在哪里重新索引记录(并在第一条记录之前填写所有内容)?
  • "在这种情况下,我希望我的 $row0false" -- SQL 使用集合,它们是 无序 列表. mysql_fetch_row() 在没有要返回的行时返回 FALSE(因为查询没有返回任何行,或者因为所有行都已获取)。您的查询正好返回 2 行。
  • mysql PHP 扩展已失效 - 停止使用 mysql PHP extension。它是旧的,自 PHP 5.5 起已弃用,并在 PHP 7.0 中完全删除。请改用mysqliPDO_mysql

标签: php mysql union union-all


【解决方案1】:

我的问题是,当$row1 是我所期望的数组时,为什么我的$row2 为假?

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

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

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


更新:

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

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

如果您想按照您编写 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 的行来知道这一点。由于您希望计数实际行之后,因此不需要额外遍历结果集,可以在列出第一个查询中的行时完成。

【讨论】:

  • 谢谢。我想我误解了ALLUNION ALL 中的含义。我的假设是它也会包含 NULL。由坏。所以我上面的结构几乎没用。因此,我必须将其拆分为 3 个单独的 mysql_query 调用。螺杆并发。
  • ALLUNION ALL 部分不会删除重复的行。但是第一个 SELECT 不返回任何行。如果它返回满是NULLs 的行,那么该行将被返回到最终结果集中。
猜你喜欢
  • 2017-03-05
  • 1970-01-01
  • 2016-08-10
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-25
相关资源
最近更新 更多