Altering a query to join 3 tables together - php

In my database, I have 3 tables.
Jokes:
CREATE TABLE IF NOT EXISTS `jokes` (
`joke_id` int(11) NOT NULL AUTO_INCREMENT,
`joke` varchar(1024) NOT NULL,
`category_id` int(11) NOT NULL,
`vote` int(255) NOT NULL,
`date_added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`joke_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Category:
CREATE TABLE IF NOT EXISTS `category` (
`category_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(51) NOT NULL,
PRIMARY KEY (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
And finally, Comments:
CREATE TABLE IF NOT EXISTS `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(40) NOT NULL,
`comment` text NOT NULL,
`joke_id` int(11) NOT NULL,
`post_id` int(11) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
I need to join all three tables together to get the category name of a joke, the joke itself, and the unique comments correlating to that specific joke_id.
For the moment I can only join two tables where the joke_id = 1. This will return the comments for that joke.
This function is stored in my read controller, with the name of Joke:
public function joke($joke_id = FALSE)
{
if ($joke_id === FALSE) redirect('main'); //go to default controller
$data['results'] = $this->comments_m->getComments($joke_id, $this->uri->segment(2));
$this->load->view('template/header');
$this->load->view('template/sidebar');
$this->load->view('content/read', $data);
$this->load->view('template/footer');
}
The model (getjokes_m) has a function called readJokes which grabs only the category, the joke, and the joke_id to read that one specific joke:
function readJokes($joke_id)
{
$query = $this->db->query("SELECT j.*, c.name FROM jokes j LEFT JOIN category c ON c.category_id = j.category_id WHERE joke_id = '$joke_id'") or die("No results found" );
//displays the results
return $query->result();
}
For the moment, this results in only getting the category name of a joke, and the joke itself. What i want is to grab the comments for this one joke as well. How can I alter my query to return the information that I need?
Edit:
This query seems to work:
SELECT c.name, j.*, co.* FROM jokes j LEFT JOIN category c ON c.category_id = j.category_id LEFT JOIN comments co ON co.joke_id = j.joke_id WHERE j.joke_id = '$joke_id'"
but at the same time, it grabs the joke as many times as the joke has been commented for some reason. I.e the joke has 6 comments, the joke is shown 6 times.

EDIT:
SELECT j.joke AS 'Joke', c.name AS 'Category', 'Comments : ' AS 'Comments'
FROM jokes j
LEFT JOIN category c ON c.category_id = j.category_id
WHERE j.joke_id = '1'
UNION
SELECT '' AS 'Joke', '' AS 'Category', c.comment AS 'Comments'
FROM comments c
WHERE c.joke_id = '1'
LIMIT 0 , 30
I don't have your data, it's hard to test, but you may want to try this one.
It's one query. A cleaner way would be to get the joke then for that joke id get the comments.

SELECT c.*, j.*, co.*
FROM jokes j
INNER JOIN category c ON c.category_id = j.category_id
INNER JOIN comments co ON co.joke_id = j.joke_id
WHERE j.joke_id = '1'
SQLFIDDLE DEMO

The query you show here is what you need
SELECT c.name, j.*, co.* FROM jokes j LEFT JOIN category c ON c.category_id = j.category_id LEFT JOIN comments co ON co.joke_id = j.joke_id WHERE j.joke_id = '$joke_id'"
or you can hit a separate query for comments by providing joke id. in fact using a separate query is good,as it reduce the fetch data volume if the number of comments is more.

Related

Rename a column in each join MySql

I have 2 tables, table1 has information about the producer (name of producer and their ID) of a resturant.
CREATE TABLE IF NOT EXISTS `fournisseur` (
`IdFournisseur` int(10) NOT NULL auto_increment,
`Fournisseur_Producteur` varchar(250) default NULL,
PRIMARY KEY (`IdFournisseur`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
table2 has dailymanue and the ID of thier producer(for exampe: IdMenuPlat, IdMenuEntree...).
CREATE TABLE IF NOT EXISTS `menu_jours` (
`menu_id` int(10) NOT NULL auto_increment,
`menu_j_titre` varchar(250), `menu_date_parution`,
`menu_entree` int(10),
`IdMenuEntree`,`menu_plat`,`IdMenuPlat`,`menu_acc1`,`IdMenuAcc1`,`menu_acc2`,`IdMenuAcc2`,`menu_sugg`,`IdMenuSugg`,`menu_sugg_acc`,`IdMenuSuggAcc`,`menu_dessert`,`IdMenuDessert` default NULL,
PRIMARY KEY (`menu_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
I want to recover daily menu with the name of their producer!
I used this query:
todaySQL = 'SELECT * FROM table2 AS t2
INNER JOIN table1 AS t1_1 ON (t1_1.IdProducter= t2.IdMenuPlat)
INNER JOIN table1 AS t1_2 ON (t1_2.IdProducter= t2.IdMenuEntree)
INNER JOIN table1 AS t1_3 ON (t1_3.IdProducter= t2.IdMenuAcc1)
INNER JOIN table1 AS t1_4 ON (t1_4.IdProducter= t2.IdMenuAcc2)
INNER JOIN table1 AS t1_5 ON (t1_5.IdProducter= t2.IdMenuSugg)
INNER JOIN table1 AS t1_6 ON (t1_6.IdProducter= t2.IdMenuSuggAcc)
INNER JOIN table1 AS t1_7 ON (t1_7.IdProducter= t2.IdMenuDessert)
WHERE menu_date_parution = \''.$todayDate.'\'' ;
but if I use this function:
todayRow = mysql_fetch_row( todaySQL )
I have all information in array by their index which is confusing for programming I would like to use this function:
todayRow = mysql_fetch_assoc( todaySQL )
which recover in array by the name of columns, but the problem is that I just have the infortmaion of the last producer ,not for the information of the all.
I think I should rename the column's name of producer(Fournisseur_Producteur) for each join. But how?
If i understand well, you dont use a loop to fetch the results.
You need a for or a while:
while($row=mysql_fetch_assoc($todaySQL)) {
echo $row['menu_id'];
}

Getting data from all three tables using a query (SQL)

In my database, I have 3 tables.
Jokes:
CREATE TABLE IF NOT EXISTS `jokes` (
`joke_id` int(11) NOT NULL AUTO_INCREMENT,
`joke` varchar(1024) NOT NULL,
`category_id` int(11) NOT NULL,
`vote` int(255) NOT NULL,
`date_added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`joke_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Category:
CREATE TABLE IF NOT EXISTS `category` (
`category_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(51) NOT NULL,
PRIMARY KEY (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
And finally, Comments:
CREATE TABLE IF NOT EXISTS `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user` varchar(40) NOT NULL,
`comment` text NOT NULL,
`joke_id` int(11) NOT NULL,
`post_id` int(11) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
These three tables need to be joined together to get data from each. So far i have used these three queries with no luck in getting what i need.
what i need this query to do is
Assign the joke_id to the joke_id in the comments, and also displays the joke_id in the view.
Assign the category_id of a joke to the name and display it
grab the votes
grab the jokes
1st query - this query does actually grab all the data i want, but at the same time does not grab the joke_id and pass it to view (as i need the joke_id to assign comments to that unique id):
SELECT j.*, c.name,
co.* FROM jokes j LEFT
JOIN category c ON c.category_id
= j.category_id LEFT JOIN
comments co ON co.joke_id =
j.joke_id WHERE j.joke_id = '$joke_id'
2nd query - This query joins the category to the correct one, and displays the joke and joke_id for me to assign comments to. But it does not show any comments
SELECT j.*, c.name
FROM jokes j LEFT JOIN category c
ON c.category_id = j.category_id
WHERE joke_id = '$joke_id'
3rd query - This query was provided by a user on stack overflow, but seems to throw a tonne of errors my way when a there is no comment attatched to that joke
SELECT c.*, j.*, co.*
FROM jokes j
INNER JOIN category c ON c.category_id = j.category_id
INNER JOIN comments co ON co.joke_id = j.joke_id
WHERE j.joke_id = '$joke_id'
Any help altering this query to get all the items in the three database together would be much appreciated!
Edit the selected fields to suits your needs. Also if you want to display only one joke and its data you have to set the id of the joke you want as you did on the WHERE for instance.
SELECT jokes.*, category.*, comments.* FROM jokes LEFT JOIN category ON jokes.category_id = category.category_id LEFT JOIN comments ON jokes.jokes_id = comments.joke_id

Altering a query to not duplicate data

In my database, I have 3 tables.
Jokes:
CREATE TABLE IF NOT EXISTS `jokes` (
`joke_id` int(11) NOT NULL AUTO_INCREMENT,
`joke` varchar(1024) NOT NULL,
`category_id` int(11) NOT NULL,
`vote` int(255) NOT NULL,
`date_added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`joke_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Category:
CREATE TABLE IF NOT EXISTS `category` (
`category_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(51) NOT NULL,
PRIMARY KEY (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
And finally, Comments:
CREATE TABLE IF NOT EXISTS `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(40) NOT NULL,
`comment` text NOT NULL,
`joke_id` int(11) NOT NULL,
`post_id` int(11) NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
This function is stored in my read controller, with the name of Joke and it grabs the data from the db then sends it to the view.
public function joke($joke_id = FALSE)
{
if ($joke_id === FALSE) redirect('main'); //go to default controller
$data['results'] = $this->comments_m->getComments($joke_id, $this->uri->segment(2));
$this->load->view('template/header');
$this->load->view('template/sidebar');
$this->load->view('content/read', $data);
$this->load->view('template/footer');
}
The model (getjokes_m) has a function called readJokes which gets the joke, joke_id, category name, votes, comments. This function is used to read specific jokes in the database.
function readJokes($joke_id)
{
$query = $this->db->query("SELECT c.name, j.*, co.* FROM jokes j LEFT JOIN category c ON c.category_id = j.category_id LEFT JOIN comments co ON co.joke_id = j.joke_id WHERE j.joke_id = '$joke_id'") or die("No results found" );
//displays the results
return $query->result();
}
The query above is where the problem lies. For the moment it returns the joke as many times as the joke has been commented. I.e if the joke has 6 comments, the joke will show 6 times (no idea why). Any help altering this query, to just show the joke once, with all the comments the joke has, will be much appreciated.
You want a group by with group_concat() for the comments:
SELECT c.name, j.*, group_concat(co.comment separator '|') as comments
FROM jokes j LEFT JOIN
category c
ON c.category_id = j.category_id LEFT JOIN
comments co
ON co.joke_id = j.joke_id
WHERE j.joke_id = '$joke_id'
GROUP BY j.joke_id;
Actually the group by is not strictly needed here, unless you want to get the results for more than one joke.

Multi-table SQL search query

I am writing an app that interacts with a MySQL database.
I have 3 tables, 'categories', 'books' and 'book_category'.
/* stores properties for categories */
`categories` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(140) NOT NULL UNIQUE,
PRIMARY KEY (`id`)
);
/* stores properties for books */
`books` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` int(11) NOT NULL,
`read` tinyint(1) NOT NULL default 0,
`creation_date` timestamp NOT NULL default CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
);
/* matches books against categories */
`book_category` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`category_id` int(11) NOT NULL,
`item_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
);
I have 2 variables to perform the search.
<?php
$categoryString = 'python'; // books saved under python
$readBool = 1; // all books that have been read
?>
I would like to write the following SQL query:
Select all python books that have been read(i.e, book.read = 1).
My SQL knowledge is very limited, please help.
This should do the trick:
SELECT books.id, books.title, books.`read`, categories.name
FROM books
INNER JOIN book_category ON books.id = book_category.item_id
INNER JOIN categories ON book_category.category_id = categories.id
WHERE books.read = 1
AND categories.name = 'python'
And here's an SQL fiddle to demonstrate.
Just try this-
select * from book_category
LEFT JOIN books ON book_category.item_id = books.id
LEFT JOIN category ON category.id = book_category.category_id
WHERE category.name = 'python' AND
book.read = 1
select b.title
from books b
left join book_category bc on (b.id=bc.item_d)
left join categories c on (c.id=bc.category_id)
where b.read=1 and c.name='python'
SELECT * FROM books WHERE id IN (
SELECT item_id FROM book_category WHERE category_id IN (
SELECT id FROM category WHERE name = 'Python'
)
)
SELECT *
FROM books AS b
INNER JOIN book_category AS bc
ON bc.item_id = b.id
INNER JOIN categories AS c
ON c.id = bc.category_id
WHERE b.read = 1 AND c.name='python'
SELECT b.title
FROM books b, categories c, book_category bc
WHERE b.id = bc.item_id
AND c.id = bc.category_id
AND b.read
AND c.name = 'python'
To make sure that your query works fast, make sure that you have following indexes:
books(id)
categories(id, name)
book_category(item_id)
book_category(caregory_id)
Try this
"select b.title from category c INNER JOIN book_category bc on bc.category_id = c.id INNER JOIN book b on b.id = b.id where b.read = '1' and c.name = 'python'";

how do I output the rowName based on a linking table?

I need to output A_Name, B_Name, and C_Name. from tableA, tableB, tableC. I have a linking table containing all the ID's of the above, e.g:
CREATE TABLE `tableLink` (
`tableLinkID` int(5) NOT NULL auto_increment,
`A_ID` int(11) NOT NULL,
`B_ID` int(5) NOT NULL,
`C_ID` int(5) NOT NULL,
PRIMARY KEY (`tableLinkID`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8 AUTO_INCREMENT=17 ;
My question: I need to know how to SELECT based on having C_ID, how to select and output A_ID's [A_Name], B_ID's [B_Name], and C_ID's [C_Name].
I hope this is clear enough.
(I have the C_ID in a variable)
Try using JOINs:
SELECT
tableA.A_Name,
tableB.B_Name,
tableC.C_Name
FROM tableLink
JOIN tableA ON tableLink.A_ID = A.ID
JOIN tableB ON tableLink.B_ID = B.ID
JOIN tableC ON tableLink.C_ID = C.ID
WHERE tableLink.C_ID = 42

Categories