MySql LEFT JOIN возвращает сначала неправильную страницу PHP, но правильные результаты в командной строке MYSQL - PullRequest
0 голосов
/ 07 февраля 2020

Мы добавили два столбца к нашей основной таблице MySQL (именованные объекты), столбец для количества и столбец для идентификатора единиц. Если количество и / или единицы измерения неизвестны, для этих столбцов устанавливается значение NULL.

Мы хотели объединить эту таблицу с таблицей типов единиц измерения, чтобы отобразить названия единиц (фунты, страницы, граммы и т. Д.).

Когда я запускаю SELECT в клиенте командной строки MYSQL, он возвращает ожидаемые результаты. Когда моя страница PHP запускает запрос, в первой строке отображаются значения с неправильной стороны объединения.

Пример: объединяемые таблицы являются объектами и типами объектов с этими определениями

mysql> show create table objects;
CREATE TABLE `objects` (
  `objId` int NOT NULL AUTO_INCREMENT,
  `name` varchar(100) DEFAULT NULL,
  `description` varchar(250) DEFAULT NULL,
  `quantity` int DEFAULT NULL,
  `unitid` int DEFAULT NULL,
  `create_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `modify_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`objId`),
  KEY `unitid` (`unitid`),
  CONSTRAINT `objects_ibfk_1` FOREIGN KEY (`unitid`) REFERENCES `unittypes` (`unitId`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4735 DEFAULT CHARSET=utf8

и:

mysql> show create table unittypes;
CREATE TABLE `unittypes` (
  `unitId` int NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `description` varchar(50) DEFAULT NULL,
  `create_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `modify_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`unitId`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

Примеры строк:

Unittypes:

+--------+------+--------------+-
| unitId | name | description  | 
+--------+------+--------------+-
|      1 | Each | Each         | 

Objects:
+-------+---------------------------------------+-------------+----------+--------+
| objId | NAME                                  | description | quantity | unitid | 
+-------+---------------------------------------+-------------+----------+--------+
|  1018 | UNKNOWN cables                        | NULL        |   NULL   |  NULL  |  
|  3466 | UNKNOWN replies                       | NULL        |   NULL   |  NULL  | 
+-------+---------------------------------------+-------------+----------+--------+
|   722 | Soundgarden-Loudest Love              | NULL        |        1 |      1 |   
|  4703 | Soundgarden-Live FROM The Artists Den | NULL        |        1 |      1 |
+-------+---------------------------------------+-------------+----------+--------+

Пример запроса на соединение:

SELECT o.objid, o.name, o.description, 
       o.quantity, u.name, u.description, o.create_date, o.modify_date 
FROM objects AS o 
LEFT JOIN unittypes u USING(unitid) 
WHERE o.NAME LIKE '%Soundgarden-L%'

В MYSql клиенте командной строки возвращает:

+-------+---------------------------------------+-------------+----------+------+-------------+---------------------+---------------------+    
| objid | name                                  | description | quantity | name | description | create_date         | modify_date         |
+-------+---------------------------------------+-------------+----------+------+-------------+---------------------+---------------------+
|   722 | Soundgarden-Loudest Love              | NULL        |        1 | Each | Each        | 2017-04-01 05:44:56 | 2020-01-15 08:59:45 |    
|  4703 | Soundgarden-Live From The Artists Den | NULL        |        1 | Each | Each        | 2019-09-17 21:52:26 | 2020-01-15 08:59:45 |
+-------+---------------------------------------+-------------+----------+------+-------------+---------------------+---------------------+

На странице PHP он возвращает (PHP страница вернула ожидаемые результаты без объединения:

objid   name    description quantity    create_date modify_date

722 Each    Each    1   2017-04-01 05:44:56 2020-01-15 08:59:45

4703    Soundgarden-Live From The Artists Den   NULL    1   Each    Each    2019-09-17 21:52:26 2020-01-15 08:59:45

Набор результатов имеет 3 строки.

Пример, когда юнит-типы не имеют подходящей строки:

В клиенте командной строки:

SELECT o.objid, o.name, o.description, 
       o.quantity, u.name, u.description, o.create_date, o.modify_date 
FROM objects AS o 
LEFT JOIN unittypes u USING(unitid) 
WHERE o.NAME LIKE '%unknown %';

Результат:

+-------+--------------------------------------------------+-------------+----------+------+-------------+---------------------+---------------------+
| objid | name                                             | description | quantity | name | description | create_date         | modify_date         |
+-------+--------------------------------------------------+-------------+----------+------+-------------+---------------------+---------------------+
|  1018 | Unknown cables                                   | NULL        |     NULL | NULL | NULL        | 2017-06-27 02:22:12 | 2017-06-27 02:22:12 |    
|  3466 | Unknown replies                                | NULL        |     NULL | NULL | NULL        | 2018-11-05 01:45:17 | 2018-11-05 01:45:17 |
|

В PHP страница:

objid   name    description quantity    create_date modify_date
1018    NULL    NULL    NULL    2017-06-27 02:22:12 2017-06-27 02:22:12

3466    Unknown replies NULL    NULL    NULL    NULL    2018-11-05 01:45:17 2018-11-05 01:45:17

Я получаю те же результаты, используя синтаксис соединения

оставленные типы юнитов соединения u для o.unitid = u.unitid

PHP код, который выполняет запрос:

if ($result =  $GLOBALS['DB']->query($selObj)) {
        if ($row = $result->fetch_assoc()) {

            $row_cnt = $result->num_rows;

            echo '<table><tr>';
            foreach(array_keys($row) as $heading) echo "<th>$heading</th>";
            echo '</tr>';

            /* process result set */
            do {
                echo '<tr>';
                foreach($row as $item) echo '<td>'.($item==NULL?'NULL':$item).'</td>';
                echo '</tr>';
            } while ($row = $result->fetch_row()); // get next result set
            echo '</table>';
            printf("Result set has %d row%s.<br><br>", $row_cnt,($row_cnt==1?"":"s"));
            $result->close();
        } else echo 'Empty result set<br><br>';
    } else echo $DB->error;

Я ожидаю, что один и тот же запрос будет вести себя одинаково в обоих примерах. Я бы предположил, что командная строка и PHP просто передают строку mySQL для обработки, но, очевидно, есть некоторая разница, которую я не вижу.

Есть ли что-то странное в том, как PHP передает запрос; MYsql не обрабатывает соединения через этот интерфейс должным образом; код неправильный (работает без объединения)?

(я также спрашивал об этом по https://dba.stackexchange.com/q/258940/200179)

1 Ответ

0 голосов
/ 07 февраля 2020

У вас есть два столбца с именем name. Второе заменит первое.

Вам следует присвоить им псевдоним, чтобы они имели разные имена. select `o`.`name` as `o_name` ...

В вашем случае причина, по которой затрагивается только первая строка, заключается в том, что вы используете fetch_assoc, чтобы получить это, а затем fetch_row, чтобы получить другие (и fetch_row работает, потому что это полностью игнорирует имена столбцов)

...