MySQL Left Join help - mysql

Hello again community,
I posted a question just over an hour ago asking for some help fixing a SQL query, that was promptly answered and was a great help. Sadly though, upon reflection and further usage, it turns out that the query was returning all rows in the targeted table. I validated this by putting the mysql_fetch_object inside a while loop.
So what I desperately need now is someone to have a look at the SQL query and tell me what is going wrong and if possible how to fix it. I simply just need one row (the correct row) to be found when using $_SESSION['model'] as the reference.
Below is the full content of my previous question.
Thank you in advance.
============================================================================
web_quote_models table
id | model | product_id | cpu_id | ram_id | hdd_id | os_id | opt_id
=========================================================================
1 | 000001 | 1 | 1 | 1 | 1 | 1 | 1
2 | 000002 | 1 | 2 | 2 | 2 | 2 | 2
3 | 000003 | 1 | 3 | 3 | 3 | 3 | 3
4 | 000004 | 1 | 4 | 4 | 4 | 4 | 4
web_quote_component_cpu table
id | name
==========================================================================
1 | Intel® Core™ i3 2100 3.1GHz dual-core
2 | Intel® Core™ i5 2500 2.7GHz quad-core
3 | Intel® Core%trade; i7 2600 3.4GHz 8mb Cache dual-core
So what I need to achieve is a query that will look inside the web_quote_models table and match the model field with a $_SESSION['model'] then match the web_quote_models.cpu_id field with the web_quote_component.id.
This is what I have so far; I cant be too far off I think.
("
SELECT web_quote_component_cpu.name
FROM web_quote_component_cpu
LEFT JOIN web_quote_models
ON web_quote_component_cpu.id=web_quote_models.cpu_id
AND web_quote_models.name='".$_SESSION['model']."'
");
A massive thank you in advance to anyone that helps.
Dan.

With Left Join, you get entries from the table on the left side of join (that is web_quote_component_cpu) even if they are not matched with the other table. If you want entries that only match, use join instead of left join.
Is that what you were asking?

SELECT web_quote_component_cpu.name FROM web_quote_component_cpu JOIN web_quote_models ON web_quote_component_cpu.id = web_quote_models.cpu_id WHERE web_quote_models.model = $_SESSION['model]
(or something like that)

Try this:
SELECT web_quote_component_cpu.name
FROM web_quote_component_cpu
LEFT JOIN web_quote_models ON web_quote_component_cpu.id=web_quote_models.cpu_id
WHERE web_quote_models.name='".$_SESSION['model']."' LIMIT 1

Related

How to properly join two tables to use alternative ORDER BY

Two tables...
people (personid, name, mainordering)
entries (userid, personid, altordering)
"personid" is the common field. My app displays a draggable list users can move around. When done, they click to "lock" in their order.
Table : people
+----------+---------+--------------+
| personid | name | mainordering |
+----------+---------+--------------+
| 1 | Bob | 2 |
| 2 | Charlie | 4 |
| 3 | Jim | 1 |
| 4 | Doug | 3 |
+----------+---------+--------------+
So using mainordering, it would display:
Jim
Bob
Doug
Charlie
entries table might have (for user 16):
+--------+----------+-------------+
| userid | personid | altordering |
+--------+----------+-------------+
| 16 | 1 | 3 |
| 16 | 2 | 1 |
| 16 | 3 | 2 |
| 16 | 4 | 4 |
+--------+----------+-------------+
So if user 16 has already submitted his entry BUT NOT LOCKED IT IN, I want to display his list using altordering. i.e.
Charlie
Jim
Bob
Doug
I'm struggling with the proper join to use. Here is what I tried and isn't working (it's simply ordering by mainordering still)...
$sql = "SELECT * from entries
WHERE userid=".$_SESSION['userid']."
LEFT JOIN people ON entries.personid = people.personid
ORDER BY altordering";
Any thoughts would be much appreciated. Thank you...
Are you sure you don't get an error when using WHERE before JOIN?
It should work like this:
SELECT people.*
FROM people
JOIN entries ON entries.personid = people.personid
WHERE entries.userid={$_SESSION['userid']}
ORDER BY entries.altordering
I assume entries.personid will always have a matching person in people, so you should use an INNER JOIN. You would use FROM entries LEFT JOIN people if you wanted to retrieve altordering even for non-existing people.

Calculating row indices with subquery having joins, results in A*B examined rows

This question is derived from a one I started previously: Incorrect row index when grouping
Due to different natures, I'm asking here and will provide the answer back there once I have resolved this issue.
I thought about subqueries, and came up with this:
SELECT
mq.*,
#indexer := #indexer + 1 AS indexer
FROM
(
SELECT
p.id,
p.tag_id,
p.title,
p.created_at
FROM
`posts` AS p
LEFT JOIN
`votes` AS v
ON p.id = v.votable_id
AND v.votable_type = "Post"
AND v.deleted_at IS NULL
WHERE
p.deleted_at IS NULL
GROUP BY
p.id
) AS mq
JOIN
(SELECT #indexer := 0) AS i
Which actually works, I get the desired result:
+----+--------+------------------------------------+---------------------+---------+
| id | tag_id | title | created_at | indexer |
+----+--------+------------------------------------+---------------------+---------+
| 2 | 2 | PostPostPost | 2014-10-23 23:53:15 | 1 |
| 3 | 3 | Title | 2014-10-23 23:56:13 | 2 |
| 4 | 2 | GIFGIFIGIIF | 2014-10-23 23:59:03 | 3 |
| 5 | 2 | GIFGIFIGIIF | 2014-10-23 23:59:03 | 4 |
| 6 | 4 | My new avatar | 2014-10-26 22:22:30 | 5 |
| 7 | 5 | Hi, haiii, oh Hey ! | 2014-10-26 22:38:10 | 6 |
| 8 | 6 | Mclaren testing stealth technology | 2014-10-26 22:44:15 | 7 |
| 9 | 7 | Just random thoughts while pooping | 2014-10-26 22:50:03 | 8 |
+----+--------+------------------------------------+---------------------+---------+
The problem now is... I ran a EXPLAIN query, to see how fast it works. And, I have a number there that is really bugging me:
Well, the number is obvious: 252 * 1663 = 419076.
This worries me, though - is the row count normal there, or I have to optimize the query? And if so, then how do I optimize this one?
As of MySQL version 5.7 all joins are treated as nested loop joins.
MySQL resolves all joins using a nested-loop join method. This means that MySQL reads a row from the first table, and then finds a matching row in the second table, the third table, and so on.
So to answer your question... no, you won't be able to get that row count down. However, by adding indexes to your join columns you may be able to achieve faster results but your row count will be the same.

Select all records from table A and join table B to get A's property

I can not figure out how I should do it...
Table 'child':
idchild | name | idability
--------------------------
1 | Joe | 1
1 | Joe | 2
2 | Peter| 1
2 | Peter| 3
3 | Kate | 4
Table 'ability':
idability | ability
-------------------
1 | run
2 | read
3 | write
4 | swim
For example, Joe can 'run' and 'read' but can't 'write' or 'swim'.
And I need a list like this about Joe's ability:
ability |
-----------------
run | +
read | +
write | -
swim | -
I've tried several SQL queries in different ways (using 'NOT EXIST') but never got the correct result. I hope somebody can tell me how I should do this.
Thank you in advance!
This should be ok:
select ability.ability, if(child.idability,'+','-') from ability left join child on ability.idability =child.idability and child.name="joe";
Try this one:
select `child`.`idChild`,`child`.`name`, `child`.`idability`, `ability`.`idAbility`,`ability`.`ability` from `child` inner join `ability` on `child`.`idAbility` = `ability`.`idability` order by `child`.`name`, `ability`.`ability`
You can remove columns that you don't need.

Joining from another table multiple times in a MySQL query

I am trying to do multiple joins on the same MySQL table, but am not getting the results that I expect to get. Hopefully someone can point out my mistake(s).
Table 1 - cpe Table
|id | name
|----------
| 1 | cat
| 2 | dog
| 3 | mouse
| 4 | snake
-----------
Table 2 - AutoSelect
|id | name | cpe1_id | cpe2_id | cpe3_id |
|-----------------------------------------------
| 1 | user1 | 1 | 3 | 4 |
| 2 | user2 | 3 | 1 | 2 |
| 3 | user3 | 3 | 3 | 2 |
| 4 | user4 | 4 | 2 | 1 |
------------------------------------------------
I would like to see an output of
user1 | cat | mouse | snake |
user2 | mouse | snake | dog |
..etc
Here is what I have tried
SELECT * FROM AutoSelect
LEFT JOIN cpe ON
( cpe.id = AutoSelect.cpe1_id ) AND
( cpe.id = AutoSelect.cpe2_id ) AND
( cpe.id = AutoSelect.cpe3_id )
I get blank results. I thought i knew how to do these joins, but apparently when I'm trying to match cpe?_id with the name of the cpe table.
Thanks in advance for any assistance.
You need left join 3 times as well. Currently your query only joins 1 time with 3 critieria as to the join. This should do:
SELECT a.name, cpe1.name, cpe2.name, cpe3.name FROM AutoSelect as a
LEFT JOIN cpe as cpe1 ON ( cpe1.id = a.cpe1_id )
LEFT JOIN cpe as cpe2 ON ( cpe2.id = a.cpe2_id )
LEFT JOIN cpe as cpe3 ON ( cpe3.id = a.cpe3_id )
And you probably mean to INNER JOIN rather than LEFT JOIN unless NULL values are allowed in your AutoSelect table.
I think your design is wrong.
With tables like that, you get it the way it's meant to be in relational databases :
table 1 : animal
id name
1 cat
2 dog
3 mouse
4 snake
table 2 : user
|id | name |
|--------------
| 1 | user1 |
| 2 | user2 |
| 3 | user3 |
| 4 | user4 |
table 3 : association
|id_user | id_animal|
|--------------------
| 1 | 1 |
| 1 | 3 |
| 1 | 4 |
| 2 | 3 |
| 2 | 1 |
| 2 | 2 |
| 3 | 3 |
| 3 | 2
| 4 | 4 |
| 4 | 2 |
| 4 | 1 |
---------------------
Then :
select u.name, a.name from user u, animal a, association ass where ass.user_id = u.id and ass.animal_id = a.id;
In this case, your solution won't produce a good dynamic database. There are other ways to make combinations of multiple tables. I can show you by my own database what you should use and when you should use this solution. The scheme is in dutch, but you'll probably understand the keywords.
Like you, I had to combine my windmills with a kWh-meter, which has to measure the energyproduction of my windmills. What you should do, is this case, is making another table(in my case molenkWhlink). Make sure your tables are INNODB-types(for making Foreign keys). What I've done is combining my meters and mills by putting a pointer(a foreign key) of their ID(in Dutch Volgnummer) in the new table. An advantage you may not need, but I certainly did, is the fact I was able to extend the extra table with connection and disconnection info like Timestamps and metervalues when linking or unlinking. This makes your database way more dynamic.
In my case, I Also had a table for meassurements(metingoverzicht). As you can see in the scheme, I've got 2 lines going from Metingoverzicht to molenkwhlink. The reason for this is quite simple. All meassurements I take, will be saved in table Metingoverzicht. Daily meassurements(which are scheduled) will have a special boolean put on, but unscheduled meassurements, will also me saved here, with the bollean turned off. When switching meters, I need the endvalue from the leaving meter and the startvalue from the new meter, to calculate the value of todays eneryproduction. This is where your solution comes in and an extra table won't work. Usually, when you need just one value from another table a JOIN will be used. The problem in this case is, I've got 2 meassurementIDs in 1 link(1 for connecting and 1 for disconnecting). They both point to the same tablecolumn, because they both need to hold the same type of information. That is when you can use a double JOIN from one table towards the other. Because, both values will only be used once, and just needed to be saved in a different place to avoid having 1 action stored on different locations, which should always be avoided.
http://s1101.photobucket.com/user/Manuel_Barcelona/media/schemedatabase.jpg.html

MySQL Left join (I think) help

I am having trouble working out how to return the correct row in a table given that said table is relational. The two tables are shown below.
web_quote_models table
id | model | product_id | cpu_id | ram_id | hdd_id | os_id | opt_id
=========================================================================
1 | 000001 | 1 | 1 | 1 | 1 | 1 | 1
2 | 000002 | 1 | 2 | 2 | 2 | 2 | 2
3 | 000003 | 1 | 3 | 3 | 3 | 3 | 3
4 | Custom | 0 | 0 | 3 | 4 | 4 | 4
web_quote_component_cpu table
id | name
=========================================================================
1 | Intel® Core™ i3 2100 3.1GHz dual-core
2 | Intel® Core™ i5 2500 2.7GHz quad-core
3 | Intel® Core%trade; i7 2600 3.4GHz 8mb Cache dual-core
So what I need to achieve is a query that will look inside the web_quote_models table and match the model field with a $_SESSION['model'] then match the web_quote_models.cpu_id field with the web_quote_component.id.
This is what I have so far; I cant be too far off I think.
("
SELECT web_quote_component_cpu.name
FROM web_quote_component_cpu
LEFT JOIN web_quote_models
ON web_quote_component_cpu.id='web_quote_models.cpu_id'
AND web_quote_models.name='".$_SESSION['model']."'
");
A massive thank you in advance to anyone that helps.
Dan.
I don't think you're far off at all. I believe that all you need to do is stop quoting web_quote_models.cpu_id:
SELECT web_quote_component_cpu.name
FROM web_quote_component_cpu
LEFT JOIN web_quote_models
-- note lack of quotes in the following line:
ON web_quote_component_cpu.id=web_quote_models.cpu_id
AND web_quote_models.name='".$_SESSION['model']."'
Edit
Based on the comment, I would personally re-write the query:
SELECT web_quote_component_cpu.name
FROM web_quote_component_cpu WHERE ID IN
( SELECT ID FROM WEB_QUOTE_MODELS WHERE
web_quote_models.name='".$_SESSION['model']."' );
Though I would suspect that swapping that last AND with a WHERE would be sufficient:
SELECT web_quote_component_cpu.name
FROM web_quote_component_cpu
LEFT JOIN web_quote_models
-- note lack of quotes in the following line:
ON web_quote_component_cpu.id=web_quote_models.cpu_id
WHERE web_quote_models.name='".$_SESSION['model']."'