PHP и mySQL: проблема с повторяющимися записями - нужно, чтобы каждая запись появлялась только один раз, но они повторяются - PullRequest
5 голосов
/ 06 января 2010

МОЯ ПЛАТФОРМА:

PHP & MySQL

ЧТО Я ЗДЕСЬ:

У меня есть 4 таблицы, а именно: 'books', 'book_type', 'book_categories', 'all_categories'.

Что я пытаюсь сделать:

Проще говоря, я хочу отобразить все книги, которые есть в наличии, т. Е. In_stock = 'y', со всей информацией о книгах из всех таблиц, только один раз, без повторения записей. В настоящее время каждая из книг повторяется, и я хочу показать их только один раз.

ТЕКУЩАЯ ПРОБЛЕМА:

Во внешнем интерфейсе моего приложения записи отображаются неоднократно, хотя на самом деле я ожидаю, что они появятся только один раз (как в DISTINCT / UNIQUE) и не повторяются.

МОЕ СУСПИЦИОН:

Я подозреваю, что повторяющиеся данные связаны с категориями, к которым относится каждая из книг. Каждая запись в книге показана столько раз, сколько она принадлежит категории. Смешение? Я имею в виду, что если book1 принадлежит 4 категориям, то book1 показывается 4 раза. Если book2 принадлежат 2 категориям, то это показано 2 раза.

ЧТО МНЕ НУЖНО:

Мне нужен код PHP и mySQL , который решит вышеуказанную проблему. Я надеюсь, что мы сможем решить проблему, не используя GROUP_CONCAT в mySQL, так как есть ограничение (1024?) Для того же. Книга может относиться ко многим категориям, и я не хочу рисковать потерей каких-либо данных с помощью GROUP_CONCAT. Я также хотел бы сделать это в одном запросе без повторного доступа к базе данных в цикле. Спасибо за понимание.

Все таблицы и соответствующие данные для воспроизведения проблемы следующие:

