Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: Вопрос по объединению таблиц

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (1): [1]   

> Без описания
teddy
Отправлено: 29 Июля, 2013 - 16:49:18
Post Id


Участник


Покинул форум
Сообщений всего: 1462
Дата рег-ции: Апр. 2013  


Помог: 91 раз(а)




Здравствуйте. Не понимаю как себя ведет следующий SQL запрос:

PHP:
скопировать код в буфер обмена
  1. $result = $db->query("SELECT DISTINCT parentmenu.name, submenu.sub_name FROM parentmenu INNER JOIN submenu ON `submenu`.parentid = `parentmenu`.id") or die($db->error);
  2.        
  3.     while($row = $result->fetch_assoc())
  4.     {
  5.          echo $row['name']."<br />";
  6.          echo $row['sub_name'];
  7.        
  8.     }
  9.  

Тоесть я говорю в запросе, выбери мне родительское меню, дочернее меню(подменю) из таблицы, которое содержит родительское меню объединяя его с подменю на основе того, что родительский id у подменю, развен id у основного меню. Как то так.

Проблема в том, что родительское меню при выводе ДУБЛИРУЕТСЯ. Я же написал DISTINCT - а он должен прекращать дублирование. Скажите пожалуйста, почему так?

Должно выводиться так:

Фильмы
- Комедии
- Боевики

Спорт
- Плавание
- Смешанные бои

Но категории повторяются. получается так:

Фильмы
Комедии
Фильмы
Боевики

и т.д

(Отредактировано автором: 29 Июля, 2013 - 16:51:41)

 
 Top
EuGen Администратор
Отправлено: 29 Июля, 2013 - 16:58:07
Post Id


Профессионал


Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




teddy
Потому что JOIN присоединяет все строки. Он не может понять, что существует некая "вложенность" (вернее, можно сконструировать замысловатый запрос, но в Вашем случае этого не нужно) элементов.
Вам достаточно сделать JOIN, после чего правильно выводить данные в PHP

CODE (SQL):
скопировать код в буфер обмена
  1. SELECT DISTINCT parentmenu.name, submenu.sub_name FROM parentmenu INNER JOIN submenu ON `submenu`.parentid = `parentmenu`.id ORDER BY parentmenu.name

- Вы получите отсортированный массив. Всё, что нужно - это выводить заголовки (например, можно просто смотреть, не сменился ли родительский элемент, и, если да - выводить его; цикл остаётся одиночным. Можно вместо этого пройтись по массиву строк и собрать данные в двумерный массив - на Ваш вкус).
Если интересует "замысловатый" запрос, то - пример: http://forum.php.su/topic.php?fo...30376#1190130376


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
teddy
Отправлено: 29 Июля, 2013 - 17:03:50
Post Id


Участник


Покинул форум
Сообщений всего: 1462
Дата рег-ции: Апр. 2013  


Помог: 91 раз(а)




EuGen пишет:
Вам достаточно сделать JOIN, после чего правильно выводить данные в PHP

Запрос который вы написали отличается от моего только ORDER BY - его я тоже добавил но результат не изменился...

Можно подробнее про "правильный" вывод в PHP? Я сначала вывожу родительское меню а потом дочернее вроде бы все правильно... Или может вы имели ввиду что в php есть специальная функция для работы с массивами которая удаляет дубли? Если да, то подскажите пожалуйста, какая это функция

А не, про функцию я ляпнул...ведь mysqli возвращает объект

(Отредактировано автором: 29 Июля, 2013 - 17:10:01)

 
 Top
EuGen Администратор
Отправлено: 29 Июля, 2013 - 17:07:48
Post Id


Профессионал


Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




teddy пишет:
Запрос который вы написали отличается от моего только ORDER BY - его я тоже добавил но результат не изменился...

EuGen пишет:
Потому что JOIN присоединяет все строки. Он не может понять, что существует некая "вложенность" (вернее, можно сконструировать замысловатый запрос, но в Вашем случае этого не нужно) элементов.

