MySQL left join does not work correctly - mysql

I want to left join 2 tables.
So all attributes of left table should be shown in result table, no matter if it can join with other table or not.
When I do the follwing, I dont get the expected result
week_table:
date kw note
---------- -- ----
2012-04-01 0 NULL
2012-04-02 0 NULL
fact_table:
id number_of_application number_of_cluster number_of_jvm number_of_node number_of_was fk_wasversion fk_date fk_domain fk_osname fk_osarch fk_osversion fk_stage
-- --------------------- ----------------- ------------- -------------- ------------- ------------- ---------- --------- --------- --------- ------------ --------
1 114 8 80 18 18 6.0 2012-04-01 domain1 Linux sparc 2 stage1
2 114 8 80 18 18 6.0 2012-04-02 domain1 Linux sparc 2 stage1
3 114 8 80 18 18 6.0 2012-04-01 domain1 AIX sparc 2 stage1
4 114 8 80 18 18 6.0 2012-04-02 domain1 Solaris sparc 2 stage1
When I do this:
select
w.date,
coalesce(sum(f.number_of_was), 0)
from
week_table w
left join fact_table f on (w.date = f.fk_date)
where f.fk_osname = "AIX"
group by w.date;
I only get :
date coalesce(sum(f.number_of_was), 0)
---------- ---------------------------------
2012-04-01 18
Expected:
date coalesce(sum(f.number_of_was), 0)
---------- --------------------------------
2012-04-02 18
Does someone know why?
Best Regards

Move the criteria on the outer joined table from the WHERE clause to the ON clause:
select
w.date,
coalesce(sum(f.number_of_was), 0)
from
week_table w
left join fact_table f on (w.date = f.fk_date and f.fk_osname = "AIX")
group by w.date;

where f.fk_osname = "AIX"
I guess there is only one record with this osname?

