Присоединяйтесь к четырем таблицам в codeigniter

У меня есть четыре таблицы Как ниже

Тэг:

------------------------------------------------------------------------------------------------
| list_id                              |user_id | name | category | fees | details |created_on |
------------------------------------------------------------------------------------------------
| 90cc57a4-f782-4c57-ac98-1965c57ece57 |user 100 |satwik| music   | 500  | dummy   |2015-08-02 |
------------------------------------------------------------------------------------------------

изменил мой list_id из случайной строки в UUID.
из этого комментария на php.net
qaru.site/info/454234/...
В таблице списков list_id является первичным ключом, я знаю, что использование autoincreament лучше, но мое требование похоже на это. и s.no является первичным ключом для остальной таблицы.

Мне нужно создать случайный ключ со стороны PHP, потому что установить list_id в сеансе и избежать другого запроса для установки list_id в сеансе. Любит:

----------------------------------------------------------------
|.sno | list_id                              | user_id | likes |
----------------------------------------------------------------
| 1   | 90cc57a4-f782-4c57-ac98-1965c57ece57 | user110 |  1    |
----------------------------------------------------------------
| 2   | 90cc57a4-f782-4c57-ac98-1965c57ece57 | user215 |  1    |
----------------------------------------------------------------
| 3   | 90cc57a4-f782-4c57-ac98-1965c57ece57 | user200 |  1    |
----------------------------------------------------------------

комментарии:

-------------------------------------------------------------------------
|.sno | user_id | list_id                              | comment         |
-------------------------------------------------------------------------
|  1  | user 205| 90cc57a4-f782-4c57-ac98-1965c57ece57 | dummy comment   |
-------------------------------------------------------------------------

Просмотров:

----------------------------------------------------------------
|.sno | list_id                              | user_id | views |
----------------------------------------------------------------
| 1   | 90cc57a4-f782-4c57-ac98-1965c57ece57 | user110 |  2    |
----------------------------------------------------------------
| 2   | 90cc57a4-f782-4c57-ac98-1965c57ece57 | user215 |  1    |
----------------------------------------------------------------
| 3   | 90cc57a4-f782-4c57-ac98-1965c57ece57 | user200 |  1    |
----------------------------------------------------------------

Я пытаюсь получить список user user user100 из таблицы списков

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

Я попытался использовать этот запрос из codeigniter

 $this->db->select ( 'list.*,count(v.views) as views,count(l.likes) as likes,count(c.comment) as comments' )
                 ->from ( 'listings as list' )
                 ->join ( 'views v', 'v.list_id = list.list_id')
                 ->join ( 'likes l', 'l.list_id = list.list_id')
                 ->join ( 'comments c', 'c.list_id = list.list_id');
$this->db->where ( 'list.user_id', $user_id);
$query = $this->db->get ();

Я получаю неправильные взгляды и комментарии и комментарии.

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

EDIT:

Я попробовал этот запрос из ответов ниже

$this->db->select ( 'l.*,count(distinct v.s_no) as views,count(distinct li.s_no) as likes,count(distinct c.s_no) as comments' ,false)
    ->from ( 'listings as l' )
    ->join ( 'likes li', 'l.list_id = li.list_id')
    ->join ( 'comments c', 'l.list_id = c.list_id')
    ->join ( 'views v', 'l.list_id = v.list_id')
    ->where ( 'l.user_id', $id);

Я получаю то, что хочу, но этот способ запроса не выполняется (возвращает null), если у меня нет комментариев или представлений или нравится.

Ответ 1

Если user_id не уникально для likes, comments или views, вы получите кросс-продукт при выполнении нескольких объединений, которые будут раздувать ваши счета. Поскольку вы запрашиваете только один user_id, подзапросы могут быть лучшим способом.

Не забудьте установить второй параметр в select на false, так что codeigniter не пытается избежать подзапросов.

