How to display all the data in MySQL with WHERE clause - mysql

I want to display all the values in my column even the null value.
Below is my code that displays all the columns data included null but it doesn't display the latest date.
SELECT
MEMB.LAST_M,
MEMB.MEMB_N,
PrintDate
FROM
MEMB
INNER JOIN tblPrint
ON MEMB.MEMB_N = tblPrint.MEMB_N
This code however displays the latest dates but doesn't display all the columns even the null values.
SELECT
MEMB.LAST_M,
MEMB.MEMB_N,
MAX(PrintDate)
FROM
MEMB
INNER JOIN tblPrint
ON MEMB.MEMB_N = tblPrint.MEMB_N
WHERE tblPrint.`PrintDate` IN (SELECT tblPrint.`PrintDate` FROM tblPrint) GROUP BY MEMB.`LAST_M`

You likely need to use LEFT JOIN instead of INNER JOIN. Without seeing the DB structure, I have no way to test to be sure, but I've run into the same issue before. LEFT JOIN fixed it for me.

With MySQL 8, window functions were implemented, so you can now include inline aggregates within a unit level query. Specifically you can add a new column to original query for Latest_Date:
SELECT
m.LAST_M,
m.MEMB_N,
p.PrintDate,
MAX(PrintDate) OVER(PARTITION BY m.MEMB_N) AS Latest_Date
FROM
MEMB m
INNER JOIN tblPrint p
ON m.MEMB_N = p.MEMB_N

The problem to your query is your WHERE clause you could try removing it and you will get the NULL values.
SELECT
MEMB.LAST_M,
MEMB.MEMB_N,
MAX(PrintDate)
FROM
MEMB
INNER JOIN tblPrint
ON MEMB.MEMB_N = tblPrint.MEMB_N
GROUP BY MEMB.LAST_M, MEMB.MEMB_N

Related

How to full join the two tables with the null values as well?

I'm using MySQL 5.5 Command Line Client.
What I want:
What I tried last:
SELECT e.event_id,e.title,e.description,e.event_date,e.image, sum(d.amount) as total,count(d.event_id) as total_donors FROM event e,donation d where d.event_id = e.event_id group by e.event_id;
This joins the table but I want the null value as well, How can I modify this to get the last row in the desired results table(in the image attached)?
Also, what is this type of join called?
Thanks.
Your query just need to convert using LEFT JOIN like this:
SELECT e.event_id,e.title,e.description,e.event_date,e.image,
/*1*/
sum(ifnull(d.amount,0)) as total,
count(d.event_id) as total_donors
FROM event e
/*2*/
LEFT JOIN donation d
/*3*/
ON d.event_id = e.event_id
group by e.event_id;
Observe the following markings in the query above:
/*1*/ add ifnull in the sum operation to return 0 instead of null. This will also prevent null result if one of the value in sum is null.
/*2*/ change comma join to LEFT JOIN particularly because you want all rows from the left table are shown despite having no match in the table on the right.
/*3*/ change where to ON.
Here is a fiddle demo: https://dbfiddle.uk/?rdbms=mysql_5.5&fiddle=723cc34b7b875111701d9134b443f39b

MYSQL Statement Issues - INNER JOIN, LEFT JOIN WITH GROUP BY and MAX

