Create a table of results using 3 tables - php

I have 3 tables in a mysql database that I want to query:
courses (id, course_name)
college_courses (id, college_id, course_id, num_of_courses)
student_courses (id, course_id, college_id)
I am trying to pass an array of course ids to the query and a college id. I want to create a result set to show the name of each course (based on the ids I pass), how many courses the college (e.g. id=8) has access to and how many of each course have been assigned to students. I've tried building a query using joins and sub queries. This is what I have right now but the numbers for courses assigned to colleges and students are all wrong:
SELECT
courses.course_name,
COALESCE(SUM(
CASE
WHEN
college_courses.college_id = 8
THEN
college_courses.num_of_courses
ELSE
0
END
), 0) AS total, COUNT(
CASE
WHEN
student_courses.college_id = 8
THEN
student_courses.id
ELSE
0
END
) AS usedCourses
FROM
courses
LEFT JOIN
college_courses
ON college_courses.course_id = courses.id
LEFT JOIN
student_courses
ON student_courses.course_id = courses.id
WHERE
courses.id IN
(
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
)
GROUP BY
courses.courseid

Related

Build MySql Query with multiple where conditions

I have to build a some complicated mysql query. I have a table with some user informations, with 3 columns: id, id_user, id_campo, valore. So, for example:
1, 1, 1, "Roberto" (where id_campo=1 is for the user name);
2, 2, 1, "Luca";
3, 1, 2, "Windows"; (where id_campo=2 is for used OS);
4, 2, 2, "Linux";
and so on.
Now, I have to select users where: name="Roberto" AND os="Linux", but the same user :
SELECT id_user WHERE (id_campo=1 AND valore="Roberto") OR (id_campo=2 AND valore="Linux").
In this sample case, the query return id_user=1 and id_user=2 but I would obtain no result. How I can modify the query so I can include the condition "the same user" ?
Thanks!
You need to build two "subqueries" and then join them by user id.
SELECT a.id_user
from (
SELECT id_user FROM table
WHERE (id_campo=1 AND valore="Roberto")
) a,
(
SELECT id_user FROM table
WHERE (id_campo=2 AND valore="Linux")
) b
WHERE a.is_user = b.id_user
You have a wrong db design but anyway you can usie an inner join on the same table based on id_user
select a.id_user, a.id_campo, a.valore
from my_table as a
inner join my_table as b on .id_user = b-id_user
where ( a.id_campo = 1 and a.valore ='Roberto')
AND ( b.id_campo = 2 and b.valore ='Linux')

Search by Mutual Friends Count - Friend System Mysql PHP

