Update without where clause - mysql

+------+------+
| 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.

Related

Get the last record with INNER JOIN

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

MySQL - dont show any row from ID use

I just need to show the values that don't use the specifically ID.
I have two table
table 1
id_xx
1
2
3
4
5
table 2
id | id_xx
3 | 3
4 | 3
4 | 1
I need this results for example. I say which results from ID i need
i need this result where id=3
id_xx
1
2
4
5
or where id=4
id_xx
2
4
5
or where id=1
1
2
3
4
5
You can LEFT JOIN table1 with table2 and apply the filter in the ON clause of the JOIN, and then filter on unmatched records:
SELECT t1.id_xx
FROM table1 t1
LEFT JOIN table2 t2 ON t2.id_xx = t1.id_xx AND t2.id = ?
WHERE t2.id IS NULL
You can replace the question mark with the id that you need to check.
Demo on DB Fiddle:
Given t2.id = 3:
| id_xx |
| ----- |
| 1 |
| 2 |
| 4 |
| 5 |
Given t2.id = 4:
| id_xx |
| ----- |
| 2 |
| 4 |
| 5 |
Another approach is using a Correlated Subquery with NOT EXISTS():
SELECT t1.id_xx
FROM table1 AS t1
WHERE NOT EXISTS (SELECT 1
FROM table2 AS t2
WHERE t2.id = ? -- your input id here
AND t2.id_xx = t1.id_xx)
If you have large table(s), and are worried about performance of these queries, then you may define the following index:
For the correlated subquery, define composite index (id, id_xx) on table2.
ALTER TABLE table2 ADD INDEX(id, id_xx);
Assuming that id_xx is already a Primary Key in the table1. So, you don't need to define any index there. If not, then you can define an index on it.

MySQL Update table by matchig values in the same column

I have a table where I store data for different groups and I need to update one group if values in one column are matching.
the table looks like this:
prop_id | group_id | value | visible
1 | 1 | 10 | 1
1 | 2 | 10 | 1
1 | 3 | 15 | 1
2 | 1 | 10 | 1
2 | 2 | 10 | 1
2 | 3 | 10 | 1
So I want to set the visible column to 0 for the group_id=3 if the values in the value column are equal to group_id=1. In this case if value=10 for both group_id=1 and group_id=3 than set visible=0 for group_id=3
expected result after update
prop_id | group_id | value | visible
1 | 1 | 10 | 1
1 | 2 | 10 | 1
1 | 3 | 15 | 1
2 | 1 | 10 | 1
2 | 2 | 10 | 1
2 | 3 | 10 | 0
How is this possible?
Write it as a SELECT first.
Start simple, the rows that we want to update we know are group_id=3 and visible=1, so write a query that gets all of those rows:
SELECT g3.value
, g3.visible
FROM mytable g3
WHERE g3.group_id = 3
AND g3.visible = 1
We know the rows we want to update are in that set, but there are some additional conditions.
So we extend that. According to the spec, we need to find out if there are any matching group_id=1 rows that are visible=1 (matching on value).
We can do that check either with an EXISTS correlated subquery, or we can use a JOIN.
SELECT g3.group_id
, g3.value
, g3.visible
FROM mytable g3
WHERE g3.group_id = 3
AND g3.visible = 1
AND EXISTS ( SELECT 1
FROM mytable g1
WHERE g1.group_id = 1
AND g1.visible = 1
AND g1.value = g3.value
)
-or-
SELECT g3.group_id
, g3.value
, g3.visible
FROM mytable g3
JOIN mytable g1
ON g1.group_id = 1
AND g1.visible = 1
AND g1.value = g3.value
WHERE g3.group_id = 3
AND g3.visible = 1
Verify the query is returning the rows we want to update, under the specific conditions. (It is much easier to verify the results of a SELECT statement, and adjust as necessary, than it is an UPDATE statement.)
Once we have a SELECT query working and verified (returning the rows we want to update) we can convert it into an UPDATE statement. Replace the SELECT ... FROM with UPDATE and add a SET clause that is returning the rows
UPDATE mytable g3
JOIN mytable g1
ON g1.group_id = 1
AND g1.visible = 1
AND g1.value = g3.value
SET g3.visible = 0
WHERE g3.group_id = 3
AND g3.visible = 1
Use Self JOIN then UPDATE
You can try this.
UPDATE T t1
JOIN T t2 on t1.group_id = t2.group_id
and t1.rop_id<>t2.rop_id and t1.value > t2.value
SET t2.visible = 0
sqlfiddle:http://sqlfiddle.com/#!9/6f06de/1

Sort MySQL Query results by amount of recursion in foreign keys

I have the following table:
+----+--------+
| id | parent |
+----+--------+
| 1 | 4 |
| 2 | 1 |
| 3 | NULL |
| 4 | NULL |
| 5 | 2 |
| 6 | 3 |
+----+--------+
I want this table to be ordered like this:
+----+--------+------------------------------------------------------------+
| id | parent | Why it has to be ordered like this |
+----+--------+------------------------------------------------------------+
| 5 | 2 | 5 has parent 2 has parent 1 has parent 4. So 3 rows above. |
| 2 | 1 | 2 has parent 1 has parent 4. So 2 rows above. |
| 1 | 4 | 1 has parent 4. So 1 row above. |
| 6 | 3 | 6 has parent 3. So 1 row above. |
| 4 | NULL | No parent. So 0 rows above. |
| 3 | NULL | No parent. So 0 rows above. |
+----+--------+------------------------------------------------------------+
So I want to recursively count the ancestors of a row and sort on that. How can I do that?
Edit: I'm on MySQL version 5.7.21.
You could do this with a recursive CTE, but you didn't list your mysql version and not all versions can do that, so here is something that should work even for older versions. This does the recursion itself with a temporary table and a while statement. The temporary table gets built with one record for each record in the main table, which holds the parent count data. First we do all records with no parent, then the query inside the while does all the records for the next generation. Note that the syntax may be a little bit off, I haven't done mysql for some time.
--Create temp table to hold the parent count data
CREATE TEMPORARY TABLE ParentCount (id int, pcount int);
--First create a pcount record with count zero for all records with no parent
insert into ParentCount (id, pcount) Select id, 0 from TestData where parent is null;
--If we don't have a parentcount set for every record, keep going
-- This will run once for every level of depth
While (Select COUNT(id) from TestData) <> (Select COUNT(id) from ParentCount) Begin
--add a pcount record for all rows that don't have one yet, but whose
-- parents do have one (ie the next generation)
insert into ParentCount (id, pcount)
Select T.id, P.pcount + 1 as newpcount
from TestData T
inner join ParentCount P on P.id = T.parent
left outer join ParentCount P2 on P2.id = T.id
where P2.id is null;
End;
--final query
Select T.id, T.parent
from TestData T
inner join Parents P on T.id = p.id
order by P.pcount DESC, T.id ASC;

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!