Неожиданное поведение оператора 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 это массив, как я ожидал?

0

Решение

Мой вопрос, почему мой $row2 ложно, когда $row1 это массив, как я ожидал?

Вы ожидаете получить 3 строки из вашего запроса, но он возвращает только 2 строки.

Ваш запрос UNIONтри SELECTs. Каждый из последних двух 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 в наборе результатов. Так как вы хотите граф после фактические строки, он не нуждается в дополнительном обходе результирующего набора, это можно сделать, перечисляя строки из первого запроса.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]