Get the last record with INNER JOIN - mysql

I'm trying to get the last record, but I ger the first record.
What am I doing wrong?
My Table permission
|id|pid|uid|
| 1| 2 | 2 |
| 2| 5 | 2 |
My Table fruits
|id|pid|number1|number2|
|1 | 1 | 50 | 100 |
|2 | 1 | 10 | 100 |
|3 | 1 | 100 | 100 | <== Try get last record
I want get the last record, but I can't.
I create the query, but not work:
SELECT DISTINCT(fruits.pid), permission.pid, fruits.number1, fruits.number2
FROM permission
LEFT JOIN fruits ON permission.pid = fruits.pid
WHERE permission.uid = '2'
GROUP BY fruits.pid
ORDER BY fruits.id DESC
I need the result:
|pid|pid|number1|number2|
|3 | 1 | 100 | 100 |

Your join doesn't join any rows. The value of fruits.pid is always 1. The values of permissions.pid are (2, 5). Thus, your join of fruits.pid = permission.pid doesn't find any rows that match, so you're not getting the results you expect. If you drop the DISTINCT in the query and remove the GROUP BY (which causes it to fail in MySQL 8) your query produces:
pid pid number1 number2
null 2 null null
null 5 null null
The row you want isn't in the result set, so of course you don't get it.
The other problem you have is that the number 3 is not in the column fruits.pid. It's an id value, so I suspect you're joining on the wrong field. And you've got permission.pid as the second field returned by your query, but that column only contains 2 and 5, as noted earlier, but you want a value of 1 there; thus, it appears you want to return fruits.pid as the second column of the result set. So something like:
SELECT fruits.id, fruits.pid, fruits.number1, fruits.number2
FROM fruits
LEFT JOIN permission
ON permission.id = fruits.pid
WHERE permission.uid = '2'
ORDER BY fruits.id DESC
db<>fiddle here

Related

Find row with certain value, then select next X rows

I'm trying to do something that should be relatively simpel, I guess, but I can't wrap my head around it.
I want to find a certain id in a table, and then select the next X rows that meet a certain criteria.
Example table:
+++++++++++++++++++++++++++++++
| id | type | value | sorting |
+++++++++++++++++++++++++++++++
|1 | 'x' | 'foo' | 1 |
|2 | 'y' | 'bar' | 5 |
|3 | 'z' | 'foo2'| 9 |
|4 | 'z' | 'bar2'| 29 |
|5 | 'x' | 'foo3'| 3 |
|6 | 'z' | 'bar3'| 11 |
|7 | 'z' | 'foo4'| 4 |
+++++++++++++++++++++++++++++++
What I want is to select the next X rows where type = 'z' starting from row with id = 3, sorted by sorting.
So for this table, I would want to get rows with id 3, 6, 4, in that order. Note that row with id 7 matches the type, but it's sorting value is lower than row with id 3.
Can this be done in one query?
My ideas: for the example table, something as such would do:
SELECT * FROM table WHERE type = 'z' AND sorting > 9 ORDER BY sorting LIMIT 3, X
But obviously, I can't know the values 9 and the offset yet, so I'd need a way to:
Find the sorting value for id 3.
Find the offset for id 3.
Apply those to the query.
Edit: Where I'm at now:
SELECT
*
FROM table
WHERE type = 'z' AND sorting > (SELECT sorting FROM table WHERE id = 3)
ORDER BY sorting
LIMIT 0, 25
So the last step is to get the offset of 3 and pass that as the first parameter to LIMIT.
Your goal is still not clear. But here is my attempt:
http://sqlfiddle.com/#!9/2d389/1
SELECT t1.*
FROM foobar t1
JOIN (SELECT *
FROM foobar
WHERE id=3
) t2
ON t1.id >= t2.id
AND t1.type = t2.type
AND t1.sorting >= t2.sorting
ORDER BY sorting
LIMIT 10

sql select count with group, add null value if no result found

I have three table which i want to count each row with group from another table column.
The problem is count with group will return nothing when no record found.
So i want to add null value for each group that no record found.
Here is the query:
select monster.monster_name,count(*) as count
from monster right join monster_ability
on monster.monster_id= monster_ability.monster_id where
isnull(monster_ability.used)
group by monster.monster_id
here is the fiddle: fiddle
I want the result should look like this:
| monster_name | count |
|--------------|-------|
| kora | 1 |
| lowdowu | 3 |
| ngjengeh| null|
| lortyu | 1 |
| foh du fy| null|
Use case when to get null when count is 0:
select
m.monster_name,
case when count(a.ability_id) = 0 then null else count(a.ability_id) end as `count`
from monster m
left join monster_ability ma on m.monster_id = ma.monster_id and ma.used is null
left join ability a on ma.ability_id = a.ability_id
group by m.monster_id
SQLFiddle demo here.

Update without where clause