CREATE TABLE IF NOT EXISTS `books` (
  `book_id` int(11) NOT NULL auto_increment,
  `book_type_id` int(11) NOT NULL,
  `book_title` varchar(50) NOT NULL,
  `book_price` smallint(4) NOT NULL,
  `in_stock` char(1) NOT NULL,
  PRIMARY KEY  (`book_id`),
  KEY `book_type_id` (`book_type_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

--
-- Dumping data for table `books`
--

INSERT INTO `books` (`book_id`, `book_type_id`, `book_title`, `book_price`, `in_stock`) VALUES
(1, 1, 'My Book 1', 10, 'y'),
(2, 1, 'My Book 2', 20, 'n'),
(3, 2, 'My Book 3', 30, 'y'),
(4, 3, 'My Book 4', 40, 'y'),
(5, 2, 'My Book 5', 50, 'n'),
(6, 1, 'My Book 6', 60, 'y'),
(7, 3, 'My Book 7', 70, 'n'),
(8, 2, 'My Book 8', 80, 'n'),
(9, 1, 'My Book 9', 90, 'y'),
(10, 3, 'My Book 10', 100, 'n');

--
-- Table structure for table `book_type`
--

CREATE TABLE IF NOT EXISTS `book_type` (
  `book_type_id` int(11) NOT NULL auto_increment,
  `book_type` varchar(50) NOT NULL,
  PRIMARY KEY  (`book_type_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

--
-- Dumping data for table `book_type`
--

INSERT INTO `book_type` (`book_type_id`, `book_type`) VALUES
(1, 'Good'),
(2, 'Better'),
(3, 'Best');


--
-- Table structure for table `book_categories`
--

CREATE TABLE IF NOT EXISTS `book_categories` (
  `book_id` int(11) NOT NULL,
  `cat_id` int(11) NOT NULL,
  PRIMARY KEY  (`book_id`,`cat_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- Dumping data for table `book_categories`
--

INSERT INTO `book_categories` (`book_id`, `cat_id`) VALUES
(1, 1),
(1, 2),
(1, 3),
(1, 4),
(1, 5),
(2, 1),
(2, 2),
(3, 1),
(3, 2),
(3, 3);


--
-- Table structure for table `all_categories`
--

CREATE TABLE IF NOT EXISTS `all_categories` (
  `cat_id` int(11) NOT NULL auto_increment,
  `category` varchar(50) NOT NULL,
  PRIMARY KEY  (`cat_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

--
-- Dumping data for table `all_categories`
--

INSERT INTO `all_categories` (`cat_id`, `category`) VALUES
(1, 'Comedy'),
(2, 'Drama'),
(3, 'Romance'),
(4, 'Horror'),
(5, 'Trivia'),
(6, 'Puzzles'),
(7, 'Riddles'),
(8, 'Kids'),
(9, 'Gents'),
(10, 'Ladies');

МОЯ ЦЕЛЬ:

//MY QUERY:
SELECT books.book_title,  books.book_price,
       book_type.book_type,
       all_categories.category
FROM books 
LEFT JOIN book_type       ON books.book_type_id = book_type.book_type_id
LEFT JOIN book_categories ON books.book_id = book_categories.book_id
LEFT JOIN all_categories  ON book_categories.cat_id = all_categories.cat_id
WHERE books.in_stock = 'y' 

ТЕКУЩИЙ ВЫХОД:

book_title  book_price  book_type       category
My Book 1    10          Good            Comedy
My Book 1    10          Good            Drama
My Book 1    10          Good            Romance
My Book 1    10          Good            Horror
My Book 1    10          Good            Trivia
My Book 3    30          Better          Comedy
My Book 3    30          Better          Drama
My Book 3    30          Better          Romance
My Book 4    40          Best            NULL
My Book 6    60          Good            NULL
My Book 9    90          Good            NULL

НУЖЕН СЛЕДУЮЩИЙ ВЫХОД:

book_title  book_price  book_type       category
My Book 1    10          Good            Comedy, Drama, Romance, Horror, Trivia
My Book 3    30          Better          Comedy, Drama, Romance
My Book 4    40          Best            NULL
My Book 6    60          Good            NULL
My Book 9    90          Good            NULL

Спасибо всем заранее.

Ответы [ 6 ]

3 голосов
/ 06 января 2010

Лучший способ убедиться, что вы не потеряете ЛЮБЫЕ данные, - это несколько запросов. Запросите таблицы по отдельности и соедините их в PHP, возможно, ваши запросы будут выглядеть следующим образом

book_id book_title  book_price  book_type         
    1  My Book 1    10          Good           
    2  My Book 3    30          Better          
    3  My Book 4    40          Best           
    4  My Book 6    60          Good            
    5  My Book 9    90          Good           

    book_id, category
    1   Comedy
    1   Drama
    1   Romance
    2   Comedy

и т.д.

Edit:

Нет, вам не нужно 100 обращений к БД, только два, один для получения книг, следующий для получения категорий. Цикл будет выполняться в PHP, чтобы пройти второй запрос и соединить данные с первым. Второй запрос может быть

ВЫБРАТЬ book.book_id, all_categories.category ОТ book_category ПРИСОЕДИНИТЬСЯ all_categories на book_categories.cat_id = all_categories.cat_id ПРИСОЕДИНИТЬСЯ к книгам на books.book_id = book_categories.book_id ГДЕ books.in_stock = 'y';

OR

SELECT book_categories.book_id, all_categories.category FROM book_category 
JOIN   all_categories on book_categories.cat_id=all_categories.cat_id  
WHERE book_id IN   (SELECT book_id FROM books WHERE books.in_stock= 'y');
1 голос
/ 07 января 2010

Установите для переменной session большое значение, выполните запрос с помощью GROUP_CONCAT, а затем сбросьте его до значения global .

SET SESSION group_concat_max_len=@@max_allowed_packet;

SELECT books.book_title,  books.book_price,
       book_type.book_type,
       GROUP_CONCAT(all_categories.category)
FROM books 
LEFT JOIN book_type       ON books.book_type_id = book_type.book_type_id
LEFT JOIN book_categories ON books.book_id = book_categories.book_id
LEFT JOIN all_categories  ON book_categories.cat_id = all_categories.cat_id
WHERE books.in_stock = 'y'
GROUP BY books.book_id;

SET SESSION group_concat_max_len=@@group_concat_max_len;
1 голос
/ 06 января 2010

Очень просто. Добавить группу по. Так было бы так:

РЕДАКТИРОВАТЬ: похоже, что лучший способ сделать это - использовать групповой конкат (даже если вас беспокоит его верхний предел), чтобы обойти верхний предел, который у него есть. время. Так что это будет примерно так:

SET GLOBAL group_concat_max_len = SOME_BIG_VALUE; #SOME_BIG_VALUE >> 1024

SELECT books.book_title,  books.book_price,
       book_type.book_type,
       GROUP_CONCAT(all_categories.category)
FROM books 
LEFT JOIN book_type       ON books.book_type_id = book_type.book_type_id
LEFT JOIN book_categories ON books.book_id = book_categories.book_id
LEFT JOIN all_categories  ON book_categories.cat_id = all_categories.cat_id
WHERE books.in_stock = 'y'
GROUP BY books.book_title
1 голос
/ 06 января 2010

Вы также можете использовать разделитель CONCAT_WS с подзапросом, например:

SELECT  books.book_title, 
    books.book_price, 
    book_type.book_type, 
    CONCAT_WS(', ', (   
                        SELECT  all_categories.category
                          FROM  all_categories 
                         WHERE  all_categories.cat_id = book_categories.cat_id
                     )
             ) AS book_category_list
 FROM books 
LEFT JOIN book_type   
       ON books.book_type_id = book_type.book_type_id                  
LEFT JOIN book_categories 
       ON books.book_id = book_categories.book_id
    WHERE books.in_stock = 'y'

Извините, форматирование стало немного странным.

1 голос
/ 06 января 2010

Приятель, тебе стоит взглянуть на GROUP_CONCAT() функцию MySQL. http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat

Это будет что-то между строк:

SELECT stuff, GROUP_CONCAT(DISTINCT category ORDER BY category DESC SEPARATOR ', ') 
GROUP BY category, price, book_type
0 голосов
/ 06 января 2010

Вы пытались добавить отличительный к вашему выбору?

SELECT DISTINCT books.book_title,  books.book_price,
   book_type.book_type,
   all_categories.category
FROM books 
LEFT JOIN book_type       ON books.book_type_id = book_type.book_type_id
LEFT JOIN book_categories ON books.book_id = book_categories.book_id
LEFT JOIN all_categories  ON book_categories.cat_id = all_categories.cat_id
WHERE books.in_stock = 'y'
GROUP BY books.book_title
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...