I can't for the life of me get this statement to work.
SELECT max(pm.timestamp), pm.id, pm.p_media_user_id, pm.p_media_type,
pm.p_media_file, pm.wall_post, pm.p_media_location,pm.p_media_location_name,
pm.p_media_category, pa.p_source_alert_id, pa.post_id, pa.p_target_alert_id,
pu.fb_id, pu.username, pu.city, pu.sex, pu.main_image
FROM p_media as pm
INNER JOIN p_users as pu ON pm.p_media_user_id = pu.fb_id
LEFT JOIN p_alerts as pa ON pm.id = pa.post_id AND pa.p_source_alert_id ='3849084'
group by pm.p_media_user_id;
The only thing that I am having issues with is the max(pm.timestamp), after the grouping I would expect it to show the NEWEST rows in the p_media table, but to the contrary it's doing the exact opposite and showing the oldest rows. So, I need the newest rows from the p_media table grouped by the user id which Join the p_users table.
Thanks in advance, if anyone helps.
As others have already pointed out, you are aggregating by the p_media_user_id column but then selecting other non aggregate columns. This either won't run at all, or it will run but give non determistic results. However, it looks like you just want the most recent record from the p_media table, for each p_media_user_id.
If so, then this would seem to be the query you intended to run:
SELECT
pm1.timestamp, pm1.id, pm1.p_media_user_id, pm1.p_media_type, pm1.p_media_file,
pm1.wall_post, pm1.p_media_location, pm1.p_media_location_name,
pm1.p_media_category, pa.p_source_alert_id, pa.post_id, pa.p_target_alert_id,
pu.fb_id, pu.username, pu.city, pu.sex, pu.main_image
FROM p_media as pm1
INNER JOIN
(
SELECT p_media_user_id, MAX(timestamp) AS max_timestamp
FROM p_media
GROUP BY p_media_user_id
) pm2
ON pm1.p_media_user_id = pm2.p_media_user_id AND
pm1.timestamp = pm2.max_timestamp
INNER JOIN p_users AS pu
ON pm1.p_media_user_id = pu.fb_id
LEFT JOIN p_alerts AS pa
ON pm1.id = pa.post_id AND
pa.p_source_alert_id = '3849084';
Your query is not doing what you think it is doing. When you use GROUP BY, only the columns that appear in the GROUP BY clause can be used in the SELECT without an aggregate function. All columns that are not in the GROUP BY clause MUST be using in an aggregate function when adding them to the SELECT.
This is the standard, and for all databases that follow the standards, you will get an error from your query. For some reason, MySQL decided not to follow the standards on this and no error is returned. This is really bad, because your query will run, but the results cannot be predicted. So you will think that the query is fine and will wonder why you get the wrong results, while in fact your query is invalid.
MySQL has finally addressed the problem and starting with MySQL 5.7.5, the ONLY_FULL_GROUP_BY SQL mode is enabled by default. The reason they gave is rather silly: because GROUP BY processing has become more sophisticated to include detection of functional dependencies., but at least they've changed the default and starting with MySQL 5.7.5, it will behave like most other databases. For earlier versions, if you have access to change the settings, I recommend enabling ONLY_FULL_GROUP_BY so you get a clear error for such invalid queries.
In some cases, you really don't care about the value returned for the non-aggregate columns, if all the values are exactly the same. To let the query pass while ONLY_FULL_GROUP_BY is enabled, use the ANY_VALUE() function on those columns. The is a better approach as it clearly indicate your intention.
To learn how you can fix your query, you can read How do we select non-aggregate columns in a query with a GROUP BY clause. You need to self-join the p_media table with only the p_media_user_id and MAX(timestamp) selected on the grouping:
SELECT pm.timestamp, pm.id, pm.p_media_user_id, pm.p_media_type, pm.p_media_file,
pm.wall_post, pm.p_media_location, pm.p_media_location_name, pm.p_media_category,
pa.p_source_alert_id, pa.post_id, pa.p_target_alert_id,
pu.fb_id, pu.username, pu.city, pu.sex, pu.main_image
FROM p_media as pm
INNER JOIN (SELECT p_media_user_id, MAX(timestamp) AS max_time
FROM p_media
GROUP BY p_media_user_id
) pmm ON pm.p_media_user_id = pmm.p_media_user_id
AND pm.timestamp = pmm.max_time
INNER JOIN p_users AS pu ON pm.p_media_user_id = pu.fb_id
LEFT JOIN p_alerts AS pa ON pm.id = pa.post_id
AND pa.p_source_alert_id = '3849084';
You should be able to add an ORDER BY after the grouping and tell SQL what column you want to sort by [ASC or DESC].
SELECT max(pm.timestamp), pm.id, pm.p_media_user_id, pm.p_media_type,
pm.p_media_file, pm.wall_post, pm.p_media_location,pm.p_media_location_name,
pm.p_media_category, pa.p_source_alert_id, pa.post_id, pa.p_target_alert_id,
pu.fb_id, pu.username, pu.city, pu.sex, pu.main_image
FROM p_media as pm
INNER JOIN p_users as pu ON pm.p_media_user_id = pu.fb_id
LEFT JOIN p_alerts as pa ON pm.id = pa.post_id AND pa.p_source_alert_id ='3849084'
group by pm.p_media_user_id
ORDER BY pm.p_media_user_id DESC;