PHP:
скопировать код в буфер обмена
  1. $result = $db->query("SELECT DISTINCT parentmenu.name, submenu.sub_name FROM parentmenu INNER JOIN submenu ON `submenu`.parentid = `parentmenu`.id") or die($db->error);
  2.  
  3. $rgResult = [];
  4. while($row = $result->fetch_assoc())
  5. {
  6.      $rgResult[$row['name']][] = $row['sub_name'];
  7. }
  8. //var_dump($rgResult)

- как работать с rgResult, уверен, догадаетесь. Альтернативный вариант (за один проход, с проверкой, не сменился ли родитель) - оставляю Вам (но даю подсказку - в том варианте без ORDER BY уже нельзя).


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
teddy
Отправлено: 29 Июля, 2013 - 18:17:59
Post Id


Участник


Покинул форум
Сообщений всего: 1462
Дата рег-ции: Апр. 2013  


Помог: 91 раз(а)




EuGen
Спасибо за внимание, Евгений )

Я посмотрю обязательно что да как... сходу пока не понимаю.. всегда были проблемы с JOIN-ами
(Добавление)
Не доходит в упор.

Пробовал даже по другому. Получал из объекта массив потом при помощи array_unique пытался удалить дубли тоже не выходит...

Не доходит почему не срабатывает DISTINCT что он есть что его нет одно и тоже..



В мозгах ошибка уровня notice ))
 
 Top
Panoptik
Отправлено: 29 Июля, 2013 - 19:57:48
Post Id



Постоянный участник


Покинул форум
Сообщений всего: 2493
Дата рег-ции: Нояб. 2011  
Откуда: Одесса, Украина


Помог: 131 раз(а)




DISTINCT работает только по одному полю, если вы в выражении SELECT указываете 2 и более полей для выборки, то все они должны быть соответственно равны другим значениям чтобы опустить повторяющие значения

к примеру наборы чисел
1 2 3
1 3 2
1 1 1
1 2 3

через дистинкт дадут

1 2 3
1 3 2
1 1 1

то есть абсолютно одинаковые результаты отсеются
(Добавление)
если нужно убрать дублирующие значения по определенным полям при этом выбрать дополнительные, то пользуйте GROUP BY


-----
Just do it
 
 Top
teddy
Отправлено: 29 Июля, 2013 - 20:11:12
Post Id


Участник


Покинул форум
Сообщений всего: 1462
Дата рег-ции: Апр. 2013  


Помог: 91 раз(а)




Panoptik пишет:
если нужно убрать дублирующие значения по определенным полям при этом выбрать дополнительные, то пользуйте GROUP BY

Не совсем то. Я уже пробовал, но тогда подкатегории выводятся только 1 раз, а остальные не выводятся
 
 Top
EuGen Администратор
Отправлено: 30 Июля, 2013 - 13:12:17
Post Id


Профессионал


Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