+------+------+
| id | no |
+------+------+
| 1 | 1 |
| 11 | 1 |
| 21 | 1 |
+------+------+
I want to update 2nd row no. to 2.
the query i can use is
update test set no = 2 where id = 11;
How can i achieve the same without where clause ??
I am not sure why you would want to but...
UPDATE `test` SET `no` = IF(`id`=11, 1, `no`);
For the record, I would be surprised if this didn't perform horribly as it would go through every row in the table.
To update the "second" row in the table, the row that has the second smallest id value...
UPDATE test t
JOIN ( SELECT r.id
FROM test r
ORDER BY r.id
LIMIT 1,1
) s
ON s.id = t.id
SET t.no = 2
EDIT
As a followup to clarify the results of the query above...
In the case where id is not unique in the table, the query could potentially update more than one row. The inline view query (s) gets the id value from the "second" row, after the rows are ordered by id value. Then all rows that have that same id value would be updated.
This is an issue only if id is not unique; if id is unique, the statement would update (at most) one row.
For example, if the contents of the table was:
+-----+-----+
| id | no |
+-----+-----+
| 1 | 1 |
| 11 | 3 | <-- "second" row, ordered by id ascending
| 11 | 4 | <-- id from third row matches id from second row
| 21 | 1 |
+-----+-----+
The result of the query above would be to update the two rows that have id value of 11.
+-----+-----+
| id | no |
+-----+-----+
| 1 | 1 |
| 11 | 2 | <-- updated
| 11 | 2 | <-- updated
| 21 | 1 |
+-----+-----+
That´s not possible, a update without where is an update to all the table. You can try this, but it is always like a where:
update test set no = case id when 11 then 2 else no end
This doesn't use a where clause and it might be a bit faster than using if() or case:
update test t join
(select 1 as dum) dum
on t.id = 11
set t.no = 2 ;
And yet a 3rd way...
update test A INNER JOIN test B
on A.ID = B.ID
and B.ID = 11
set A.No = 2;
For clarity this does a self join on a table that only has record 11, thus updating only record 11 (b.iD = 11). using an ON Clause.

Values in same row of groupwise maximum

I've got a table with the most common colors in images. It looks something like this:
file | color | count
---------------------
1 | ffefad | 166
1 | 443834 | 84
2 | 74758a | 3874
2 | abcdef | 228
2 | 876543 | 498
3 | 543432 | 3382
3 | abcdef | 483
I'm trying to get the most common color for each image. So I'd like my result to be:
file | color | count
---------------------
1 | ffefad | 166
2 | 74758a | 3874
3 | 543432 | 3382
So my problem seems to be that I need to GROUP BY the file column, but MAX() the count column. But simply
SELECT h.file, h.color, MAX(h.count) FROM histogram GROUP BY h.file
isn't working because it's indeterminate, so the color result won't match the row from the count result.
SELECT h.file, h.color, MAX(h.count) FROM histogram GROUP BY h.file, h.color
fixes the determinacy, but now every row is "unique" and all rows are returned.
I can't figure out a way to do a subquery or join, since the only "correct" values I can figure to get, file and count, are not distinct by themselves.
Perhaps I need a saner schema? It's "my" table so I can change that if need be.
SELECT tbl.file, tbl.color, tbl.count
FROM tbl
LEFT JOIN tbl as lesser
ON lesser.file = tbl.file
AND tbl.count < lesser.count
WHERE lesser.file IS NULL
order by tbl.file
select file , max(count)
FROM histogram
GROUP BY h.file
This will give the max(count) by file. Turn it into a subquery and inner join so it acts as a filter.
select h.file, h.colour, h.count
from histogram inner join
(select file , max(count) as maxcount
FROM histogram
GROUP BY h.file) a
on a.file = h.file and a.maxcount = h.count
This will respond with 2 rows if there are more than 1 colour with the same max count.

Joining 3 tables with n:m relationship, want to see nonmatching rows