MySQL Query limiting results by sub table

I'm really struggling with this query and I hope somebody can help.
I am querying across multiple tables to get the dataset that I require. The following query is an anonymised version:
SELECT main_table.id,
sub_table_1.field_1,
main_table.field_1,
main_table.field_2,
main_table.field_3,
main_table.field_4,
main_table.field_5,
main_table.field_6,
main_table.field_7,
sub_table_2.field_1,
sub_table_2.field_2,
sub_table_2.field_3,
sub_table_3.field_1,
sub_table_4.field_1,
sub_table_4.field_2
FROM main_table
INNER JOIN sub_table_4 ON sub_table_4.id = main_table.id
INNER JOIN sub_table_2 ON sub_table_2.id = main_table.id
INNER JOIN sub_table_3 ON sub_table_3.id = main_table.id
INNER JOIN sub_table_1 ON sub_table_1.id = main_table.id
WHERE sub_table_4.field_1 = '' AND sub_table_4.field_2 = '0' AND sub_table_2.field_1 != ''
The query works, the problem I have is sub_table_1 has a revision number (int 11). Currently I get duplicate records with different revision numbers and different versions of sub_table_1.field_1 which is to be expected, but I want to limit the result set to only include results limited by the latest revision number, giving me only the latest sub_table_1_field_1 and I really can not figure it out!
Can anybody lend me a hand?
Many Thanks.
It's always important to remember that a JOIN can be on a subquery as well as a table. You could build a subquery that returns the results you want to see then, once you've got the data you want, join it in the parent query.
It's hard to 'tailor' an answer that's specific to you problem, as it's too obfuscated (as you admit) to know what the data and tables really look like, but as an example:
Say table1 has four fields: id, revision_no, name and stuff. You want to return a distinct list of name values, with their latest version of stuff (which, we'll pretend varies by revision). You could do this in isolation as:
select t.* from table1 t
inner join
(SELECT name, max(revision_no) maxr
FROM table1
GROUP BY name) mx
on mx.name = t.name
and mx.maxr = t.revision_no;
(Note: see fiddle at the end)
That would return each individual name with the latest revision of stuff.
Once you've got that nailed down, you could then swap out
INNER JOIN sub_table_1 ON sub_table_1.id = main_table.id
....with....
INNER JOIN (select t.* from table1 t
inner join
(SELECT name, max(revision_no) maxr
FROM table1
GROUP BY name) mx
on mx.name = t.name
and mx.maxr = t.revision_no) sub_table_1
ON sub_table_1.id = main_table.id
...which would allow a join with a recordset that is more tailored to that which you want to join (again, don't get hung up on the actual query I've used, it's just there to demonstrate the method).
There may well be more elegant ways to achieve this, but it's sometimes good to start with a simple solution that's easier to replicate, then simplify it once you've got the general understanding of the what and why nailed down.
Hope that helps - as I say, it's as specific as I could offer without having an idea of the real data you're using.
(for the sake of reference, here is a fiddle with a working version of the above example query)
In your case where you only need one column from the table, make this a subquery in your select clause instead of than a join. You get the latest revision by ordering by revision number descending and limiting the result to one row.
SELECT
main_table.id,
(
select sub_table_1.field_1
from sub_table_1
where sub_table_1.id = main_table.id
order by revision_number desc
limit 1
) as sub_table_1_field_1,
main_table.field_1,
...
FROM main_table
INNER JOIN sub_table_4 ON sub_table_4.id = main_table.id
INNER JOIN sub_table_2 ON sub_table_2.id = main_table.id
INNER JOIN sub_table_3 ON sub_table_3.id = main_table.id
WHERE sub_table_4.field_1 = ''
AND sub_table_4.field_2 = '0'
AND sub_table_2.field_1 != '';

Mysql where in not working as expected

I have the following query:
SELECT
`tests`.`id`,
`tests`.`created_at`,
`tests`.`updated_at`,
`tests`.`created_by`,
`tests`.`date_of_test`,
`tests`.`location`,
`tests`.`information`,
`tests`.`title`,
`tests`.`goals`,
`tests`.`deleted_at`,
`tests`.`status`,
`tests`.`tester`,
`tests`.`test_approach`
FROM `tests`
WHERE
`tests`.`id` IN (
SELECT `test_wobble`.`test_id`
FROM `project_wobble`
INNER JOIN `wobbles` ON `project_wobble`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profiles` ON `wobble_profiles`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profile_user` ON `wobble_profile_user`.`wobble_profile_id` = `wobble_profiles`.`id`
INNER JOIN `test_wobble` ON `test_wobble`.`wobble_id` = `wobbles`.`id`
WHERE `project_wobble`.`project_id` = '2' AND `wobble_profile_user`.`user_id` = '3'
GROUP BY `wobbles`.`id`
)
GROUP BY `tests`.`id`
ORDER BY tests.date_of_test DESC
If I run the IN query on its own, it returns
1 result
with the value 13.
the column is called "test_id"
When i run the whole above query, I get
2 results from the test table back...
with different ids... 13 and 14.
If I replace the IN query with the number 13... The SQL returns 1 result (The correct one).
What am i doing wrong here?
This query:
SELECT `test_wobble`.`test_id`
FROM `project_wobble`
INNER JOIN `wobbles` ON `project_wobble`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profiles` ON `wobble_profiles`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profile_user` ON `wobble_profile_user`.`wobble_profile_id` = `wobble_profiles`.`id`
INNER JOIN `test_wobble` ON `test_wobble`.`wobble_id` = `wobbles`.`id`
WHERE `project_wobble`.`project_id` = '2' AND `wobble_profile_user`.`user_id` = '3'
GROUP BY `wobbles`.`id`
groups by wobbles.id but returns test_wobble.test_id which is not a part of GROUP BY.
On each iteration, MySQL pushes the IN field into this query:
SELECT `test_wobble`.`test_id`
FROM `project_wobble`
INNER JOIN `wobbles` ON `project_wobble`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profiles` ON `wobble_profiles`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profile_user` ON `wobble_profile_user`.`wobble_profile_id` = `wobble_profiles`.`id`
INNER JOIN `test_wobble` ON `test_wobble`.`wobble_id` = `wobbles`.`id`
WHERE `project_wobble`.`project_id` = '2' AND `wobble_profile_user`.`user_id` = '3'
-- This is implicitly added by MySQL when optimizing
AND `test_wobble`.`test_id` = `tests`.`id`
GROUP BY `wobbles`.`id`
and then just checks if some value exists.
If you remove the GROUP BY from your IN query, you'll see that it contains both 13 and 14, but only one of those is returned when you run the query with GROUP BY.
You can also try running the second query, substituting 13 and 14 instead of tests.id and make sure the query returns something in both cases.
This might actually be considered a bug in MySQL. However, since the documentation does not specify which ungrouped and unaggregated expression will be returned from a grouped query, it's better to specify it explicitly, of side effects from the optimizer will kick in like the do in this case.
Could you please provide some sample of your data and outline what are you going to achieve with the query?
It is a little bit hard to tell without knowing what the data is. But, you do have an issue in the subquery. This is your subquery:
SELECT `test_wobble`.`test_id`
FROM `project_wobble` INNER JOIN
`wobbles`
ON `project_wobble`.`wobble_id` = `wobbles`.`id` INNER JOIN
`wobble_profiles`
ON `wobble_profiles`.`wobble_id` = `wobbles`.`id` INNER JOIN
`wobble_profile_user`
ON `wobble_profile_user`.`wobble_profile_id` = `wobble_profiles`.`id` INNER JOIN
`test_wobble`
ON `test_wobble`.`wobble_id` = `wobbles`.`id`
WHERE `project_wobble`.`project_id` = '2' AND `wobble_profile_user`.`user_id` = '3'
GROUP BY `wobbles`.`id`
Note the select and group by. These have different variables:
`test_wobble`.`test_id`
`wobbles`.`id`
I'm not sure which one you really want. But MySQL returns an indeterminate value when you run the query -- and a value that can change from one run to the next. You should fix the select and group by so they match.
The inner query exposes undefined behaviour. It is explained in the documentation on the page MySQL Handling of GROUP BY.
According to the SQL standard, the inner query is invalid. To be valid, all the columns that appear in the SELECT, HAVING and ORDER BY clauses must satisfy one of the following:
they appear in the GROUP BY clause;
are used (in SELECT, HAVING or ORDER BY) only as parameters of aggregate functions;
are functionally dependent on the GROUP BY columns.
For example, using your tables, you can put in the SELECT clause:
wobbles.id - because it appears in the GROUP BY clause;
COUNT(DISTINCT project_wobble.project_id) - even if project_wobble.project_id does not appear in GROUP BY, it can be used as a parameter of the aggregate function COUNT(DISTINCT);
any column of table wobbles, given that the column id is its PK - all the columns of table wobbles are functionally dependent on wobbles.id (their values are uniquely determined by the value of wobbles.id).
Before version 5.7.5, MySQL accepts queries that do not follow the above requirements but, as the documentation states:
In this case, the server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate, which is probably not what you want.
Starting with version 5.7.5, MySQL implements detection of functional dependence as an configurable feature (which is turned ON by default).
On 5.7.5 your inner query will trigger an error and that's all; your query is invalid, so it doesn't run at all.
On previous versions (also on 5.7.5 if the ONLY_FULL_GROUP_BY SQL mode is disabled), the query runs but its results are unpredictable. They can change from one execution to the next if, for example, a row is deleted then re-inserted.
Because the MySQL query optimizer re-organizes your whole query for better execution plan, when it is embedded in the larger query its execution is not the same as when it is ran standalone. This is another way you can observe its undefined behaviour.
How to fix your query
Extract the inner query, remove the GROUP BY clause, add more columns to the SELECT clause and look at what it produces:
SELECT DISTINCT `test_wobble`.`wobble_id`, `test_wobble`.`test_id`
FROM `project_wobble`
INNER JOIN `wobbles` ON `project_wobble`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profiles` ON `wobble_profiles`.`wobble_id` = `wobbles`.`id`
INNER JOIN `wobble_profile_user` ON `wobble_profile_user`.`wobble_profile_id` = `wobble_profiles`.`id`
INNER JOIN `test_wobble` ON `test_wobble`.`wobble_id` = `wobbles`.`id`
WHERE `project_wobble`.`project_id` = '2' AND `wobble_profile_user`.`user_id` = '3'
If I'm not wrong, it will produce two rows having the same wobble_id and values 13 and 14 for column test_id.
If this result set is correct then you can remove test_wobble.wobble_id from SELECT, keep DISTINCT and put the query into the larger one.
There is no need for GROUP BY (because of the DISTINCT) and it should work faster without it.

MySQL include zero rows when using COUNT with GROUP BY

I am trying to perform a query which groups a set of data by an attribute called type_id.
SELECT
vt.id AS voucher_type,
COALESCE(COUNT(v.id), 0) AS vouchers_remaining
FROM
vouchers v
INNER JOIN voucher_types vt
ON vt.id = v.type_id
WHERE
v.sold = 0
GROUP BY vt.id
What I want in the result is the type_id and the number of unsold products remaining for each type. This is working OK provided that there is at least one left, however if there is a zero count row, it is not returned in the result set.
How can I set up a dummy row for those types which do not have any corresponding rows to count?
Any advice would be greatly appreciated.
Thanks
You'll have to use a LEFT JOIN instead of an INNER JOIN. You start by selecting all voucher_types and then left join to find the count.
SELECT
voucher_types.id AS voucher_type,
IFNULL(vouchers_count.vouchers_remaining, 0) AS vouchers_remaining
FROM
voucher_types
LEFT JOIN
(
SELECT
v.type_id AS voucher_type,
COUNT(v.id) AS vouchers_remaining
FROM
vouchers v
WHERE
v.sold = 0
GROUP BY v.type_id
) AS vouchers_count
ON vouchers_count.voucher_type = voucher_types.id
You want an OUTER JOIN (or LEFT JOIN, same difference) instead of an INNER JOIN. That should already do the trick.
Because you're doing an INNER JOIN you automatically exclude types with no corresponding vouchers. You need a RIGHT OUTER JOIN.
Also, as far as I can remember, COUNT will always give you an integer, so there is no need for the COALESCE.
Good luck,
Alin