$this->db->select ( 'list.*, 
    (select count(*) from views v where v.user_id = list.user_id) as views,
    (select count(*) from likes l where l.user_id = list.user_id) as likes,
    (select count(*) from comments c where c.user_id = list.user_id) as comments',false)->from ( 'listings as list' );
$this->db->where ( 'list.user_id', $user_id);
$query = $this->db->get ();

Ответ 2

Учитывая вашу структуру, каждая таблица должна иметь одно поле, определенное как primary key и ассоциации таблицы листинга (симв., просмотров и комментарии) должны относиться к этому ключу как foreign key я ожидаю, что поле sno будет определено как первичный ключ для каждой таблицы, поэтому в вашем case list_id в понравившемся просмотре и комментариях будет иметь ссылку таблицы листинга с автогенерируемым идентификатором списка, который равен 1,2,3, тогда столбец list_id в вашей таблице листинга больше не нужен, в том же случае примените для своей таблицы пользователей и ее автоматически сгенерированные идентификаторы пользователей, теперь часть запроса вы используете несколько объединений, чтобы было перекрестное произведение, как указано @FuzzyTree, и выполнение агрегации в результирующем наборе даст вам неправильную результаты более чем ожидаются, так что вам нужен отдельный счет, поэтому я определил первичные ключи для таблиц, вместо того, чтобы подсчитывать v.views считать разные v.sno одинаковыми для похожих и комментариев

select l.*,
count(distinct v.sno) as views,
count(distinct li.sno) as likes,
count(distinct c.sno) as comments
from listings l
join likes li on(l.sno = li.list_id)
join comments c on(l.sno = c.list_id)
join `views` v on(l.sno = v.list_id)
where l.user_id = 'user100'
group by l.sno

Используя активную запись, вы можете написать свой запрос примерно как

$this->db->select ( 'l.*,
    count(distinct v.sno) as views,
    count(distinct li.sno) as likes,
    count(distinct c.sno) as comments' ,false)
    ->from ( 'listings as l' )
    ->join ( 'likes li', 'l.sno = li.list_id')
    ->join ( 'comments c', 'l.sno = c.list_id')
    ->join ( 'views v', 'l.sno = v.list_id')
    ->where ( 'l.user_id', $user_id)
    ->group_by( 'l.sno');

В соответствии с вашим предоставленным списком данных 1 имеет 3 понравившиеся, 3 просмотров и 1 комментарий, вы можете найти прикрепленную демо выше запроса, а также вы можете найти определения таблицы обновлений с помощью внешние ключи и каскадные (поможет поддерживать отношения)

Fiddle Demo

Редактировать сообщения, содержащие 0 понравлений/просмотров и комментариев

используя внутренние сообщения объединений с 0 понравившимися/представлениями и комментариями, не будут возвращены для этого, вам нужно присоединиться к объединению, вы можете увидеть обновленную демоверсию и используя активную запись, вы можете построить запрос, как показано ниже, определить тип соединения (left/internal/right ) в join() функция Третий параметр

$this->db->select ( 'l.*,
    count(distinct v.sno) as views,
    count(distinct li.sno) as likes,
    count(distinct c.sno) as comments' ,false)
    ->from ( 'listings as l' )
    ->join ( 'likes li', 'l.sno = li.list_id','left')
    ->join ( 'comments c', 'l.sno = c.list_id','left')
    ->join ( 'views v', 'l.sno = v.list_id','left')
    ->where ( 'l.user_id', $user_id)
    ->group_by( 'l.sno');

Updated Demo

Ответ 3

Если вы более подробно рассмотрите "неправильные" значения и взгляните на отдельные строки, которые вносят вклад в завышенные значения, вы обнаружите, что вы получаете одинаковые строки, подсчитанные несколько раз. (С внутренним соединением, если одна из таблиц имеет нулевые соответствующие строки, эта строка не будет возвращена.)

У вас есть классический кросс-продукт. Что происходит с операцией JOIN, каждая соответствующая строка из Likes получает "соответствие" каждой соответствующей строке из Views. Если в Views есть три соответствующие строки и три соответствующие строки в Likes, вы получите возвращаемые 3x3 строки.


Дизайн вашей базы данных выглядит нормально.

Это сгенерированный SQL-запрос, который является проблемой.

Чтобы исправить запрос,

либо избегать генерации кросс-продукта, либо считать разные строки *

Чтобы избежать перекрестного продукта, не JOIN для таблиц Likes и Views. В качестве альтернативы вы можете избежать операций объединения и вместо этого использовать коррелированные подзапросы в списке SELECT...

 SELECT list.*
      , (SELECT COUNT(1) FROM views v WHERE v.list_id = list.list_id) AS count_views
      , (SELECT COUNT(1) FROM likes l WHERE l.list_id = list.list_id) AS count_likes
   FROM list  
  WHERE ... 

или, если вы используете операцию JOIN и генерируете кросс-продукт, то получите количество уникальных строк, используя выражение типа COUNT(DISTINCT pk), поэтому вы не считаете одну и ту же строку более одного раза.

  SELECT list.*
       , COUNT(DISTINCT v.`s.no`) AS count_views
       , COUNT(DISTINCT l.`s.no`) AS count_likes

Чтобы разрешить возврат строк с нулевым числом, вы должны использовать внешние соединения:

    FROM list
    LEFT JOIN views v ON v.list_id = list.list_id
    LEFT JOIN likes l ON l.list_id = list.list_id

Как только вы поймете, что делает MySQL с инструкцией SELECT, которую генерирует ваш код, просто нужно выяснить инструкцию SQL, которая вернет результат, который вы хотите.

Как только вы получите инструкцию SQL, которая возвращает ожидаемые результаты, то это просто вопрос о том, чтобы заставить CodeIgniter запускать инструкцию SQL.

Ответ 4

select a.list_id,a.user_id,a.name,a.category,a.fees,a.details,a.created_on,
(select sum(likes) from  Likes where user_id=a.user_id) "total likes",
(select count(*) from  comments where user_id=a.user_id) "total comments",
(select sum(views) from  views  where user_id=a.user_id) "total views",
from Listings as a
where a.user_id ='user 100'

Ответ 5

любезно измените свой запрос, чтобы получить правильный счет, как показано ниже.

    $this->db->select ( 'list.*,count(v.views) as views,count(l.likes) as likes,count(c.comment) as comments' )
             ->from ( 'listings as list' )
             ->join ( 'comments c', 'c.list_id = list.list_id')
             ->join ( 'views v', 'v.list_id = list.list_id')
             ->join ( 'likes l', 'l.list_id = list.list_id');

        $this->db->where ( 'list.user_id', $user_id);
        $this->db->group_by( 'v.list_id');
        $this->db->group_by( 'l.list_id');
        $this->db->group_by( 'c.list_id');
      $query = $this->db->get ();

Ответ 6

Если вы боитесь слишком большого количества подключений, время, когда вы пытались выполнить инструкцию SQL IN. Сделайте что-нибудь вроде:

// You can include query binding if you like
$sql = SELECT column_name(s)
FROM table_name
WHERE column_name IN (SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1,value2,...) WHERE SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1,value2,...));