2010-01-26 2 views
0

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

У меня есть таблица, скажем таблицу А и таблицу В

Table A : 
| ID | fk_tableB_ID | title 
------------------------- 
| 10 | 1,2   | title 1 
| 11 | 3   | title 2 

Table B : 
| ID | category 
--------------- 
| 1 | cat1 
| 2 | cat2 
| 3 | cat3 

Я попробовал этот запрос:

SELECT 
    a.ID, 
    a.title, 
    (
     SELECT 
      group_concat(b.category) 
     FROM 
      tableB B 
     WHERE 
      B.ID IN (a.fk_tableB_ID) 
    ) as category 
FROM 
    tableA a 

Это возвращение:

| ID | category | title 
----------------------- 
| 10 | cat1  | title1 
| 11 | cat3  | title2    

Но это не то, что я хотеть. Я хочу

| ID | category | title 
----------------------- 
| 10 | cat1,cat2 | title1 
| 11 | cat3  | title2 

Пожалуйста, помогите, что такое правильный код запроса mysql, чтобы я мог получить эту таблицу выше. Thx заранее

ответ

0

Да, это почти так, как это будет работать, если вы храните несколько значений в одной ячейке. Спасите себя и создайте таблицы так, чтобы в одной строке был только один fk_tableB_ID. Вы можете комбинировать значения в одной строке на выбранном вами языке программирования, поскольку это невозможно в MySQL.

Что-то, как это должно работать для вас:

Table A : 
| ID | page_ID | fk_tableB_ID | title 
------------------------- 
| 7 | 10  | 1   | title 1 
| 8 | 10  | 2   | title 1 
| 9 | 11  | 3   | title 2 

Table B : 
| ID | category 
--------------- 
| 1 | cat1 
| 2 | cat2 
| 3 | cat3 

И ваши запросы будут значительно упростить:

SELECT 
    a.page_ID, 
    b.category, 
    a.title 
FROM 
    table_a a 
LEFT JOIN 
    table_b b 
ON 
    a.fk_tableB_ID = b.ID 

И если вы решили использовать PHP, сделать объединение там. Это должно работать:

$r = mysql_query('SELECT ... '); 

$result = array(); 

while($row = mysql_fetch_assoc($r)) { 
    $result[$row['page_ID']]['title'] = $row['title']; 
    $result[$row['page_ID']]['categories'][] = $row['category']; 
} 

что должно привести к чему-то вроде этого:

Array 
(
    [10] => Array 
     (
      [title] => title 1 
      [categories] => Array 
       (
        [0] => cat1 
        [1] => cat2 
       ) 

     ) 

    [11] => Array 
     (
      [title] => title_2 
      [categories] => Array 
       (
        [0] => cat3 
       ) 

     )  
) 

И если вы хотите использовать этот массив, чтобы построить таблицу, аналогичную вашему примеру, вы можете использовать это:

echo "| ID  | category   | title\n"; 
echo "----------------------------------------\n"; 
foreach($array as $page_ID => $row) { 
    echo '| '.str_pad($page_ID, 7); 
    echo '| '.str_pad(implode(',', $row['categories']), 20); 
    echo '| '.$row['title']."\n"; 
} 

, которые будут выводить это:

| ID  | category   | title 
---------------------------------------- 
| 10  | cat1,cat2   | title_1 
| 11  | cat3    | title_2 

Это именно то, что вы хотели. Конечно, вы, вероятно, хотите вывести таблицу HTML, но вы получите эту идею.

+0

Параметр ' Таблица A', которую вы предлагаете, плохая конструкция, например, каждый заголовок хранится несколько раз. Возможно, есть также поле описания с большим количеством текста. Вы создаете избыточность! Третья таблица - намного лучший дизайн. –

+0

@ Феликс, вы правы, это был всего лишь способ сделать то, что он хотел, с минимальным количеством необходимых изменений. Третья таблица действительно была бы лучшим решением. –

+0