I am creating a Friend System in my Forum.
I am having a tough time trying to figure out how I would grab users and order by the mutual_friend count.
I am trying to build a page that shows a list of recommended friends.
Here is my structure of tables:
users table
-----
user_id | name |
friends table
-----
friend_id | from_id | to_id
Here is an example of what is happening.
Suppose there are total of A,B,C,D,E,F = 6 people in the site.
I am A, and B,C are my friends.
D and E in turn are friends of B.
D is also a friend of C but E is not a friend of C.
F is not a friend of anyone in the site.
Therefore from above data it looks like D and E are mutual friends of me (A). F is not a mutual friend of mine.
Since D is a friend of both B and C and E is friend of only B:
A and D has 2 mutual friends.
A and E has 1 mutual friend.
A and F has 0 mutual friend.
Now if I want to search (remember i am A) for people who are not my friends I can do something like:
$myfriends = "2,3"; //putting all my friends in a variable
SELECT * FROM users WHERE user_id NOT IN( $myfriends )
But it will yield in terms of user_id ASC .
How can I make it search in DESC order of mutual_friends. ?
I am A i.e user_id = 1
i.e. Person with more mutual friends comes first
Please can anyone show me how can I do this? I have been stuck here for a long while. I searched for lots of thing but can't figure it out.
This query will take the reciprocity of relationships into account, so it doesn't matter if the relationship goes "From A to B" or "From B to A", it will still return the expected result. So given tables like this:
CREATE TABLE people
(`id` int, `name` varchar(1))
;
INSERT INTO people
(`id`, `name`)
VALUES
(1, 'A'),
(2, 'B'),
(3, 'C'),
(4, 'D'),
(5, 'E'),
(6, 'F')
;
CREATE TABLE friends
(`id` int, `personId1` int, `personId2` int)
;
INSERT INTO friends
(`id`, `personId1`, `personId2`)
VALUES
(1, 1, 2),
(2, 3, 1),
(3, 2, 4),
(4, 5, 2),
(5, 3, 4)
;
I believe this is set up as you described: A and B are friends, A and C are friends (notice the inverted relationship), B and D are friends, E and B are friends (another inverted relationship), and C and D are friends.
Assume the id of the person you want is in #personId:
SELECT StrangerId, COUNT(MutualFriendId) AS TotalMutualFriends
FROM
(SELECT
CASE WHEN f.personId2 = mf.friendId THEN f.personId1 ELSE f.personId2 END AS StrangerId,
CASE WHEN f.personId1 = mf.friendId THEN f.personId1 ELSE f.personId2 END AS MutualFriendId
FROM
(SELECT
CASE
WHEN personId1 = #personId THEN personId2
ELSE personId1
END AS friendId
FROM friends
WHERE personId1 = #personId OR personId2 = #personId) AS mf
INNER JOIN friends f
ON (personId1 != #personId AND personId2 = mf.friendId)
OR (personId1 = mf.friendId AND personId2 != #personId)
) AS totals
GROUP BY StrangerId
ORDER BY TotalMutualFriends DESC;
Results for #personId = 1 are:
StrangerId TotalMutualFriends
4 2
5 1
And here is a SQLFiddle to demonstrate (I couldn't get it to allow me to set up a variable, so there is a 1 in its place).
Something like this, perhaps:
Select user_id, friends.to_id, count(friend_of_friend.to_id)
from users left outer join
friends on users.user_id = friends.from_id left outer join
users as friend_user on friends.to_id = friend_user.user_id left outer join
friends as friend_of_friend on friend_user.user_id = friend_of_friend.from_id and friend_of_friend.to_id in (select to_id from friends where from_id = users.user_id)
Group by USER_ID, friends.to_id
Order by 3
Edit for clarity:
The logic of this query depends on joining the same table multiple times. The first two joins are pretty straight-forward, we are starting with a table of users, then joining in the friends table that links each user with all their friends. But then we join in the user table again, but this time using the "to" column - we are getting the user info for each friend. Since we can't have the same table name twice in a query, we give it an alias of "friend_user". Then we join the friends table again, based on the id in the friend_user table - this gives us all the friends of each original user's friends. Then we limit the friends of friends that we get back using the "Friend_of_friend.to_id in ..." to compare the friends of friends to a list of all of the original user's friends, which we bring in by a subquery - the section just after the "in" that is enclosed in parenthesis.

Sum more than 1 table from SQL on codeigniter

need a small help to figure out this situation.
I see that codeigniter is not supporting UNION and i want to figure out this method to get the total sum for 2 tables, with same id of product.
The issue is that on sum 2 tables, the values are duplicating or multiplicative.
Link to SQL Fiddle
Structure :
create table products
(id int, name varchar(9));
insert into products
(id, name)
values
(1,'Product 1'),
(2,'Product 2'),
(3,'Product 3');
create table p_items
(puid int, prid int, quantity int);
insert into p_items
(puid, prid, quantity)
values
(11,1,100),
(11,2,100),
(11,2,100),
(14,2,100),
(14,3,100),
(15,3,100);
create table s_items
(puid int, prid int, quantity int);
insert into s_items
(puid, prid, quantity)
values
(11,1,1),
(11,2,1),
(11,2,1),
(13,2,1),
(15,3,1),
(13,3,1);
Execute in normal SQL:
select a.puid, b.name, a.prid, sum(a.quantity) as P_ITEMS, sum(c.quantity) as S_ITEMS
from p_items a
join products b
on b.id = a.prid
join s_items c
on c.prid = a.prid
group by a.prid;
Codeigniter Function:
$this->alerts
->select('products.id as productid, products.name, sumt(p_items.quantity), sum(s_items.quantity)', FALSE)
->from('products')
->join('p_items', 'products.id = p_items.prid', 'left')
->join('s_items', 'products.id = s_items.prid')
->group_by("products.id");
echo $this->alerts->generate();
Any help is very appreciated.
Your problem is your producing a cartesian product and thus getting your duplicated sums. Look at Product ID 3 for example. You're associating that with p_items prid = 3. By itself, that would return you 200. However, once you then join on s_items prid = 3, now for each row in s_items, it has to match with each row in p_items. Meaning:
14 3 100 15 3 1
14 3 100 15 3 1
15 3 100 15 3 1
15 3 100 15 3 1
---------------
400 4
Besides the product table, which table is your master table? If you use p_items, you want get row 13 from s_items. Likewise, if you use s_items, you won't get rows 14 from p_items.
You can accomplish this using a subquery:
select b.id,
b.name,
P_ITEMS,
S_ITEMS
from products b
left join
(SELECT prid, SUM(quantity) as P_Items
FROM p_items
GROUP BY prid)
a on b.id = a.prid
left join
(SELECT prid, SUM(quantity) as S_Items
FROM s_items
GROUP BY prid)
c on c.prid = a.prid
group by b.id, b.name
And the updated Fiddel: http://sqlfiddle.com/#!2/62b45/12
Good luck.
If the best way to get the answer you want is with a union query, and codeigniter does not let you write one, don't use codeigniter to write your query. Put it in a stored procedure and call the stored procedure with codeigniter.

get random 5 rows from each category where the main table and category table have one to many relation ship

Here is the situation i have two tables
of
idof, (somtother data)
---------------------
1, (somtother data)
2, (somtother data)
3, (somtother data)
and i have
ofc
id, ofid, idcat
------------------
1,1,1
1,1,2
1,2,1
1,3,3
Here is what i use to get all from first table and joint it with second
SELECT * FROM `of`
LEFT JOIN (`ofc`)
ON ( `of`.`idof` = `ofc`.`ofid` )
Now i want to get 5 rows from of (imagine that second table has more rows) for each idcat, and i cant seem to get the sql right. i have done till now
select * from `of` as `f`
JOIN `ofc` as `fa`
ON `f`.`idof`=`fa`.`ofid`
where (
select count(*) from `of` as `nf`
JOIN `ofc` as `nfa`
ON `nf`.`idof`=`nfa`.`ofid`
GROUP BY `nfa`.`idcat`
) <= 5;
Bit this subquery returns more than one row, and mysql complains. is there any other way to do this?without executing one query for each different idc?

i try to select data from multiple tables with four indexes

I have two tables and i try to create a table for managing data.
the first table is "questions":
questions (question_id, key1, key2, key3, key4, user_id, creation_date, class, type permission)
and the other:
questions_keys (question_key_id, question_key_name, question_key_refers_to)
every time i push the submit button stored in the table question_keys four records and one in table of questions. heres an example:
question_keys:
1, mathematics, 0
2, history, 1
3, physics, 2
4, geography, 3
and question table:
(1, 1, 2, 3, 4, 8, 2012-12-19 20:41:48, 4, multiple_choice, 0)
the query i need: in the table show the question_key_name where key1, key2, key3, key4 in table questions is equal to question_key_id.
and show in one row something like this:
mathematics, history, physics, geography, multiple_choice, 2012-12-19 20:41:48 etc
i'm new and i need your help.. thanks a lot!
Try this:
SELECT qk1.question_key_name qk2.question_key_name, qk3.question_key_name,
qk4.question_key_name, q.type, q.creation_date
FROM questions q
INNER JOIN question_keys qk1 ON q.key1 = qk1.question_key_id
INNER JOIN question_keys qk2 ON q.key2 = qk2.question_key_id
INNER JOIN question_keys qk3 ON q.key3 = qk3.question_key_id
INNER JOIN question_keys qk4 ON q.key4 = qk4.question_key_id;
You'll have to join the tables four times with this design:
SELECT question_key_name
FROM question_key qk
JOIN questions q on q.key1 = qk.question_key_id
WHERE q.question_id = ?
and then repeat for the other 3. You can UNION them all together, which would return you 4 rows.
As for returning only one row, check out GROUP_CONCAT, but that will return you the question_key_name values as one column. You may be better off combining the 4 rows in your app code.

Categories