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
Related
I've tried a few PROCEDURES and LOOPS, but i'm having trouble getting my results.
I have a table of 19,000 records that looks like this:
id | seq | custom_id
1 | 0 | 123
2 | 0 | 124
3 | 1 | NULL
4 | 0 | 125
5 | 1 | NULL
6 | 2 | NULL
7 | 3 | NULL
My goal is:
id | seq | custom_id
1 | 0 | 123
2 | 0 | 124
3 | 1 | 124-1
4 | 0 | 125
5 | 1 | 125-1
6 | 2 | 125-2
7 | 3 | 125-3
So if seq is 0 it will have a custom ID. if seq is not 0 I would like to get the custom id and concat -seq to the end.
In a Correlated Subquery, we can get the previous (and closest) custom_id value where the seq is 0.
Now, we simply need to use Concat() function to concatenate the previous custom_id value with the current row's seq value, to get the new custom_id.
Try the following query to Select the data (DB Fiddle DEMO):
SELECT
t1.id,
t1.seq,
CASE WHEN t1.seq = 0 THEN t1.custom_id
ELSE CONCAT((SELECT t2.custom_id
FROM your_table AS t2
WHERE t2.id < t1.id AND
t2.seq = 0
ORDER BY t2.id DESC LIMIT 1), '-', t1.seq)
END AS custom_id
FROM your_table AS t1
However, based on your comments, it seems that you are interested in Updating the custom_id column at once. In MySQL, using subquery on the same table (which is being updated as well), is possible via Derived Tables approach.
We determine the modified custom_id for id where seq <> 0 in a sub-select result set (Derived table), and then Join it back to the main table for update.
Try the following for Updating the data (DB Fiddle DEMO):
UPDATE
your_table AS tab
JOIN
(
SELECT
t1.id,
CONCAT((SELECT t2.custom_id
FROM your_table AS t2
WHERE t2.id < t1.id AND
t2.seq = 0
ORDER BY t2.id DESC LIMIT 1),
'-', t1.seq) AS custom_id
FROM your_table AS t1
WHERE t1.seq <> 0
) AS dtab ON dtab.id = tab.id
SET tab.custom_id = dtab.custom_id
WHERE tab.seq <> 0;
I have a table that has the rows item_id (unique key), base_id, step_id, and active.
What i need to do is update everything in that table, that matches base_id where step_id = 1 and active = 0 to active = 1 that doesn't have an entry in the same table with the same base_id and step_id = 2 and active = 1.
----------------------------------------
| item_id | base_id | step_id | active |
| 1 | 1 | 1 | 0 |
| 2 | 1 | 2 | 1 |
| 3 | 2 | 1 | 0 |
| 4 | 3 | 1 | 0 |
| 5 | 3 | 1 | 0 |
----------------------------------------
This would return make item 3, 4, and 5 update to have active = 1
If that makes sense. Any help is greatly appreciated. Thanks in advance.
select item_id
from your_table
where base_id in
(
select base_id
from your_table
group by base_id
having sum(step_id = 1 and active = 0) > 0
and sum(step_id = 2 and active = 1) = 0
)
What does the inner select do?
It groups the records by base_id and takes only those having at least 1 record with step_id = 1 and active and zero records with step_id = 2 and active = 1.
sum() counts how many times the inner condition is true.
To update the table so that the matching values have active set to 1 we can take the solution by juergen d and turn it into an update statement.
As MySQL has some issues with updating a table that it is referencing in a subquery we insert an extra level of nesting which forces the creation of a temporary result and allows the update:
update table1 t
set t.active = 1
where base_id in (
select base_id from (
select base_id
from table1
group by base_id
having sum(step_id = 1 and active = 0) > 0
and sum(step_id = 2 and active = 1) = 0
) a
);
This would set active = 1 for item_id 3, 4 and 5
Sample SQL Fiddle
I would approach this with a simple in or exists:
select t.*
from table t
where step_id = 1 and active = 0 and
not exists (select 1
from table t2
where t2.base_id = t.base_id and t2.step_id = 2 and t2.active = 1
);
This seems like a direct translation of your description.
+------+------+
| 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.
This question is based on: Select row from left join table where multiple conditions are true
I am now trying to select rows from Table 1, which do not have a connection in Table 2 to a certain property ID.
These are the tables:
Table 1
| ID | Name |
| 1 | test |
| 2 | hello |
Table 2
| ID | PropertyID |
| 1 | 3 |
| 1 | 6 |
| 1 | 7 |
| 2 | 6 |
| 2 | 1 |
I am using the following query (which is working with '='):
SELECT tab1ID
FROM table2
WHERE propertyID != 3 OR propertyID = 6
GROUP BY tab1ID
HAVING COUNT(*) = 2;
This query should return ID=2, but it returns zero rows. What I am doing wrong?
Any help is greatly appreciated!
Edit: I had given a MWE but this is my actual query:
SELECT transactionline.total FROM transactionline
LEFT JOIN product_variant ON product_variant.SKU = transactionline.SKU
LEFT JOIN product ON product_variant.productID = product.productID
LEFT JOIN connect_option_product ON connect_option_product.productID = product.productID
LEFT JOIN productattribute_option ON productattribute_option.optionID = connect_option_product.optionID
WHERE productattribute_option.optionID = 4 OR productattribute_option.optionID = 9
GROUP BY transactionline.lineID
HAVING COUNT(*) = 1
AND SUM(productattribute_option.optionID = 4) = 0
AND SUM(productattribute_option.optionID = 9) > 0
A product can have multiple connections to the optionID's. The goal of this query is to select the total amount where some filters are true or false.
Your grouping is correct. But you need to count how many times the value you do not want is in your group. That count must be zero.
SELECT tab1ID
FROM table2
GROUP BY tab1ID
HAVING sum(propertyID = 6) > 0
AND sum(propertyID = 3) = 0
I just added the 'default' column to my DB. I am trying to set the default value to '1' based on the latest 'addDate' per accountId.
+----+-----------+--------------------+--------+
| id | accountId | addDate | default|
+----+-----------+--------------------+--------+
| 1 | 45 |2012-02-29 08:41:59 | |
| 2 | 55 |2012-03-29 08:41:59 | |
| 3 | 45 |2012-04-29 08:41:59 | |
| 4 | 55 |2012-05-29 08:41:59 | |
| 5 | 60 |2012-05-29 08:41:59 | |
+----+-----------+--------------------+--------+
I found I was able to isolate the proper rows by using =>
select * from tble1
where addDate = (select max(addDate) from tble1 as sl where sl.accountId = tble1.accountId);
I need to be able to run an UPDATE that sets 'default' column to '1' only 1 time per 'accountId' basing it off of latest 'addDate'.
try this
UPdate Table1
SET `default` = 1
where addDate in (select * from (
select max(addDate) from table1 as sl group by accountId)t
)
DEMO HERE
UPDATE table1 x
LEFT
JOIN table1 y
ON y.accountid = x.accountid
AND y.adddate > x.adddate
SET x.default = 1
WHERE y.id IS NULL;
or (faster)
UPDATE table1 x
JOIN
( SELECT accountid
, MAX(addDate) max_adddate
FROM table1
GROUP
BY accountid
) y
ON y.accountId = x.accountId
AND y.max_adddate = x.adddate
SET x.default = 1;