get data between two table - php

i have to table sql table1 for question and table2 for comment
i want to get post has the largest number of comments
how can to this between two table ??
table question like this
id title
----- -------
1 title1
2 title2
3 title3
4 title4
table comment like this
id content questid
----- ------- --------
1 test 1
2 test 3
2 test 3
2 test 3
my code
$gquest = $DB_con->prepare("SELECT * FROM `question` ORDER BY id DESC");
$gquest->execute();
foreach ($gquest->fetchAll() as $rowL)
{
$cat = $DB_con->prepare("SELECT * FROM `comment` WHERE `questid`=".$rowL['id']."");
$cat->execute();
$cominf = $cat->fetch(PDO::FETCH_ASSOC);
$countquest = $cat->rowCount();
$gqt = $DB_con->prepare("SELECT * FROM `question` ORDER BY ".$cominf['id']." DESC");
$gqt->execute();
$cfr = $gqt->fetch(PDO::FETCH_ASSOC);
}

You can get what you're looking for from a single query by joining the two tables on the question ID and then COUNT() the number of comment occurrences for each question. Here is an example of what it could look like:
$gquest = $DB_con->prepare("
SELECT q.*, COUNT(c.questid) AS num_comments
FROM question q
JOIN comment c
ON q.id = c.questid
GROUP BY q.id
ORDER BY num_comments DESC
LIMIT 1;
");
Here's an SQL fiddle

Related

How should be my mysql table structure?

This is what I want:
Users will send one or two values in my website and I will store them in two variables $genres1 and $genres2.
Like: If user sends, Action, then my code will show all movies with Action genres. If user sends Action+Crime, then my table will fetch all movies with Action+Crime.
Got it?
My current table structure is one to many relationship, like this
tmdb_id movie_title
-----------------------------
1 Iron man
2 Logan
3 Batman
4 The hangover
tmdb_id genres
-----------------------------
1 Action
1 Crime
2 Drama
2 Action
3 Crime
3 Action
4 Comedy
4 Drama
But the problem here is, I can't achieve what I explained above with this.
2nd option: I make a single table like this:
movie_tile genres1 genres2 genres3 genres4
----------------------------------------------------
Logan Action Crime Drama Null
Iron man Action Crime Null Null
And I can do what, I want with this single line:
SELECT * FROM movies WHERE (genres1='$genres1' or genres2='$genres1' orgenres1='$genres3' or genres3='$genres1')
Any other option?
use a table width genres
and use an other table connecting the movie to any genre
-----
movieid title
-----
1 Logan
2 Smurf
-----
-----
genreid genre
-----
1 animated
2 blue people
-----
-----
movieid genreid
-----
1 1
2 1
2 2
-----
that way you won't be limited to 4 genres per movie
now I read your question better.
That's what you do, but you put left out the genre-table.
The 2nd option is bad, as you limit yourself to only 4 categories
Is this connected to PHP? I think is easiest to solve this further by a join query, sorted by movie and a loop in PHP
you want all movies where (by user request) the genres are both Crime And Action?
SELECT mg.movieid, count(1), m.title
FROM movies_genres mg
JOIN movies m ON m.movieid mg.movieid
WHERE mg.genreid = 1 OR mg.genreid =3
group by mg.movieid, m.title
HAVING COUNT(1) = 2
edit: see other genres as well
SELECT movies.movieid,movies.title, genres.genre
FROM movies
JOIN movie_genre mg ON mg.movieid = movies.movieid
JOIN genres on genres.genreid = mg.genreid
WHERE movie.movieid IN (
SELECT mg.movieid
FROM movies_genres mg
WHERE mg.genreid = 1 OR mg.genreid =3
GROUP BY mg.movieid
HAVING COUNT(1) = 2
)
forgot to mention: count = 2, means you gave 2 genreid's to find. This could also be 1, 3 or 25
select distinct a.tmdb_id, a.movie_tittle
from movie_tittle a inner join genre_tittle b
on a.tmdb_id = b.tmdb_id
where b.genres in ('Action', 'Crime')
Based on your comment, try this :
SELECT
a.tmdb_id, a.movie_tittle
FROM
movie_tittle a inner join genre_tittle b
ON
a.tmdb_id = b.tmdb_id
WHERE
b.genres in ('Action', 'Crime')
GROUP BY
a.tmdb_id, a.movie_tittle
HAVING
count(a.tmdb_id) = 2
tmdb_id and genres in table genre_tittle should not duplicated. Make it as primary key.
But the problem here is, I can't achieve what I explained above with [the first two tables]
Yes, you can. Assuming the two tables are called movies and movie_genres, you can select the movies which have both tags using:
SELECT movie_title FROM movies
JOIN movie_genres genre1 USING (tmdb_id)
JOIN movie_genres genre2 USING (tmdb_id)
WHERE genre1.genres = 'Action'
AND genre2.genres = 'Crime'
See it for yourself here.
try something like this :
tableA
Movie_ID Movie_title
1 Iron man
2 Logan
3 Batman
4 The hangover
tableB
Genre_ID Genre_title
1 Action
2 Crime
3 Drama
4 Comedy
tableC
ID Movie_ID Genre_ID
1 1 1
2 1 2
3 2 2
4 2 3
query :
Select A.Movie_title,B.Genre_title
from tableC C
inner join tableA A on A.Movie_ID = C.Movie_ID
inner join tableB B on B.Genre_ID = C.Genre_ID
where
C.Genre_ID in (IFNULL(val1,0),IFNULL(val2,0))
you should make a relational table to solve you issues like so
movie table
movie_id movie_name genre_id
1 alien 2
2 logan 1
3 ps i love you 4
4 click 3
then you will need a genre table
genre table
genre_id genre_type
1 action
2 sci fi
3 comedy
4 romance
then your select would link the to tables
function get_movies_by_genre($genre_id) {
global $MySQLiConnect;
$query = '
SELECT *
FROM movies m
INNER JOIN genre g ON (g.genre_id = m.genre_id)
WHERE g.genre_id = ?
';
$stmt = $DBConnect->stmt_init();
if ($stmt->prepare($query)) {
$stmt->bind_param("i", $genre_id);
$stmt->execute();
$result = $stmt->get_result();
$rows = $result->fetch_all(MYSQLI_ASSOC);
$stmt->close();
}
return $rows;
}
or
function get_movies_by_genre($genre_id) {
global $MySQLiConnect;
$query = '
SELECT *
FROM movies m
INNER JOIN genre g ON (g.genre_id = m.genre_id)
WHERE g.genre_name = ?
';
$stmt = $DBConnect->stmt_init();
if ($stmt->prepare($query)) {
$stmt->bind_param("i", $genre_id);
$stmt->execute();
$result = $stmt->get_result();
$rows = $result->fetch_all(MYSQLI_ASSOC);
$stmt->close();
}
return $rows;
}
This is the base function to get you all information from the movie table depending on which genre id you send to it.
as for multiple ids you can then run the function through a foreach loop for as many genre_ids as you need and then display them as you need.
I hope this helps.

how can select data from two tables in php

I have two tables news and topics
news topics
id title text id title text
--- ----- ---- --- ----- ----
1 abc aa 1 hgd hh
2 def bb 2 ddf ff
3 gfs cc 3 gty gg
4 sdfv dd 4 bbc tt
i want to select title the two tables
i tried this code but it sin't work
<?
$select_newtopics = $mysqli->query("select * from news,arts order by id desc");
$num_newtopics = $select_newtopics->num_rows;
while ($rows_newtopics = $select_newtopics->fetch_array(MYSQL_ASSOC)){
$id_newtopics = $rows_newtopics ['id'];
$title_newtopics = $rows_newtopics ['title'];
echo $title_newtopics."<br>";
}
?>
Assuming you want a result set that contains all the (unique) titles from both tables, regardless of whether or not the tables are related in any way...
SELECT title FROM news
UNION
SELECT title FROM topics
See MySQL's UNION documentation for more details, options, and specifics.
To display the results, it's mostly the same as your previous code:
$select_newtopics = $mysqli->query("SELECT title FROM news
UNION
SELECT title FROM topics");
$num_newtopics = $select_newtopics->num_rows;
while ($row = $select_newtopics->fetch_array(MYSQL_ASSOC)) {
echo $row['title'] . '<br>';
}
Since I don't see a key tying the 2 tables together, you can use UNION reference google for additional info, example below:
SELECT title FROM news
UNION
SELECT title FROM topics;
Your table have to share an id for example added news_id to topics table to link the two table
news topics
id title text id title text news_id
--- ----- ---- --- ----- ---- -------
1 abc aa 1 hgd hh 1
2 def bb 2 ddf ff 2
3 gfs cc 3 gty gg 3
4 sdfv dd 4 bbc tt 4
Please update your database structure and you can use JOIN
<?
$select_newtopics = $mysqli->query("SELECT news.id AS newsId,
news.title AS newsTitle,
news.text AS newsText,
topics.id AS topicId,
topics.title AS topicTitle,
topics.text AS topictext
FROM topics
LEFT JOIN news ON topics.news_id = news.id
ORDER BY topics.id
DESC");
$num_newtopics = $select_newtopics->num_rows;
while ($rows_newtopics = $select_newtopics->fetch_array(MYSQL_ASSOC)){
$id_newtopics = $rows_newtopics ['topicId'];
$title_newtopics = $rows_newtopics ['topicTitle'];
echo $title_newtopics."<br>";
}
?>

SQL joining other table with condition

I have this query:
SELECT *
FROM `classes`
JOIN `classes_students`
ON `classes`.`id` = `classes_students`.`class`
And I need to add condition for selecting just classes, in which are not currently logged student (user ID is not in classes_students connected with class id) and also count how many students are in that class.
Table structure:
classes: id, name, etc
classes_students: class_id, user_id, etc
Table data:
classes:
1 | test
2 | test2
3 | test3
classes_students:
1 | 1
1 | 2
2 | 3
3 | 4
3 | 5
Expected output if im user with id 1:
classes names (with number of students in):
2 (1 student)
3 (2 students)
All this in one query. It is possible? If yes, how?
Select classid, count(*)
from class
left join student on student.classid = class.classid
group by classid
Glad help for you
Try this query:
$user_id = 1; // current user_id
$query = "SELECT `classes`.`id`, `classes`.`name`, COUNT(*) as students FROM `classes`
JOIN `classes_students`
ON `classes`.`id` = `classes_students`.`class_id`
AND `classes_students`.`user_id` != $user_id
GROUP BY `classes_students`.`class_id`
";
I figured it out! :)
Thank you guys for ur help.
$user_id = 1; // current user_id
$query = "SELECT `classes`.`id`, `classes`.`name`, COUNT(*) as students FROM `classes`
LEFT JOIN `classes_students`
ON `classes`.`id` = `classes_students`.`class_id`
WHERE `classes`.`id` NOT IN (SELECT `class_id` FROM `classes_students` WHERE `user_id`='.$user_id.')
GROUP BY `classes_students`.`class_id`
";

Mysql join with latest update in 4 tables

Hi here is my tables..
Table Sites
sid sname uid
---- ---------- ----
1 aaa.com 1
5 bbb.com 1
Table keywords_s
kid skeywoird
---- ----------
1 word1
2 word2
Table matchon
mid uid sid kid
---- ------ ----- -----
1 1 1 1
2 1 1 2
Table rank
mid rank dateon url
---- ------ ------- -----
2 7 08-May-2014 bbb.com/a
2 6 09-May-2014 bbb.com/2
And my query
"SELECT
keywords_s.skeyword,
keywords_s.kid,
sites.sname,
rank.rank,
rank.url,
rank.dateon
FROM matchon
Inner JOIN sites ON sites.sid = matchon.sid
Inner JOIN keywords_s ON keywords_s.kid = matchon.kid
Inner JOIN rank ON rank.mid = matchon.mid
where matchon.uid = :uid and sites.sname = :sname and sites.deactive != '1'
group by keywords_s.skeyword order by rank.rank
"
I am getting output
rank keyword dateon url
---- --------- ------- -----
7 word2 08-May-2014 bbb.com/a
Output needed is
rank keyword dateon url
---- --------- ------- -----
6 word2 09-May-2014 bbb.com/2
Here what i want to get ...
1st Group by keywords_s.skeyword order by rank.rank (this is coming But)
2nd Order by rank.slno desc (not working)
(I need 2nd order to work so i can get latest rank and date with, group by skeyword and order by rank)
SELECT keywords_s.skeywor
, keywords_s.kid
, sites.sname
, rank.rank
, rank.url
, rank.dateon
FROM matchon JOIN sites ON sites.sid = matchon.sid
JOIN keywords_s ON keywords_s.kid = matchon.kid
JOIN rank ON rank.mid = matchon.mid AND
rank.dateon = (SELECT MAX(dateon) FROM rank WHERE mid = matchon.mid)
WHERE matchon.uid = :uid and sites.sname = :sname and sites.deactive != '1'
GROUP BY keywords_s.skeyword order by rank.rank
This should work as per your requirement
"Select * from(SELECT
keywords_s.skeyword,
keywords_s.kid,
sites.sname,
rank.rank,
rank.url,
rank.dateon
FROM matchon
Inner JOIN sites ON sites.sid = matchon.sid
Inner JOIN keywords_s ON keywords_s.kid = matchon.kid
Inner JOIN rank ON rank.mid = matchon.mid
where matchon.uid = :uid and sites.sname = :sname and sites.deactive != '1'
order by rank.rank desc)xyz
group by xyz.skeyword
"

How to limit / offset query that returns several rows per unique ID?

My issue is that I need to paginate data from this query:
function search($search_term, $limit, $offset)
{
$id = $this->auth->get_user_id();
$query = $this->db->query("
SELECT user_id,
first_name,
cars_name,
cars_id
FROM user_profiles
LEFT JOIN cars
ON cars.id_fk = user_id
WHERE user_id NOT LIKE '$id'
AND activated = 1
AND banned = 0
AND first_name LIKE '%$search_term%'
ORDER BY first_name ASC
");
$search_data = array();
foreach ($query->result() as $row) {
$search_data[$row->user_id]['name'] = $row->first_name;
$search_data[$row->user_id]['cars'][$row->cars_id] = array(
'cars_name' => $row->cars_name);
}
return $search_data;
}
A sample data table / query response would be:
1 JOE HONDA 123
1 JOE TOYOTA 124
2 MAC VW 125
2 MAC HONDA 126
2 MAC TESLA 127
3 STU SUBARU 128
3 STU KIA 129
-----------
Page 1
-----------
1 JOE HONDA 123
TOYOTA 124
2 MAC VW 125
HONDA 126
------------
Page 2
------------
3 STU SUBARU 128
KIA 129
If I enter a limit and offset at the end of MySQL query
...
LIMIT $limit
OFFSET $offset;
");
the limit and offset are applied to the total number of rows, not the the number of rows grouped by user.
I've tried using GROUP BY but was unable to make it work.
My goal is to make the query as above but LIMIT and OFFSET the query by a number of rows that counts users, not all rows.
Any ideas?
I don't see a way to do this in one query. My solution would be to get the count of unique ID's using a group by query with the same parameters:
SELECT COUNT(1) AS uid_count
FROM user_profiles
LEFT JOIN cars
ON cars.id_fk = user_id
GROUP BY user_profiles.user_id
WHERE user_id NOT LIKE '$id'
AND activated = 1
AND banned = 0
AND first_name LIKE '%$search_term%'
Then fetch the uid_countmysql_num_rows and use that to calculate pagination variables for the above query.
The solution really is to use a GROUP BY clause:
SELECT SQL_CALC_FOUND_ROWS
user_id,
first_name,
cars_name,
cars_id
FROM user_profiles
LEFT JOIN cars
ON cars.id_fk = user_id
WHERE user_id NOT LIKE '$id'
AND activated = 1
AND banned = 0
AND first_name LIKE '%$search_term%'
GROUP BY user_id
ORDER BY first_name ASC
LIMIT 100
The order is important. GROUP BY first, then ORDER BY, and then OFFSET/LIMIT.
Notice the SQL_CALC_FOUND_ROWS up there? After the query has executed, if you want to get the total row count (including those who aren't returned because of the LIMIT clause), just use:
SELECT FOUND_ROWS() AS `count`
And fetch the count column.
However, like you said, the rows will collapse and you will lose some cars_name and cars_id values.
Another solution is to use GROUP_CONCAT, then split it in PHP:
SELECT
user_id,
first_name,
GROUP_CONCAT(cars_name SEPARATOR ','),
GROUP_CONCAT(cars_id SEPARATOR ','),
FROM user_profiles
LEFT JOIN cars
ON cars.id_fk = user_id
WHERE user_id NOT LIKE '$id'
AND activated = 1
AND banned = 0
AND first_name LIKE '%$search_term%'
ORDER BY first_name ASC
LIMIT 100
This would give you something like:
1 JOE HONDA,TOYOTA 123,124
2 MAC VW,HONDA,TESLA 125,126,127
3 STU SUBARU,KIA 128,129
If you want to get a list like this
Page 1
----------------------
1 JOE HONDA 123
1 JOE TOYOTA 124
Page 2
----------------------
2 MAC VW 125
2 MAC HONDA 126
2 MAC TESLA 127
Page 3
----------------------
3 STU SUBARU 128
3 STU KIA 129
Forget about limit, do this instead:
A - First retrieve a list of user id's and insert that into a temp table
CREATE TEMPORARY TABLE `test`.`temp_user_ids` (
`id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INTEGER UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
)
ENGINE = MEMORY
B - Next insert the relavant user_id's into the table.
INSERT INTO temp_user_ids
SELECT null, user_id
FROM user_profiles
LEFT JOIN cars
ON cars.id_fk = user_id
WHERE user_id NOT LIKE '$id'
AND activated = 1
AND banned = 0
AND first_name LIKE '%$search_term%'
ORDER BY user_id DESC /*insert in reverse order !*/
The lowest user_id is the last_insert_id in the temptable, and the temp_table
items are in sequential order.
C - Set the SQL #var #current_id to the last_insert_id in the temp_table.
SELECT #current_id:= LAST_INSERT_ID()
D - Next select relevant rows from the table, using only the user_id you want.
SELECT count(*) as row_count,
up.user_id,
first_name,
group_concat(cars_name) as car_names,
group_concat(cars_id) as car_ids,
FROM user_profiles up
LEFT JOIN cars
ON cars.id_fk = up.user_id
INNER JOIN temp_user_ids t
ON (t.user_id = up.user_id)
WHERE t.id = #current_id
GROUP BY up.user_id
ORDER BY cars.id
E - Now lower the #current_id
SELECT #current_id:= #current_id - 1;
F - And repeat step D and E until there's no more rows to be had.
The first field row_count tells you the number of rows aggregated in the fields
car_names and car_ids. You can separate these fields by using php's explode.

Categories