I have 4 tables:
Students with over 7000 records
Teachers with over 600 records
Universities with over 30 records
Lessons_Meta with over 10000 records
Table Students columns:
id | student_number | name
Table Teachers columns:
id | teacher_number | name
Table Universities columns:
id | name
Table Lessons_Meta columns:
id | lesson_code | lesson_name | student_id | teacher_id | university_id
My view is:
CREATE VIEW `view_lessons` AS
SELECT
*,
(SELECT `name` FROM `students` WHERE `students`.`id` = `lessons_meta`.`student_id` LIMIT 1) AS "student_name",
(SELECT `name` FROM `teachers` WHERE `teachers`.`id` = `lessons_meta`.`teacher_id` LIMIT 1) AS "teacher_name",
(SELECT `name` FROM `universities` WHERE `universities`.`id` = `lessons_meta`.`university_id` LIMIT 1) AS "university_name"
FROM `lessons_meta`
My query is:
SELECT * FROM `view_lessons` LIMIT 20
After 20 seconds, show this query completed! How can I decrease this time load?
You probably just need indexes. Start with the following indexes:
CREATE INDEX idx_students_id_name ON students(id, name);
CREATE INDEX idx_teachers_id_name ON teachers(id, name);
CREATE INDEX idx_universities_id_name ON universities(id, name);
Change your View to this
CREATE VIEW `view_lessons` AS
SELECT L.*, S.`name` AS student_name, T.`name` AS teacher_name, U.`name` AS university_name
FROM `lessons_meta` L
INNER JOIN `students` S ON S.`id` = L.`student_id`
INNER JOIN `teachers` T ON T.`id` = L.`teacher_id`
INNER JOIN `universities` U ON U.`id` = L.`university_id`
In the lessons_meta table, add indexes on student_id, teacher_id, university_id
On all tables, ensure that the id column is properly indexed, normally they should be unique/PK
Related
I am a beginner to Web programming and SQL. I am not used to work with tables that have a many to many relationship and I am facing a problem here due to my lack of knowledge.
Those are my tables and this is what I want to do:
Table users
ID | Users
-----------------
1 | John
2 | Mark
3 | Sophia
Table projects
ID | Projects
-----------------
1 | Generic Name nº 1
2 | Generic Name nº 2
3 | Generic Name nº 3
Table users_projects
UsersID | ProjectsID
-----------------
1 | 1
2 | 1
2 | 2
3 | 2
3 | 3
I want to select all the users where, let's say, the Projects.Id value is 1, while keeping the many to many realtionship between this two tables. How do I do that?
Desired Output
ID | Users
-----------------
1 | John
2 | Mark
SELECT t1.*
FROM users t1
JOIN users_projects t2 ON t1.id = t2.usersid
or
SELECT *
FROM users t1
WHERE EXISTS ( SELECT NULL
FROM users_projects t2
WHERE t1.id = t2.usersid )
I recommend you to rename ID columns in users and projects and assign them the same names which are used in users_projects. This will remove ambiguity and will make your structure and queries more clear.
If you want the result for Projects.Id value is 1 try:
select u.ID,u.Users
from users u
inner join users_projects p on u.ID=p.UsersID
where p.ProjectsID=1;
CREATE TABLE users (
ID int,
Users varchar(10) );
INSERT INTO users VALUES
(1,'John'),
(2,'Mark'),
(3,'Sophia');
CREATE TABLE users_projects (
UsersID int,
ProjectsID int );
INSERT INTO users_projects VALUES
(1,1),
(2,1),
(2,2),
(3,2),
(3,3);
Result:
ID Users
1 John
2 Mark
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=463a1cfac69f07d41a2caa440decdb25
You can try below, by using left join you specify on which fields to join.
You can use table aliases and prefix the fields with the alias to indicate between which table the fields are linked.
select u.Users, u.ID, p.Projects, p.ID
from Users u
left join user_project up
on u.ID = up.UsersID
left join projects p
on up.ProjectsID = p.projects
order by u.Users, p.Projects
I have two tables, one is called contacts and the other one is called numbers. One stores contact information and looks like this
contacts
-------------------------------------------------------
| id | fname | lname | email | address | uid | uniqid |
-------------------------------------------------------
My second table which stores phone numbers that belong to specific contact look like this
numbers
---------------------
| id | number | cid |
---------------------
The cid is the same as the uniqid on contact table, how can i get the contact row with its numbers which is on the second table through mysql?
Update
Correction to the correct answer
SELECT id ,fname ,lname ,email ,address , uid, uniqid,number
FROM contacts a
inner join (SELECT cid, GROUP_CONCAT(DISTINCT number SEPARATOR ',') number FROM numbers) b ON b.cid=a.uniqid
It was missing DISTINCT
use join
select id ,fname ,lname ,email ,address , uid, uniqid,number
from contacts a
inner join numbers b on b.cid=a.uniqid
You can use GROUP_CONCAT to get multiple numbers to one row and then when you imply the join you won't get duplicates.
select `id` ,`fname` ,`lname` ,`email` ,`address` , `uid`, `uniqid`,`number`
from `contacts` a
inner join (Select `cid`, GROUP_CONCAT(`number` seperator ',') `number` from `numbers`) b on b.cid=a.uniqid
You can map the two id's make sure you have this as table index, for faster retrieval of data.
SELECT id ,fname ,lname ,email ,address , uid, uniqid, number from contacts a, number b WHERE a.uniqid = b.cid;
Just use inner join with n.cid = c.uniqid
select c.id,c.fname,c.lname,c.email,c.address,c.uid,c.uniqid,n.number
from contacts c
inner join numbers n
on n.cid = c.uniqid
using join is the right choice here:
SELECT con.*,num.* from contacts as con inner join numbers as num on con.uniqid = num.cid
Here we are using the concept of foreign key . Here cid is foreign key of contact table on number table. we have to match primary key of contact table with the foreign key of number table. if both are match then it's show the result.
Select a.id, a.fname, a.lname, a.email, a.address,
a.uid, a.uniqid,b.number from contact a, number b where a.id=b.id;
This will probably be easy for allot of you guru's.
I am trying to get * from two tables.
First table i can match with a user_id. structure is as follows:
table name: order_new
id | service_id | user_id | total_price | total_price_tax | orderstatus | notes | orderdate
table name 2: order_new_items
id | id_order | name | qty | price
The first table ( order_new ) i can get by using the session id. that first table has a row called "id". That id has items in table 2 ( order_new_items ) under the row of "id_order".
Im not sure on how to join the two and pull all data from both tables matching id from first table and id_order from second table
SELECT * FROM order_new, order_new_items where order_new.id = order_new_items.id and order_new.id = 4711
This will retrieve all rows where an ID exists in bot tables. It will not retrieve rows from table order_new when there are no corresponding rows in order_new_items (i.e. empty order)
To achieve this, you need to use:
SELECT * FROM order_new
LEFT JOIN order_new_items on order_new.id = order_new_items.id
where order_new.id = 4711
probably you need to list columns explicitly instead of *
MySQL-Only:
SELECT * FROM order_new o, order_new_items i WHERE user_id = '7' AND o.id_order = i.id;
I'm assuming, that id from order_new is the primary key for the table, while id_order is the foreign key for the 1:n relationship.
To be noted, the 7 is an example of course and needs to be substituted with whatever value you're looking for.
According to comments, I'm answering another question:
$result = mysql_query("SELECT * FROM order_new WHERE user_id = 7");
while ($row = mysql_fetch_array($result)) {
//store order information
$res2 = mysql_query("SELECT * FROM order_new_items WHERE id_order = $row[id]");
while($row2 = mysql_fetch_array($res2)) {
//store further information
}
}
Try this, this will fetch you data from both tables based on conditon.
SELECT a*, b.id, b.name, b.qty, b.price FROM order_new a
INNER JOIN order_new_items b on b.id_order = a.id
WHERE a.id = 100
I have a customer table with million of records.
Customer
id | name | .....
I also have an orders table with
id | custID | orderDate | ....
I need to find all the people who have not placed an order for more than 30 days.It should also include people who have never placed the order
select name,customer.id from customer where id in
(select custID from orders where datediff(curdate(),orders.orderDate) > 30 )
union
select name,customer.id from customer left join orders on customer.id = orders.custID where orders.id is null
How can i optimize the query ?
Try
select name,t.id
from customer t where
not exists (
select 1
from orders where
custID=t.id
and
datediff(curdate(),orders.orderDate) <= 30 )
Try this one
Select Customer.Custid,
Customer.name
from Customer
left join orders on
customer.custid = orders.custid and
datediff(getdate(),orders.orderdate)>30)
where
orders.id is null
This is my SQL:
"SELECT users.username, users.id_user, friends.name, friends.meet_date
FROM users INNER JOIN friends ON (users.id_user = friends.id_user)
GROUP BY username ORDER BY username";
This is the output on my webpage:
Username Friend's Name Meeting Date
George Nicolas 2010
Man Anatol 2008
For now, it selects just the first rows from database for each user.
Each table has an auto_increment, id_user for the first table and id_friend for the second one.
I would like it to show that friend which were meet last by each user.
I've tried to add an order by "meet_date DESC" but it doesn't work.
How could I achieve my wish?
One standard trick is to use an outer self join:
SELECT users.username, users.id_user, friends.name, friends.meet_date
FROM users
INNER JOIN friends ON (users.id_user = friends.id_user)
LEFT JOIN friends f2 ON friends.meet_date > f2.meet_date
WHERE f2.(primary key) IS NULL
GROUP BY username
ORDER BY username
which finds the date for which there is no other record with a greater date value. This avoids the inefficiencies of correlated subqueries and extra aggregates; or the doubtful assumption that records are always added in meet-date order which is necessary if you want to use the primary key.
* Edited by other user *
You should replace (primary key) by primary key column table or just by a f2 column:
SELECT users.username, users.id_user, friends.name, friends.meet_date
FROM users
left JOIN friends ON (users.id_user = friends.id_user)
LEFT JOIN friends f2 ON friends.meet_date > f2.meet_date
WHERE f2.id_user IS NULL
GROUP BY username
ORDER BY username
Query runs as spected:
| USERNAME | ID_USER | NAME | MEET_DATE |
-------------------------------------------
| a | 1 | c | 0 |
| b | 2 | (null) | (null) |
The easy way is a subquery:
SELECT
users.username,
users.id_user,
( select friends.name
from friends
where (users.id_user = friends.id_user)
ORDER BY friends.meet_date desc
LIMIT 1 ) as friend_name,
( select friends.meet_date
from friends
where (users.id_user = friends.id_user)
ORDER BY friends.meet_date desc
LIMIT 1 ) as friend_meet_date
FROM users
;
* Testing *
create table users (username varchar(50), id_user int);
create table friends ( name varchar(50), id_user int, meet_date int);
insert into users values ( 'a', 1),('b',2);
insert into friends values ('c', 1, 0), ('d',1,1);
Results:
| USERNAME | ID_USER | FRIEND_NAME | FRIEND_MEET_DATE |
-------------------------------------------------------
| a | 1 | d | 1 |
| b | 2 | (null) | (null) |
Try it at sql fiddle.
Notice thant a correlated subquery is not an elegant approach, is the easy approach.
Do you not have an auto_increment field? This would allow you to sort by that. The other option is to change meet_date to a date field so you can properly sort by it. No reason to store a DateTime as a varchar field
Assuming that you have got id as a primary key with auto_increment in users table, this should do the trick:
SELECT MAX(users.id), users.username, users.id_user, friends.name, friends.meet_date
FROM users INNER JOIN friends ON (users.id_user = friends.id_user)
GROUP BY username ORDER BY username
SELECT users.username, users.id_user, friends.name, friends.meet_date
FROM users INNER JOIN friends ON (users.id_user = friends.id_user)
GROUP BY username ORDER BY username
having max(friends.meet_date)=friends.meet_date