I have inherited a MySQL database, that has a table as follows:
mysql> describe stock_groups;
+--------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| group | varchar(5) | YES | | NULL | |
| name | varchar(255) | YES | | NULL | |
| parent | varchar(5) | YES | | NULL | |
| order | int(11) | YES | | NULL | |
+--------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
When I run mysql> select * from stock_groups wheregroup='D2';
I get:
mysql> select * from stock_groups where `group`='D2';
+----+-------+------+--------+-------+
| id | group | name | parent | order |
+----+-------+------+--------+-------+
| 79 | D2 | MENS | D | 51 |
+----+-------+------+--------+-------+
1 row in set (0.00 sec)
and also i have a table:
mysql> describe stock_groups_styles_map;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| group | varchar(5) | NO | | NULL | |
| style | varchar(25) | NO | | NULL | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
when I run:
mysql> select `group` from stock_groups_styles_map where style='N26';
+-------+
| group |
+-------+
| B1 |
| B11 |
| D2 |
| V2 |
+-------+
4 rows in set (0.00 sec)
how do i get the stock_groups.name ?
Join the tables, and select only the data you need. If you need unique rows, use the distinct keyword:
select -- If you need unique names, use "select distinct" instead of "select"
sg.name
from
stock_groups_styles_map as sgs
inner join stock_groups as sg on sgs.group = sg.group
where
sgs.style = 'N26'
You could also solve this using subqueries, but that would be rather inneficient in this case.
Something important
You should add the appropriate indexes to your tables. It will improve the performance of your database.
You can use inner join on group column
SELECT ss.group, sg.name from
stock_groups sg inner join stock_groups_styles_map ss on ss.group = sg.group
where ss.style='N26'
SELECT stock_groups.name FROM stock_groups_styles_map, stock_groups WHERE stock_groups_styles_map.style ='N26';
worked for me.
Related
In the database 'college2' there are 3 TABLES:'student, course & enrolment', and one(1) VIEW:'enrolment_status', which is created using the following command:
CREATE VIEW enrolment_status AS
SELECT code, COUNT(id)
FROM enrolment
GROUP BY code;
Explain command for 'course,enrolment and enrolment_status' results in:
mysql> EXPLAIN course;
+---------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| code | char(8) | NO | PRI | NULL | |
| name | varchar(90) | YES | MUL | NULL | |
| max_enrolment | char(2) | YES | | NULL | |
+---------------+-------------+------+-----+---------+-------+
3 rows in set (0.09 sec)
mysql> explain enrolment;
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | char(6) | YES | MUL | NULL | |
| code | char(8) | YES | MUL | NULL | |
+-------+---------+------+-----+---------+-------+
2 rows in set (0.02 sec)
mysql> explain enrolment_status;
+-----------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------+------+-----+---------+-------+
| code | char(8) | YES | | NULL | |
| COUNT(id) | bigint(21) | NO | | 0 | |
+-----------+------------+------+-----+---------+-------+
2 rows in set (0.18 sec)
'max_enrolment' column in 'course' TABLE is the maximum allowed # of student for each course, say 10 or 20.
'count(id)' column in 'enrolment_status' VIEW (not table) is actual # of students enrolled in each course.
'id' column in 'enrolment' TABLE is the student id enrolled in a course.
HERE'S MY QUESTION:
I want to have the '# of seats left' which is the difference between 'max_enrolment' column and 'count(id)' column.
'#of seats left' can be a stand alone table or view or a column added to any of the above tables. How can i do this:
I tried many commands including the following,
CREATE VIEW seats_left AS (
SELECT course.code, course.max_enrolment - enrolment_status.count
FROM course, enrolment_status
WHERE course.code = enrolment_status.code);
...which gives me the following error message:
ERROR 1054 (42S22): Unknown column 'enrolment_status.count' in 'field list'
mysql> SELECT*FROM enrolment_status;
+----------+-----------+
| code | COUNT(id) |
+----------+-----------+
| COMP9583 | 7 |
| COMP9585 | 9 |
| COMP9586 | 7 |
| COMP9653 | 7 |
| COMP9654 | 7 |
| COMP9655 | 8 |
| COMP9658 | 7 |
+----------+-----------+
7 rows in set (0.00 sec)
mysql> SELECT code, max_enrolment FROM course;
+----------+---------------+
| code | max_enrolment |
+----------+---------------+
| COMP9583 | 10 |
| COMP9585 | 15 |
| COMP9586 | 15 |
| COMP9653 | 12 |
| COMP9654 | 10 |
| COMP9655 | 12 |
| COMP9658 | 12 |
+----------+---------------+
7 rows in set (0.00 sec)
+----------+---------------------+
| code | max_enrolment - cnt |
+----------+---------------------+
| COMP9583 | 9 |
| COMP9585 | 14 |
| COMP9586 | 14 |
| COMP9653 | 11 |
| COMP9654 | 9 |
| COMP9655 | 11 |
| COMP9658 | 11 |
+----------+---------------------+
7 rows in set (0.09 sec)
Try to use an acronym for in the view.
CREATE VIEW enrolment_status AS
SELECT code, COUNT(id) count
FROM enrolment
GROUP BY code;
Then you should be able to do this:
CREATE VIEW seats_left AS (
SELECT course.code, course.max_enrolment - enrolment_status.count
FROM course, enrolment_status
WHERE course.code = enrolment_status.code);
If you cannot change the view, then you must use the exact same name in the query:
CREATE VIEW seats_left AS (
SELECT course.code, course.max_enrolment - enrolment_status.'count(id)'
FROM course, enrolment_status
WHERE course.code = enrolment_status.code);
Try this:
SELECT b.`code`,max_enrolment - cnt from
(select `code`, cnt from
(select count(1) as cnt,`code` from enrolment_status
GROUP BY `code`) as a) as a
LEFT JOIN
(SELECT code,max_enrolment from course) as b
on a.`code` = b.`code`
You can change left join to right join
I have two tables in mysql server. I use these tables for studing JOIN multiple tables but something appears to be incorrect:
mysql> select * from category;
+-------------+-----------+
| category_id | name |
+-------------+-----------+
| 1 | fruit |
| 2 | vegetable |
+-------------+-----------+
2 rows in set (0.00 sec)
mysql> desc category;
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| category_id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(50) | NO | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
And:
mysql> select * from goods;
+---------+--------+-------------+------+
| good_id | name | category_id | cost |
+---------+--------+-------------+------+
| 1 | banan | 1 | 1.00 |
| 2 | potato | 2 | 1.00 |
| 3 | peach | 1 | 1.00 |
+---------+--------+-------------+------+
3 rows in set (0.00 sec)
mysql> desc goods;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| good_id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
| category_id | int(11) | NO | MUL | NULL | |
| cost | decimal(6,2) | NO | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
The second table has foreign key (category_id) and I can join them using INNER JOIN:
mysql> select c.name category, g.name, g.cost from category as c INNER JOIN goods g ON c.category_id = g.category_id;
+-----------+--------+------+
| category | name | cost |
+-----------+--------+------+
| fruit | banan | 1.00 |
| vegetable | potato | 1.00 |
| fruit | peach | 1.00 |
+-----------+--------+------+
3 rows in set (0.00 sec)
I tried to use NATURAL JOIN but it didnt work and it seems I dont know why(((
mysql> select c.name, g.name, g.cost from category as c NATURAL JOIN goods g;
Empty set (0.00 sec)
Could somebody explain why NATURAL JOIN does not work?
I was having the exact same thing happen to me, and my Googling led me to this question. I eventually figured it out, so I figured I'd post my answer here.
This was the culprit:
Instead of specifying a join condition through ON, USING or a WHERE clause, the NATURAL keyword tells the server to match up any column names between the two tables, and automatically use those columns to resolve the join.
Your fruit and category tables both have a column called "name". When SQL tries to join the two, it tries to join all like columns. So thus, category_id==category_id, but name!=name.
Rename your columns tablename_column instead.
My application is similar to Facebook, and I'm trying to optimize the query that get user records. The user records are that he as src ou dst. The src is in usermuralentry directly, the dst list are in usermuralentry_user.
So, a entry can have one src and many dst.
I have those tables:
mysql> desc usermuralentry ;
+-----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_src_id | int(11) | NO | MUL | NULL | |
| private | tinyint(1) | NO | | NULL | |
| content | longtext | NO | | NULL | |
| date | datetime | NO | | NULL | |
| last_update | datetime | NO | | NULL | |
+-----------------+------------------+------+-----+---------+----------------+
10 rows in set (0.10 sec)
mysql> desc usermuralentry_user ;
+-------------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| usermuralentry_id | int(11) | NO | MUL | NULL | |
| userinfo_id | int(11) | NO | MUL | NULL | |
+-------------------+---------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
And the following query to retrieve information from two users.
mysql> explain
SELECT *
FROM usermuralentry AS a
, usermuralentry_user AS b
WHERE a.user_src_id IN ( 1, 2 )
OR
(
a.id = b.usermuralentry_id
AND b.userinfo_id IN ( 1, 2 )
);
+----+-------------+-------+------+-------------------------------------------------------------------------------------------+------+---------+------+---------+------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-------------------------------------------------------------------------------------------+------+---------+------+---------+------------------------------------------------+
| 1 | SIMPLE | b | ALL | usermuralentry_id,usermuralentry_user_bcd7114e,usermuralentry_user_6b192ca7 | NULL | NULL | NULL | 147188 | |
| 1 | SIMPLE | a | ALL | PRIMARY | NULL | NULL | NULL | 1371289 | Range checked for each record (index map: 0x1) |
+----+-------------+-------+------+-------------------------------------------------------------------------------------------+------+---------+------+---------+------------------------------------------------+
2 rows in set (0.00 sec)
but it is taking A LOT of time...
Some tips to optimize? Can the table schema be better in my application?
Use this query
SELECT *
FROM usermuralentry AS a
left join usermuralentry_user AS b
on b.usermuralentry_id = a.id
WHERE a.user_src_id IN(1, 2)
OR (a.id = b.usermuralentry_id
AND b.userinfo_id IN(1, 2));
And for some tips here are
You are using two tables in from clause which is a cartision product and will take a lot of time as well as undesired results. Always use joins in this situation.
I think your join isn't properly formed, and you need to change the query to use UNION. The OR condition in the where clause is killing performance as well:
SELECT *
FROM usermuralentry AS a
JOIN usermuralentry_user AS b ON a.id = b.usermuralentry_id /* use explicit JOIN! */
WHERE a.user_src_id IN (1 , 2)
UNION
SELECT *
FROM usermuralentry AS a
JOIN usermuralentry_user AS b ON a.id = b.usermuralentry_id
WHERE b.usermuralentry_id IN ( 1, 2 )
You also need an index: ALTER TABLE usermuralentry_user ADD INDEX (usermuralentry_id)
I have these two tables in my db
describe external_review_sources;
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| ersID | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(50) | NO | UNI | NULL | |
| logo | varchar(255) | NO | | NULL | |
+-------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
And
describe listing_external_review_source_rel;
+---------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+----------------+
| lersrID | int(11) | NO | PRI | NULL | auto_increment |
| bid | int(10) | NO | | NULL | |
| url | varchar(255) | NO | | NULL | |
| ersID | int(11) | YES | | NULL | |
| active | int(10) | NO | | NULL | |
| order | int(10) | NO | | NULL | |
+---------+--------------+------+-----+---------+----------------+
6 rows in set (0.00 sec)
I query these tables this way:
SELECT *
FROM
listing_external_review_source_rel
RIGHT JOIN
external_review_sources USING(ersID)
where bid=902028 or bid IS NULL;
+-------+---------------+------+---------+--------+-------+--------+-------+
| ersID | name | logo | lersrID | bid | url | active | order |
+-------+---------------+------+---------+--------+-------+--------+-------+
| 1 | G1 | a | 17 | 902028 | url11 | 1 | 0 |
| 2 | D1 | b | 18 | 902028 | url22 | 0 | 0 |
+-------+---------------+------+---------+--------+-------+--------+-------+
2 rows in set (0.00 sec)
As you can see results are showing up for bid=902028, how ever for a bid such as 866696 that does NOT exist in listing_external_review_source_rel, the results are empty
SELECT *
FROM listing_external_review_source_rel
RIGHT JOIN external_review_sources USING(ersID)
where bid=866696 or bid IS NULL;
Empty set (0.00 sec)
I expect the results to be this:
+-------+---------------+------+---------+--------+-------+--------+-------+
| ersID | name | logo | lersrID | bid | url | active | order |
+-------+---------------+------+---------+--------+-------+--------+-------+
| 1 | G1 | NULL | NULL| NULL | NULL | NULL | NULL |
| 2 | D1 | NULL | NULL| NULL | NULL | NULL | NULL |
+-------+---------------+------+---------+--------+-------+--------+-------+
2 rows in set (0.00 sec)
That's what I have used the "or bid IS NULL" condition.
What am I doing wrong and what query would give me this result? I basically am interested in having nonmatching rows in my results as well.
Most people use LEFT JOIN so I'll rewrite it to be more standard:
SELECT *
FROM external_review_sources a LEFT JOIN
listing_external_review_source_rel b ON a.ersID=b.ersID AND bid=866696;
Remember that an outter join returns all rows where the ON condition matches, and NULL where they don't. In this case your match condition is more than just the ersID
Try this
SELECT * FROM
external_review_sources e
LEFT JOIN
listing_external_review_source_rel r ON e.ersID = r.ersID AND r.bid = 866696
WHERE
r.bid IS NULL;
When filtering on "outer tables", the filter needs to be a derived table or in the JOIN because you want to filter before the WHERE (logically). Also, a best practice is to use LEFT JOIN for clarity.
With a derived table
SELECT * FROM
external_review_sources e
LEFT JOIN
(
SELECT *
FROM listing_external_review_source_rel
WHERE bid = 866696
) r USING (ersID)
WHERE
r.bid IS NULL;
Try it this way, moving the test of the bid column out of the WHERE clause and into the JOIN:
SELECT *
FROM listing_external_review_source_rel ler
RIGHT JOIN external_review_sources ers
ON ler.ersID = ers.ersID
AND ler.bid=866696;
I'm having trouble with the following query:
SELECT costingjobtimes.TimeStamp, costingdepartment.DeptDesc, costingemployee.Name, costingjobtimes.TimeElapsed FROM costingemployee INNER JOIN (costingdepartment INNER JOIN costingjobtimes ON costingdepartment.DeptID = costingjobtimes.DeptID) ON costingemployee.EmployeeID = costingjobtimes.EmployeeID;
I would expect it to return every row in the costingjobtimes database however it's only returning 4 at current.
Basically, I have 3 tables. (costingjobtimes, costingdepartment, costingemployee) They are as follows:
mysql> DESCRIBE costingemployee
-> ;
+------------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------+------+-----+---------+-------+
| EmployeeID | varchar(8) | | PRI | | |
| Name | text | | | | |
+------------+------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> DESCRIBE costingdepartment
-> ;
+----------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+------------------+------+-----+---------+-------+
| DeptID | int(10) unsigned | | PRI | 0 | |
| DeptDesc | text | | | | |
+----------+------------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> DESCRIBE costingjobtimes
-> ;
+-------------+------------------+------+-----+---------------------+-----------
-----+
| Field | Type | Null | Key | Default | Extra
|
+-------------+------------------+------+-----+---------------------+-----------
-----+
| id | int(10) unsigned | | PRI | NULL | auto_incre
ment |
| EmployeeID | text | | | |
|
| DeptID | int(10) unsigned | | | 0 |
|
| JobNumber | text | | | |
|
| TimeElapsed | decimal(10,5) | | | 0.00000 |
|
| TimeStamp | datetime | | | 0000-00-00 00:00:00 |
|
| JobRef | text | | | |
|
+-------------+------------------+------+-----+---------------------+-----------
-----+
7 rows in set (0.00 sec)
So all the query is supposed to do is return all the rows from costingjobtimes, but put in the employees name instead of EmployeeID and Department description instead of the DeptID. Any help would be great..
Thanks in advance,
I don't know if an Inner Join is really what you are looking for teishu. Maybe you should try a normal join.
For example:
select e.Name, d.DeptDesc, j.JobNumber, j.TimeElapsed, j.TimeStamp, j.JobRef
from costingjobtimes as j
join costingdepartment as d on d.DeptID = j.DeptId
join costingemployee as e on e.EmployeeID = j.EmployeeID
This should give you a resultset with the information from the costingjobtimes table combined with the name of the employee and the description of the department.
Hope that helpes.