MySQL Left join WHERE table2.field = "X" - mysql

I have the following tables:
pages:
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| page_id | int(11) | NO | PRI | NULL | auto_increment |
| type | varchar(20) | NO | | NULL | |
| categories | varchar(255) | NO | | NULL | |
| title | varchar(255) | NO | MUL | NULL | |
| text | longtext | NO | MUL | NULL | |
+------------+--------------+------+-----+---------+----------------+
custom:
+---------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+-------+
| page_id | int(10) unsigned | NO | PRI | NULL | |
| key | varchar(255) | NO | PRI | NULL | |
| value | longtext | NO | | NULL | |
+---------+------------------+------+-----+---------+-------+
I want to join the tables in a way where:
1) all the entries from the first table are returned LEFT JOIN custom ON pages.page_id = custom.page_id
2) pages.type IN ('type_a', 'type_b', 'type_c')
3) "key" from the second table has value "votes" custom.key = 'votes'
I made everything so far, but the third condition is the problem. If there isn't entry for key = 'votes' in table custom the query returns only these with entries. I want to return NULL if missing entries.
I need key = 'votes', because I have other entries for this page_id where the key is not 'votes' and this duplicates the rows from pages

Simply add your contraint custom.key='votes' to the LEFT JOIN
SELECT *
FROM pages LEFT JOIN custom
ON pages.page_id=custom.page_id AND custom.key='votes'
WHERE pages.type IN('type_a','type_b','type_c') ;

I'd do it like this:
SELECT *
FROM pages
LEFT JOIN
( SELECT * From custom where key='votes') cv
on pages.page_id = cv.page_id
WHERE pages.type IN ('type_a', 'type_b', 'type_c');

try changing your where condition to custom.key = 'votes' OR custom.key is null.

Related

SQL, delete only if exactly one row is found

I have a nested query that deletes a row in table terms only if exactly one row in definitions.term_id is found. It works but it takes like 9 seconds on my system. Im looking to optimize the query.
DELETE FROM terms
WHERE id
IN(
SELECT term_id
FROM definitions
WHERE term_id = 1234
GROUP BY term_id
HAVING COUNT(term_id) = 1
)
The database is only about 4000 rows. If I separate the query into 2 independent queries, it takes about 0.1 each
terms
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| term | varchar(50) | YES | | NULL | |
+-------+------------------+------+-----+---------+----------------+
definitions
+----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| term_id | int(11) | YES | | NULL | |
| definition | varchar(500) | YES | | NULL | |
| example | varchar(500) | YES | | NULL | |
| submitter_name | varchar(50) | YES | | NULL | |
| approved | int(1) | YES | MUL | 0 | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| votos | int(3) | NO | | NULL | |
+----------------+------------------+------+-----+---------+----------------+
To speed up the process, please consider creating an index on the relevant field:
CREATE INDEX term_id ON terms (term_id)
How about using correlated sub query using exists and try,
DELETE FROM terms t
WHERE id = 1234
AND EXISTS (SELECT 1
FROM definitions d
WHERE d.term_id = t.term_id
GROUP BY term_id
HAVING COUNT(term_id) = 1)
It's often quicker to create a new table retaining only the rows you wish to keep. That said, I'd probably write this as follows, and provide indexes as appropriate.
DELETE
FROM terms t
JOIN
( SELECT term_id
FROM definitions
WHERE term_id = 1234
GROUP
BY term_id
HAVING COUNT(*) = 1
) x
ON x.term_id = t.id
Hehe; this may be a kludgy way to do it:
DELETE ... WHERE id = ( SELECT ... )
but without any LIMIT or other constraints.
I'm depending on getting an error something like "subquery returned more than one row" in order to prevent the DELETE being performed if multiple rows match.

How to order records from one table by repetitions of column value by from second table