Thx для вашего ответа это действительно помогает. Я знаю, что это плохая таблица, но иногда я получаю таблицы точно так же (обновленный старый скрипт от другого программиста). Я подумал, может быть, я могу сделать с ним один вопрос, но теперь я знаю, что это невозможно. – aprian

0

лучший способ сделать это будет иметь другую таблицу, в середине называется что-то вроде «a_has_category»

Table a : 
| ID | title 
--------------- 
| 10 | title 1 
| 11 | title 2 

Table category : 
| ID | category 
--------------- 
| 1 | cat1 
| 2 | cat2 
| 3 | cat3 

Table a_has_Category : 
| ID | fk_a | fk_category 
--------------- 
| 1 | 10 | 1 
| 2 | 10 | 1 
| 3 | 11 | 2 

Затем использовать несколько внутренних JOINS построить запрос

SELECT a.title, B.category FROM a 
INNER JOIN a_has_category 
ON fk_a = a_ID 
INNER JOIN category 
ON fk_category = category_ID 

Как только вы вернетесь к своим результатам, объедините категории в строку запятыми между использованием функции IMPLODE PHP.

0

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

Table A : 
| ID | title 
------------ 
| 10 | title 1 
| 11 | title 2 


Table B : 
| ID | category 
--------------- 
| 1 | cat1 
| 2 | cat2 
| 3 | cat3 

Table A_B: 
| fk_tableA_ID | fk_tableB_ID 
----------------------------- 
| 10   | 1 
| 10   | 2 
| 11   | 3 

Я не думаю, что это можно делать то, что вы хотите в одном запросе (может быть, в хранимую процедуру), но давайте посмотрим, что другие придумают.

Имея только одно значение в поле, называется first normal form (1NF). Это первый шаг оптимизации базы данных.

0

проблема с выполнением этого способа, которым вы пытаетесь сделать, заключается в том, что функции IN требуется массив. Если вам действительно нужно спуститься по этому маршруту, вам нужно будет запустить функцию в строке для создания массива, а затем использовать ее в инструкции IN.

пример здесь http://forums.mysql.com/read.php?60,78776,242420#msg-242420

, но я бы рекомендовал добавлять таблицу ссылок вместо.

0

Как упоминалось выше, при наличии нескольких внешних ключей в одном столбце плохой дизайн, вы должны использовать таблицу n: m. Смотрите эту структуру таблицы, как, например: (да я оставил некоторые индексы :)

CREATE TABLE IF NOT EXISTS `a` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(50) NOT NULL, PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ; 

INSERT INTO `a` (`id`, `title`) VALUES (1, 'first row'), (2, 'second row'), (3, 'third row'), (4, 'fourth row'); 



CREATE TABLE IF NOT EXISTS `ab` ( `a_id` int(11) NOT NULL, `b_id` int(11) NOT NULL) ENGINE=MyISAM DEFAULT CHARSET=utf8; 



INSERT INTO `ab` (`a_id`, `b_id`) VALUES (1, 1), (1, 2), (1, 4), (2, 5), (3, 5), (4, 6), (4, 5), (3, 6); 


CREATE TABLE IF NOT EXISTS `b` ( `id` int(11) NOT NULL AUTO_INCREMENT, `category` varchar(50) NOT NULL, PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ; 


INSERT INTO `b` (`id`, `category`) VALUES (1, 'Cat1'), (2, 'Cat2'), (3, 'Cat3'), (4, 'Cat4'), (5, 'Cat5'), (6, 'Cat6'); 

Затем вы можете использовать этот запрос:

SELECT a.id, a.title, group_concat(b.category) 
FROM a 
LEFT JOIN ab ON a.id = ab.a_id 
LEFT JOIN b ON b.id = ab.b_id 
GROUP BY a.id; 

, что приводит к:

id title group_concat(b.category) 
1 first row Cat4,Cat1,Cat2 
2 second row Cat5 
3 third row Cat5,Cat6 
4 fourth row Cat5,Cat6 
Смежные вопросы