For this problem, consider the following 3 tables:
Event
id (pk)
title
Event_Category
event_id (pk, fk)
category_id (pk, fk)
Category
id (pk)
description
Pretty trivial I guess... :) Each event can fall into zero or more categories, in total there are 4 categories.
In my application, I want to view and edit the categories for a specific event. Graphically, the event will be shown together with ALL categories and a checkbox indicating whether the event falls into the category. Changing and saving the choice will result in modifocation of the intermediate table Event_Category.
But first: how to select this for a specific event? The query I need will in fact always return 4 rows, the number of categories present.
Following returns only the entries for the categories the event with id=11 falls into. Experimenting with outer joins did not give more rows in the result.
SELECT e.id, c.omschrijving
FROM Event e
INNER JOIN Event_Categorie ec ON e.id = ec.event_id
INNER JOIN Categorie c ON c.id = ec.categorie_id
WHERE e.id = 11
Or should I start with the Category table in the query? Hope for some hints :)
TIA, Klaas
UPDATE:
Yes I did but still have not found the answer. But I have simplified the issue by omitting the Event table from the query because this table is only used to view the Event descriptions.
SELECT * from Categorie c LEFT JOIN Event_Categorie ec ON c.id = ec.categorie_id WHERE ec.event_id = 11;
The simplified 2-table query only uses the lookup table and the link table but still returns only 2 rows instead of the total of 4 rows in the Categorie table.
My guess would be that the WHERE clause is applied after the joining, so the rows not joined to the link table are excluded. In my application I solved the issues by using a subquery but I still would like to know what is the best solution.
What you want is the list of all categories, plus information about whether that category is in the list of categories of your event.
So, you can do:
SELECT
*
FROM
Category
LEFT JOIN Event_Category ON category_id = id
WHERE
event_id = 11
and event_id column will be NULL on the categories that are not part of your event.
You can also create a column (named has_category below) that you will use to see if the event has this category instead of comparing with NULL:
SELECT
*,
event_id IS NOT NULL AS has_category
FROM
Category
LEFT JOIN Event_Category ON category_id = id
WHERE
event_id = 11
EDIT: This seems exactly what you say you are doing on your edit. I tested it and it seems correct. Are you sure you are running this query, and that rows with NULL are not somehow ignored?
The query
SELECT * FROM Categorie;
returns 4 rows:
+----+--------------+-------------------------------------+--------------------------------------+
| id | omschrijving | afbeelding | afbeelding_klein |
+----+--------------+-------------------------------------+--------------------------------------+
| 1 | Creatief | images/categorieen/creatief420k.jpg | images/categorieen/creatief190k.jpg |
| 2 | Sportief | images/categorieen/sportief420k.jpg | images/categorieen/sportief190kr.jpg |
| 4 | Culinair | images/categorieen/culinair420k.jpg | images/categorieen/culinair190k.jpg |
| 5 | Spirit | images/categorieen/spirit420k.jpg | images/categorieen/spirit190k.jpg |
+----+--------------+-------------------------------------+--------------------------------------+
4 rows in set (0.00 sec)
BUT:
The query
SELECT *
FROM Categorie
LEFT JOIN Event_Categorie ON categorie_id = id
WHERE event_id = 11;
returns 2 rows:
+----+--------------+-------------------------------------+-------------------------------------+----------+--------------+
| id | omschrijving | afbeelding | afbeelding_klein | event_id | categorie_id |
+----+--------------+-------------------------------------+-------------------------------------+----------+--------------+
| 1 | Creatief | images/categorieen/creatief420k.jpg | images/categorieen/creatief190k.jpg | 11 | 1 |
| 4 | Culinair | images/categorieen/culinair420k.jpg | images/categorieen/culinair190k.jpg | 11 | 4 |
+----+--------------+-------------------------------------+-------------------------------------+----------+--------------+
2 rows in set (0.00 sec)
So I still need the subquery... and the LEFT JOIN is not effective in showing all rows of the CAtegorie table, regardless whether there is a match with the link table.
This query, however, does what I want it to do:
SELECT *
FROM Categorie c
LEFT JOIN (SELECT * FROM Event_Categorie ec WHERE ec.event_id = 11 ) AS subselect ON subselect.categorie_id = c.id;
Result:
+----+--------------+-------------------------------------+--------------------------------------+----------+--------------+
| id | omschrijving | afbeelding | afbeelding_klein | event_id | categorie_id |
+----+--------------+-------------------------------------+--------------------------------------+----------+--------------+
| 1 | Creatief | images/categorieen/creatief420k.jpg | images/categorieen/creatief190k.jpg | 11 | 1 |
| 2 | Sportief | images/categorieen/sportief420k.jpg | images/categorieen/sportief190kr.jpg | NULL | NULL |
| 4 | Culinair | images/categorieen/culinair420k.jpg | images/categorieen/culinair190k.jpg | 11 | 4 |
| 5 | Spirit | images/categorieen/spirit420k.jpg | images/categorieen/spirit190k.jpg | NULL | NULL |
+----+--------------+-------------------------------------+--------------------------------------+----------+--------------+
4 rows in set (0.00 sec)
The issue is that you have filtered the results by the eventid. As you can see in your results, two of the categories (Sportief and Spirit) do not have events. So the correct SQL statement (using SQL Server syntax; some translation may be required) is:
SELECT *
FROM Categorie
LEFT JOIN Event_Categorie ON categorie_id = id
WHERE (event_id IS NULL) OR (event_id = 11);
Finally I found the right query, no subselect is necessary. But the WHERE clause works after the joining and therefore is no part of the join anymore. THe solution is extending the ON clause with an extra condition. Now all 4 rows are returned with NULL for the non-matching Categories!
SELECT *
FROM Categorie
LEFT JOIN Event_Categorie ON categorie_id = id AND event_id = 11;
So the bottom line is that putting an extra condition in the ON clause has different effect than filtering out rows by the same condition in the WHERE clause!