teddy
Всё же, я так и не понял, что же именно не получается.
CODE (SQL):
скопировать код в буфер обмена
  1. mysql> SHOW CREATE TABLE tbl20130730_parent;
  2. +--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  3. | TABLE              | CREATE TABLE                                                                                                                                                                                         |
  4. +--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  5. | tbl20130730_parent | CREATE TABLE `tbl20130730_parent` (
  6.   `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  7.   `title` varchar(255) DEFAULT NULL,
  8.   PRIMARY KEY (`id`)
  9. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 |
  10. +--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  11. 1 row IN SET (0.00 sec)
  12.  
  13. mysql> SHOW CREATE TABLE tbl20130730_child;
  14. +-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  15. | TABLE             | CREATE TABLE                                                                                                                                                                                                                                                                                                                                                                                                         |
  16. +-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  17. | tbl20130730_child | CREATE TABLE `tbl20130730_child` (
  18.   `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  19.   `parent_id` int(11) UNSIGNED DEFAULT NULL,
  20.   `title` varchar(255) DEFAULT NULL,
  21.   PRIMARY KEY (`id`),
  22.   KEY `fkParentid` (`parent_id`),
  23.   CONSTRAINT `fkParentKey` FOREIGN KEY (`parent_id`) REFERENCES `tbl20130730_parent` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
  24. ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 |
  25. +-------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  26. 1 row IN SET (0.00 sec)

- исходные таблицы.
CODE (SQL):
скопировать код в буфер обмена
  1. mysql> SELECT * FROM tbl20130730_parent;
  2. +----+-------+
  3. | id | title |
  4. +----+-------+
  5. |  1 | Cars  |
  6. |  2 | Motos |
  7. +----+-------+
  8. 2 rows IN SET (0.00 sec)
  9.  
  10. mysql> SELECT * FROM tbl20130730_child;
  11. +----+-----------+--------+
  12. | id | parent_id | title  |
  13. +----+-----------+--------+
  14. |  1 |         1 | BMW    |
  15. |  2 |         1 | Audi   |
  16. |  3 |         1 | Reno   |
  17. |  4 |         1 | Ford   |
  18. |  5 |         2 | H-D    |
  19. |  6 |         2 | Honda  |
  20. |  7 |         2 | Yamaha |
  21. +----+-----------+--------+
  22. 7 rows IN SET (0.00 sec)

- исходные данные
CODE (SQL):
скопировать код в буфер обмена
  1. mysql> SELECT tbl20130730_parent.title AS category, tbl20130730_child.title AS item FROM tbl20130730_parent LEFT JOIN tbl20130730_child ON tbl20130730_child.parent_id=tbl20130730_parent.id;
  2. +----------+--------+
  3. | category | item   |
  4. +----------+--------+
  5. | Cars     | BMW    |
  6. | Cars     | Audi   |
  7. | Cars     | Reno   |
  8. | Cars     | Ford   |
  9. | Motos    | H-D    |
  10. | Motos    | Honda  |
  11. | Motos    | Yamaha |
  12. +----------+--------+
  13. 7 rows IN SET (0.00 sec)

- запрос на получение категорий с элементами.
PHP:
скопировать код в буфер обмена
  1. $rConnect = new mysqli('localhost', 'user', 'password', 'test') or exit(mysqli_error());
  2. $rSelect  = $rConnect->query('SELECT tbl20130730_parent.title AS category, tbl20130730_child.title AS item FROM tbl20130730_parent LEFT JOIN tbl20130730_child ON tbl20130730_child.parent_id=tbl20130730_parent.id') or exit(mysqli_error());
  3. $rgResult = [];
  4. while($rgRow = $rSelect->fetch_array())
  5. {
  6.    $rgResult[$rgRow['category']][]=$rgRow['item'];
  7. }
  8. foreach($rgResult as $sCategory=>$rgCategory)
  9. {
  10.    echo $sCategory,'<br/>';
  11.    foreach($rgCategory as $sItem)
  12.    {
  13.       echo ' ',$sItem,'<br/>';
  14.    }
  15. }

ну и
CODE (text):
скопировать код в буфер обмена
  1. Cars
  2.  BMW
  3.  Audi
  4.  Reno
  5.  Ford
  6. Motos
  7.  H-D
  8.  Honda
  9.  Yamaha

- примерный результат.
Всё-таки вариант без сбора данных в промежуточный массив оставлю Вам.


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
teddy
Отправлено: 30 Июля, 2013 - 14:17:48
Post Id


Участник


Покинул форум
Сообщений всего: 1462
Дата рег-ции: Апр. 2013  


Помог: 91 раз(а)




EuGen
Упс, столько написали ) Даже стыдно как то стало, что поднял эту тему )) Спасибо за ваши старания и внимание!

Вот в этом и заключается ступор ) Я хотел решить вопрос одним циклом, цикл в цикле - так уже я решал честно говоря без промежуточного массива Улыбка