Table user_contest_image:
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | YES | MUL | NULL | |
| filename | varchar(255) | YES | | NULL | |
| title | varchar(255) | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
Table image_vote:
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| image_id | int(11) | YES | MUL | NULL | |
| ip | varchar(255) | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
image_vote.image_id is foreign key to user_contest_image.id.
I am trying to get all records from user_contest_image and order them by the repetitions of the related image_vote.image_id.
Example data:
user_contest_image
id user_id filename title
1 1 image_1.png imageTitle1
2 2 image_2.png imageTitle2
image_vote
id image_id ip
1 2 127.0.0.1
2 1 127.0.0.1
3 2 127.0.0.1
Two times of image_id with value 2 and one time with value 1.
I am trying to order the result like so:
user_contest_image.id user_contest_image.filename
2 image_2.png
1 image_1.png
I didn't provide example of my work because I really don't get how should I do it.
Join the tables, group by image id, add a COUNT(image_vote.id) field, and order by that field.
Looking to your data seems you need the order result for the image vote
select user_contest_image.id , filename
from user_contest_image
inner join image_vote on image_vote.image_id = user_contest_image.id
group by user_contest_image.id, user_contest_image.file_name
order by count(image_vote.image_id) DESC

mysql UPDATE says column cannot be null. Why is it null?

I have a join table called carriers_rects that looks like this:
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| carrier_id | int(11) unsigned | NO | | NULL | |
| rect_id | int(11) unsigned | NO | | NULL | |
+------------+------------------+------+-----+---------+----------------+
I also have a rects table that looks like this:
+---------+-------------+------+-----+----------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+----------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(54) | NO | | new rect | |
| width | varchar(54) | NO | | NULL | |
| length | varchar(54) | NO | | NULL | |
| rounded | tinyint(1) | NO | | NULL | |
| xx | varchar(54) | NO | | NULL | |
| yy | varchar(54) | NO | | NULL | |
| height | varchar(54) | NO | | NULL | |
+---------+-------------+------+-----+----------+----------------+
I am trying to add a case_id column to rects and just make it a one-to-many relationship and kill the carriers_rects table. We are moving our DB and we never used the many-to-many relationship.
So I added the case_id column to rects:
alter table rects add case_id int(11) not null;
Then I tried to update the case_id on the rects with all the case_id's that would match from the carriers_rects table.
update rects set case_id = (select carrier_id from carriers_rects where rect_id = id);
I am getting column case_id cannot be null.
I tested to see if there where any nulls and I can't seem to find any.
select * from (select * from carriers_rects where rect_id IN(select id from rects)) `b` where id is null;
I also tried it the other way around because honestly I am a little confused.
select id from rects where id IN(select rect_id from carriers_rects)
Clearly I am not a sql genius. But would love to be schooled here.
Not sure why I am getting the error mentioned above.
What if you change to a update-join syntax rather than using subquery like
update rects r
join carriers_rects cr on cr.rect_id = r.id
set r.case_id = cr.carrier_id
where cr.carrier_id is not null;
The main reason of this error is in your inner query condition rect_id = id . They both are from carriers_rects (it means carriers_rects.rect_id = carriers_rects.id) so you get null. Change it to rect_id = rects.id
update rects set case_id =
(select carrier_id from carriers_rects where rect_id = rects.id);

How to link 4 tables using an mySQL query