because of where f.fk_osname = "AIX"
if the data doesnt exist on your right table, it is NULL, and you are asking to retrieve only the rows where fk_osname is = "AIX"`
you can do WHERE (f.fk_osname = "AIX" OR f.fk_osname IS NULL)

Related

How to I get the mysql average of a join with conditions?

I am trying to get the average ratings of a user by project type but include all users that have ratings regardless of type.
SELECT projects.user_id, AVG(ratings.rating) AS avg1
FROM projects
JOIN ratings
ON projects.project_id = ratings.project_id
WHERE projects.type='0'
GROUP BY projects.user_id;
Thanks in advance for the help.
The output I get for type 0 is:
user_id | avg1
-----------------
11 | 2.25
but I am trying to get:
user_id | avg1
-----------------
11 | 2.25
12 | 0
because user 12 has a project in the rating table but not of type 0 I still want it output with avg1 = 0
The output for type 1 works as expected because all users that have ratings also have type 1:
user_id | avg1
-----------------
11 | 4
12 | 2.5
Projects table is: (only the first 4 projects are in the ratings table)
project_id |user_id | type
--------------------------
51 11 0
52 12 1
53 11 0
54 11 1
55 12 1
56 13 0
57 14 1
Ratings table is:
project_id | rating
-------------------
51 0
51 1
52 4
51 5
52 2
53 3
54 4
52 1.5
Use conditional aggregation:
SELECT p.user_id,
COALESCE(AVG(CASE WHEN p.type = '0' THEN r.rating END), 0) AS avg1
FROM projects p JOIN ratings r
ON p.project_id = r.project_id
GROUP BY p.user_id;
See the demo.

How can I match the id of two different columns using left outer join in mysql

select
pe.fk_id_produto,
pe.qt_unitaria,
er.FK_produto,
IFNULL(er.quantidade_recebida,0) AS quantidade_recebida
from tblprodutoencomendado as pe
left outer join tblencomendarecebida er on er.FK_encomenda = pe.FK_num_encomenda
where fk_id_produto IN(SELECT FK_produto FROM tblencomendarecebida WHERE fk_encomenda = 13) or fk_num_encomenda = 13
group by fk_id_produto asc;
----------------------------------------------------------------
RESULT OF THIS QUERY
FK_id_produto qt_unitaria FK_produto quantidade_recebida
------------- ----------- ---------- -------------------
13 17 NULL NULL
16 44 13 32
15 15 NULL NULL
20 10 20 10
What I desire:
FK_id_produto qt_unitaria FK_produto quantidade_recebida
------------- ----------- ---------- -------------------
13 17 13 32
15 15 NULL NULL
16 44 NULL NULL
20 10 20 10
I have tried almost everything... can any one help please? thanks in advance
it looks that your join not on the right field
select
pe.fk_id_produto,
pe.qt_unitaria,
er.FK_produto,
IFNULL(er.FK_produto,0) AS quantidade_recebida
from tblprodutoencomendado as pe
left outer join tblencomendarecebida er on er.FK_produto = pe.fk_id_produto
group by fk_id_produto asc;

Get intersection of 2 tables in MySQL

Id MedId ShipId AvailableQuant DefaultQuant MinQuant MedExpiry LastUsed
------ ------ ------ -------------- ------------ -------- ------------------- ---------------------
1 1 2918 20 30 15 2015-02-05 11:37:24 2014-12-01 11:37:32
4 2 2918 50 55 30 2015-03-26 11:57:14 2014-12-03 11:57:22
5 3 2918 15 40 20 2014-12-10 16:58:58 2014-12-10 16:59:02
6 4 2918 30 75 30 2015-03-31 11:58:26 2014-12-03 11:58:32
7 5 2918 22 50 20 2015-01-01 11:59:05 2014-12-03 11:59:09
9 6 3095 5 35 10 2014-12-03 11:59:51 2014-09-01 11:59:55
10 7 2918 30 60 35 2014-12-01 12:00:43 2014-10-22 12:00:57
11 8 3095 25 30 20 2014-12-31 17:48:58 2014-12-01 17:49:12
And there are 2 queries that i have written
1)To give me count of critical Items
SELECT SUM(IF(m.AvailableQuant <= m.MinQuant,1, 0)) AS criticalFROM tbl_vesselmaster vs
INNER JOIN comp_login cl ON vs.co_id = cl.id
INNER JOIN m_shipinv m ON vs.id = m.ShipId
WHERE vs.co_id=$co_id;
2)To give me medicine that have excedeed expiry date
SELECT COUNT(MedId) as count FROM `m_shipinv` WHERE DATE(MedExpiry) < DATE(NOW());
i want a query to get the count intersection of this both query. means if the item is critical and its medicine is expired then it should count only 1
this should be the output
count
-------
4
I think you can just add the where clause to the first query:
SELECT SUM(m.AvailableQuant <= m.MinQuant) AS critical
FROM tbl_vesselmaster vs INNER JOIN
comp_login cl
ON vs.co_id = cl.id INNER JOIN
m_shipinv m
ON vs.id = m.ShipId
WHERE vs.co_id = $co_id OR DATE(MedExpiry) < DATE(NOW());
Note that I simplified the SUM() calculation. The if is not needed because MySQL treats booleans as integers in a numeric context.
Can't you just put the two conditions in the where clause ?
I don't understand all you inner joins as you only describe one table. I just altered the select of Gordon Linoff:
SELECT count(*) AS critical
FROM tbl_vesselmaster vs
INNER JOIN comp_login cl ON vs.co_id = cl.id
INNER JOIN m_shipinv m ON vs.id = m.ShipId
WHERE vs.co_id = $co_id
AND DATE(MedExpiry) < DATE(NOW())
AND m.availableQuant <= m.minQuant;
I think the result should be 3: only records 5, 9 and 10 meet both criteria.

select data based on multiple criteria (cloest value)

I am using MySQL. I'm trying to build something and just can't find a solution to a problem.
I am selecting a value from the lookup table based on my table as shown in the below example.
Select Criteria:
my.id<>l.id AND my.route1=l.route1 AND my.route2=l.route2 AND my.utc=l.utc
where my.stime is closest or same as l.stime
ex) my.id=2's col should get the l.id=1, l.etime=7777 since my.id<>l.id and the rest are the same.
ex) my,id=5's col has options l.id=3, l.etime=9999 and l.id=4, l.etime=7979 since my.id<>l.id, my.route=l.route, my.utc=l.utc. Yet, since my.stime=2220 is closer to l.stime=2222 than l.stime=3333 , l.id=3, l.etime=9999 will be chosen.
ex) my,id=6's col example is to select either value if "closest" is the same.
ex) my,id=7's col example is to return NULL when the criteria is not met.
Table: lookup (l.)
id route1 route2 utc stime etime
---|--------|--------|-----|-------|------
1 11 22 111 1111 7777
2 11 22 111 1111 8888
3 22 33 222 2222 9999
4 22 33 222 3333 7979
5 22 33 222 3335 8989
Table: my (my.) | result
id route1 route2 utc stime | l.id l.etime
---|--------|--------|-----|------- |-------|----------|
2 11 22 111 1111 | 1 7777
5 22 33 222 2220 | 3 9999
6 22 33 222 3334 | 4or5 7979or8989
7 22 33 999 9999 | null null
A new table should be created where the result is appended to the last col of my.
Any help is appreciated. Thanks in advance.
This solution is a bit convoluted, but it's a starting point.
First, let's create an auxiliary table:
CREATE TEMP TABLE temp AS
SELECT m.id mid, l.id lid, ABS(l.stime-m.stime) timediff
FROM my m JOIN lookup l
WHERE m.route1 = l.route1 AND m.route2 = l.route2 AND
m.utc = l.utc AND m.id <> l.id;
From this table we can get the minimum timediff for each my.id:
SELECT mid, min(timediff) mtimediff FROM temp GROUP BY mid
Result:
mid mtimediff
---------- ----------
2 0
5 2
6 1
Now we can find which rows in lookup have this stime difference, and choose the smallest id:
SELECT t.mid mid, min(lid) lid
FROM temp t JOIN (
SELECT mid, min(timediff) mtimediff FROM temp GROUP BY mid
) mt ON t.mid = mt.mid AND t.timediff = mt.mtimediff
GROUP BY t.mid
This is the result:
mid lid
---------- ----------
2 1
5 3
6 4
And finally we use those ids to extract the data from the tables:
SELECT m.id, m.route1, m.route2, m.utc, m.stime, l.id, l.etime
FROM my m JOIN lookup l JOIN (
SELECT t.mid mid, min(lid) lid
FROM temp t JOIN (
SELECT mid, min(timediff) mtimediff FROM temp GROUP BY mid
) mt ON t.mid = mt.mid AND t.timediff = mt.mtimediff
GROUP BY t.mid
) ON m.id = mid AND l.id = lid;
Giving:
id route1 route2 utc stime id etime
---------- ---------- ---------- ---------- ---------- ---------- ----------
2 11 22 111 1111 1 7777
5 22 33 222 2220 3 9999
6 22 33 222 3334 4 7979

SQL: how to select a single id that meets multiple criteria from multiple rows

On a MySQL database, I have the table below
package_content :
id | package_id | content_number | content_name | content_quality
1 99 11 Yellow 1
2 99 22 Red 5
3 101 11 Yellow 5
4 101 33 Green 5
5 101 44 Black 5
6 120 11 Yellow 5
7 120 55 White 5
8 135 66 Pink 5
9 135 99 Orange 5
10 135 11 Yellow 5
and i am looking a possibility to make search queries on it:
I would like to select the package_id where content_number could be 11 AND 22 (In this case it should select only package_id 99
I really don't know if it's possible in SQL since the statement AND will always results as false. If i use the statement OR i also get the package_id 99, 101, 120, 135 and that's not what i want.
Maybe my table is not well designed too, but any suggestions would help!
Thanks in advance
Edit
I added the content_quality column
I used the sql query from juergen, works very well
select package_id
from package_content
where content_number in (11,22)
group by package_id
having count(distinct content_number) = 2
My last question is how could i now add another criteria : Select the package_id where content_number is 11 and 22 and content_number 11 has content_quality 1
Edit 2:
For the 2nd question i use now this query. Thanks to both of you who helped me! :)
SELECT *
FROM (
SELECT package_id
FROM package_content
WHERE
(content_number=11 AND content_quality > 1)
OR (content_number = 33 AND content_quality = 5)
OR (content_number = 44 AND content_quality =5 AND content_name like 'Black')
GROUP BY package_id
HAVING count( DISTINCT content_number) = 3
)t1
LEFT JOIN package_content ON package_content.package_id = t1.package_id
This will output
id | package_id | content_number | content_name | content_quality
3 101 11 Yellow 5
4 101 33 Green 5
5 101 44 Black 5
You need to group by the package_id and then use having to perform an aggregate function over the grouped data
select package_id
from package_content
where content_number = 22
or
(
content_number = 11 and content_quality = 1
)
group by package_id
having count(distinct content_number) = 2
You could query with a self join for that:
SELECT DISTINCT package_id
FROM package_content a, package_content b
WHERE a.package_id = b.package_id
AND a.content_number = 11 AND b.content_number = 22
Edit: For your second question: Just add that to the query. The package_content renamed to a is responsible for the content_number 11. Therefore you can ask, wether a has content_quality 1:
SELECT DISTINCT package_id
FROM package_content a, package_content b
WHERE a.package_id = b.package_id
AND a.content_number = 11 AND b.content_number = 22
AND a.content_quality = 1