Если честно мне это меню особо не нужно, у меня есть рабочее "решение", я просто взялся за этот скрипт для тренировки JOIN-ов... Получается так что вывод в PHP не столь важен, сколько хорошенько понять прицип объединения таблиц... Когда например лучше применить одно, а когда другое. там когда INNER JOIN а когда LEFT JOIN или FULL OUTER JOIN и т.д ) - из за этого я плохо понимаю что я делаю, вот и решил разобраться...


Прошу ещё обратить внимание на этот ньюанс:
CODE (SQL):
скопировать код в буфер обмена
  1. KEY `fkParentid` (`parent_id`),
  2. 23.  CONSTRAINT `fkParentKey` FOREIGN KEY (`parent_id`)
  3.  

Этот код я взял с вашего примера выше при создании таблиц. Этого я не указывал когда у себя создавал таблицы. Разве здесь нужны такие ключи? Сори если вопрос не очень корректный, в данный момент не очень хорошо разбираюсь в грамотной архитектуре MySQL. Только на базовом уровне.



Надеюсь я не надоел Улыбка
 
 Top
EuGen Администратор
Отправлено: 30 Июля, 2013 - 14:26:26
Post Id


Профессионал


Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




Внешние ключи нужны для контроля целостности данных на уровне СУБД (о чём свидетельствует, например, указанные мной ON DELETE SET NULL ON UPDATE CASCADE).
Если не получается именно одним циклом, то, хорошо, вот пример:
PHP:
скопировать код в буфер обмена
  1.     $rConnect = new mysqli('localhost', 'user', 'password', 'test') or exit(mysqli_error());
  2.     $rSelect  = $rConnect->query('SELECT tbl20130730_parent.title AS category, tbl20130730_child.title AS item FROM tbl20130730_parent LEFT JOIN tbl20130730_child ON tbl20130730_child.parent_id=tbl20130730_parent.id ORDER BY tbl20130730_parent.id') or exit(mysqli_error());
  3.     $sCategory= null;
  4.     while($rgRow = $rSelect->fetch_array())
  5.     {
  6.        echo $sCategory!=$rgRow['category']?($sCategory=$rgRow['category']).'<br/>':'';
  7.        echo ' ',$rgRow['item'],'<br/>';
  8.     }

- насчёт внешних ключей можете почитать мануал: http://dev[dot]mysql[dot]com/doc/refman/[dot][dot][dot]constraints[dot]html или статьи в Сети, к примеру, http://stackoverflow[dot]com/questio[dot][dot][dot]gn-keys-in-mysql


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
teddy
Отправлено: 30 Июля, 2013 - 14:38:34
Post Id


Участник


Покинул форум
Сообщений всего: 1462
Дата рег-ции: Апр. 2013  


Помог: 91 раз(а)




EuGen
Опаньки, спасибо огромное, Евгений! ))

Отличный фокус $sCategory!=$rgRow['category']*

Не встречал ранее подобное... Доки придется читать с помощью переводчика )

Спасибо ещё раз за помощь ) о таком варианте я даже не подумал
 
 Top
EuGen Администратор
Отправлено: 30 Июля, 2013 - 14:41:28
Post Id


Профессионал


Покинул форум
Сообщений всего: 9095
Дата рег-ции: Июнь 2007  
Откуда: Berlin


Помог: 707 раз(а)




teddy пишет:
Отличный фокус $sCategory!=$rgRow['category']*

Думаю, становится понятно, почему для работы данного приёма необходим ORDER BY


-----
Есть в мире две бесконечные вещи - это Вселенная и человеческая глупость. Но насчет первой .. я не уверен.
 
 Top
teddy
Отправлено: 30 Июля, 2013 - 15:04:22
Post Id


Участник


Покинул форум
Сообщений всего: 1462
Дата рег-ции: Апр. 2013  


Помог: 91 раз(а)




EuGen
Да, конечно понятно )) спасибо ещё раз, вы мне очень помогли!

(Отредактировано автором: 30 Июля, 2013 - 15:05:14)

 
 Top
Страниц (1): [1]
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Работа с СУБД »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB