MySQL Left join (I think) help - mysql

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']."'

Related

How can i calculate the average of fields and exclude the 0 values

I have this:
SELECT
ROUND(AVG(coffee)) 'coffee',
ROUND(AVG(cappucino)) 'cappucino',
ROUND(AVG(espresso)) 'espresso',
ROUND(AVG(machine)) 'machine'
FROM `reviews` ORDER BY `username`
My Table looks like:
+-----+-----------+---------------+---------------+---------------+---------------+
| id | name | coffee | cappucino | espresso | machine |
+-----+-----------+---------------+---------------+---------------+---------------+
| 1 | Joe | 5 | 4 | 5 | 4 |
| 2 | Jane | 3 | 5 | 2 | 5 |
| 3 | Mike | 0 | 0 | 0 | 5 |
+-----+-----------+---------------+---------------+---------------+---------------+
I need the average of the reviews but Mike doesn't drink any coffee and he clicked the "Does not apply" button. So the current average is:
coffee 2.66666667
cappucino 3
espresso 2.33333333
machine 4.66666667
But it should be:
coffee 4
cappucino 4.5
espresso 3.5
machine 4.66666667
How can I figure this out?
NULL values are ignored by AVG, so do AVG(NULLIF(coffee,0)). Or store NULL instead of 0 in the first place.
This is definitely a great question. I have come up with a solution.
select avg(coffee) from data where coffee>0 union select avg(cappucino) from data where cappucino >0 union select avg(expresso) from data where expresso>0 union select avg(machine) from data where machine>0;
Try this. I'm calculating averages of all fields separately using the where condition that the value in the field should be greater than 0 and then I am displaying the UNION of all queries.
This will be the output... To avoid getting avg(coffee) as the column header, you may use ALIAS.
+-------------+
| avg(coffee) |
+-------------+
| 4.0000 |
| 4.5000 |
| 3.5000 |
| 4.6667 |
+-------------+
I hope this was helpful.
This was the fix:
SELECT
ROUND(AVG(NULLIF(coffee,0))) 'coffee',
ROUND(AVG(NULLIF(cappucino,0))) 'cappucino',
ROUND(AVG(NULLIF(espresso,0))) 'espresso',
ROUND(AVG(NULLIF(machine,0))) 'machine'
FROM `reviews` ORDER BY `username`

Mysql - join 3 tables with different number of rows into another [duplicate]

This question already has answers here:
How can I do a FULL OUTER JOIN in MySQL?
(15 answers)
Closed 5 years ago.
I have the following tables and I need to join them:
Table A
+----+----------+--------+
| ID | Period | Value |
+----+----------+--------+
| 1 |2009-02-01| 20.3 |
| 2 |2009-03-01| 22.5 |
| 3 |2009-04-01| 17.4 |
| 4 |2009-05-01| 16.5 |
| 5 |2009-06-01| 26.5 |
| 6 |2009-07-01| 35.4 |
+----+----------+--------+
Table B
+----+----------+--------+
| ID | Period | Value |
+----+----------+--------+
| 1 |2009-04-01| 57.1 |
| 2 |2009-05-01| 56.5 |
| 3 |2009-06-01| 59.8 |
| 4 |2009-07-01| 55.4 |
+----+----------+--------+
Table C
+----+----------+--------+
| ID | Period | Value |
+----+----------+--------+
| 1 |2009-03-01| 82.5 |
| 2 |2009-04-01| 87.4 |
| 3 |2009-05-01| 86.7 |
+----+----------+--------+
My output table is already created empty table and looks like this:
Table D
+----+----------+--------+--------+--------+
| ID | Period | ValueA | ValueB | ValueC |
+----+----------+--------+--------+--------+
As table A contains most of the records I want to use it as primary table. The desired result is as follow:
Table D
+----+----------+--------+--------+--------+
| ID | Period | ValueA | ValueB | ValueC |
+----+----------+--------+--------+--------+
| 1 |2009-02-01| 20.3 | NULL | NULL |
| 2 |2009-03-01| 22.5 | NULL | 82.5 |
| 3 |2009-04-01| 17.4 | 57.1 | 87.4 |
| 4 |2009-05-01| 16.5 | 56.5 | 86.7 |
| 5 |2009-06-01| 26.5 | 59.8 | NULL |
| 6 |2009-07-01| 35.4 | 55.4 | NULL |
+----+----------+--------+--------+--------+
I'm very new to MySQL. I looked to similar questions in the forum and tried to figure it out for myself but with no success.
Any help appreciated.
ANSWER
Ok. Few things. First the question isn't duplicate! The thing looks more like a speedy moderator than duplicate question. And No, I didn't find this answer anywhere on this website and for sure not in the suggested from the moderator answer.
Now the interesting part.
With the help of the creative moderator after spending few hours finally I got it work. As I said in the original question table D already exists. This is because the model is created and managed by third party application. In this case Django. This is an important point as otherwise the operation will be different. I also have more than one schema on the server.
I think In this case the best way for this query is by using alias as follow:
insert into my_schema.table_d(period, valueA, valueB, valueC)
select A.Period, A.Value, B.Value, C.Value
from my_schema.table_a A
left join my_schema.table_b B
on A.Period = B.Period
left join my_schema.table_c C
on A.Period = C.Period
You are looking for a left join:
insert into d( . . . )
select . . .
from a left join
b
on a.period = b.period left join
c
on a.period = c.period;
Fill in the columns where the . . . are.

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.

Self join and recursive selection in a table

Assuming a table as below
| ID | NAME | ROLE | MGRID |
---------------------------
| 1 | ONE | 5 | 5 |
| 2 | TWO | 5 | 5 |
| 3 | THREE | 5 | 6 |
| 4 | FOUR | 5 | 6 |
| 5 | FIVE | 15 | 7 |
| 6 | SIX | 25 | 8 |
| 7 | SEVEN | 25 | 7 |
| 8 | EIGHT | 5 | 8 |
How do I get a list of all employees reporting to an employee, including the ones who are in subsequent reporting levels below?
I mean, given emp id 5, I should get [1, 2] and given 7, I should get [1, 2, 5, 7]. How do I get this done?
Will self joins be of help here? Need to brush up my knowledge on joins now.
SELECT id
FROM emp
START WITH id = 7
CONNECT BY NOCYCLE mgrid = PRIOR id
SQLFIDDLE LINK
Here is a SQL statement using Oracle.
select id, name, role, mgrID
from employees
start with id = 7
connect by NoCycle prior id = mgrid;
Please note that the manager for employee 7 is the employee 7 - they are their own manager. This will cause an error - "Connect By loop in user data'. By using the NoCycle keyword you can tell Oracle to detect this and avoid the error.
Does this solve your issue?
I know this isn't exactly what you were asking, but if you are willing to choose a finite number of level's to recurse it isn't too bad to write.
SELECT table_2.id
FROM table LEFT JOIN
(table AS table_1 LEFT JOIN table AS table_2 ON table_1.id = table_2.MgrID)
ON table.id = table_1.MgrID
WHERE (((table.id)=7));
ETC.

MySQL Left Join help

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