Vehicle
+--------------------+--------------+------+-----+---------+
| Field | Type | Null | Key | Default |
+--------------------+--------------+------+-----+---------+
| id | int(11) | NO | Pk | NULL |
| model | varchar(35) | NO | | NULL |
+--------------------+--------------+------+-----+---------+
info
+--------------------+--------------+------+-----+---------+
| Field | Type | Null | Key | Default |
+--------------------+--------------+------+-----+---------+
| id | int(11) | NO | Pk | NULL |
| vehicle_id | varchar(35) | NO | FK | NULL |
| location | varchar(35) | NO | | NULL |
+--------------------+--------------+------+-----+---------+
Axle 1
+--------------------+--------------+------+-----+---------+
| Field | Type | Null | Key | Default |
+--------------------+--------------+------+-----+---------+
| id | int(11) | NO | Pk | NULL |
| vehicle_id | varchar(35) | NO | FK | NULL |
| weight | varchar(35) | NO | | NULL |
+--------------------+--------------+------+-----+---------+
Axle 2
+--------------------+--------------+------+-----+---------+
| Field | Type | Null | Key | Default |
+--------------------+--------------+------+-----+---------+
| id | int(11) | NO | Pk | NULL |
| vehicle_id | varchar(35) | NO | FK | NULL |
| weight | varchar(35) | NO | | NULL |
+--------------------+--------------+------+-----+---------+
I wish to create a query that will return all the fields from all tables with a common vehicle_id. The vehicle_id being a reference in each of the 3 tables (info, axle1, axle 2) to the primary key in the Vehicle table. Could someone please explain how I might go about doing so? I tried using multiple joins but it didnt work!Many thanks.
EDIT:
Query I tried was;
SELECT *
FROM Vehicle
JOIN info, axle1, axle 2
ON vehicle.id = axle1.vehicle_id
AND vehicle.id = axle2.vehicle_id AND vehicle.id = info.vehicle_id
Try this instead:
SELECT *
FROM Vehicle v
INNER JOIN Info i ON v.id = i.vehicle_id
INNER JOIN Axle1 a1 ON i.vehicle_id = a1.vehicle_id
INNER JOIN Axle2 a2 ON a1.vehicle_id = a2.vehicle_id
Check this link: mySQL get information from multiple tables in one query I think there's an example that may fit
You just need to specify an identifier for each table, so you can specify which table are you talking about when you refer to a field. Then, make sure you link all the id's as a condition so you leave out all the combinations where identifiers don't match. That would be:
SELECT * FROM Vehicle v, Info i, Axle1 a1, Axle2 a2 WHERE v.id == a1.vehicle_id AND v.id == a2.vehicle_id AND v.id == i.vehicle_id

SQL query doesn't return multiple rows per matched item in a join

I have 2 tables:
mysql> describe solution_sections;
+---------------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------------+------+-----+---------+----------------+
| solution_section_id | int(10) | NO | PRI | NULL | auto_increment |
| display_order | int(10) | NO | | NULL | |
| section_name | varchar(1000) | YES | | NULL | |
+---------------------+---------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql> describe suggested_solution_comments;
+-----------------------+----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+----------------+------+-----+---------+----------------+
| comment_id | int(10) | NO | PRI | NULL | auto_increment |
| problem_id | int(10) | NO | | NULL | |
| suggested_solution_id | int(10) | NO | | NULL | |
| commenter_id | int(10) | NO | | NULL | |
| comment | varchar(10000) | YES | | NULL | |
| solution_part | int(3) | NO | | NULL | |
| date | date | NO | | NULL | |
+-----------------------+----------------+------+-----+---------+----------------+
What I am trying to do is to display the list of section_name from the solution_sections table, and n matched items from the suggested_solution_comments table for every section_name. So for every section name, the query should get the list of suggested_solution_comments associated with it.
The tables are linked by suggested_solution_comments.solution_part and solution_sections.solution_section_id
Here is what I am trying so far:
select section_name , comment , solution_part , display_order from solution_sections
left join suggested_solution_comments on
solution_sections.solution_section_id = suggested_solution_comments.solution_part
where suggested_solution_id = 188 OR suggested_solution_id IS NULL
group by display_order;
The problem is that the query gets the list of section_name, and one matched comment per section_name, but not more than one comment. Any idea why it doesn't get all the associated comments?
Thanks!!
the GROUP BY might account for what you are seeing try without it (UPDATE as per comments)
select section_name , comment , solution_part , display_order
from solution_sections
left join suggested_solution_comments on
solution_sections.solution_section_id = suggested_solution_comments.solution_part
where suggested_solution_id = 188 OR suggested_solution_id IS NULL
order by display_order;
Some remarks:
You datamodel seems a bit strange... for example the solution_part is int(3) and is linked to solution_section_id which is turn is an autoincrement int(10) ?