MySQL update table with values from same table - mysql

I have a 4 column table, the primary key is a composite of id, gameId and flag.
id | gameId | score | flag
--------------------------
1 | 1 | 10 | 1
1 | 1 | 20 | 0
2 | 1 | 1 | 0
1 | 2 | 10 | 1
3 | 2 | 1 | 0
I need to update the table so that:
All of gameId 2 scores are added to gameId 1 where the id and flag is the same.
(e.g. row 1 would have a score of 20 by adding the scores of row 1 and row 4)
If the above happens the gameId 2 row needs to be deleted.
Where the above isn't found (e.g. there is a row where the gameId is 2 but the id and flag don't match another row), the gameId can just be changed to 1.
So my table after the SQL is complete should look like this:
id | gameId | score | flag
--------------------------
1 | 1 | 20 | 1
1 | 1 | 20 | 0
2 | 1 | 1 | 0
3 | 1 | 1 | 0
How can I write this in SQL?
Thanks :)

think this going to work:
Try 1
UPDATE score_list AS t2
LEFT JOIN score_list AS t1 ON
(t1.id = t2.id AND t1.flag = t2.flag AND t1.gameId = 1)
SET
t1.score = t1.score + t2.score,
t2.gameId = IF(t1.gameId IS NULL, 1, t2.gameId)
WHERE t2.gameId = 2;
DELETE FROM score_list WHERE gameId = 2;
Try 2
# add scores to gameId = 1
UPDATE score_list AS t2
LEFT JOIN score_list AS t1 ON
(t1.id = t2.id AND t1.flag = t2.flag AND t1.gameId = 1)
SET
t1.score = t1.score + t2.score
WHERE t2.gameId = 2;
# try to move gameID 2 to gameId 1, using ignore to allow rows to fail, as gameId alredy exists
UPDATE IGNORE score_list SET gameId = 1 WHERE gameId = 2;
# delete all not updated rows from last query
DELETE FROM score_list WHERE gameId = 2;

Related

multiple row update with one SQL

I have two tables below
t1
-------------------------------------
| id | MaleCnt | FemaleCnt | flag |
------------------------------------
1 20 null 1
2 30 null 1
3 40 null 1
t2
----------------------------
| id | FemaleCnt | flag |
----------------------------
1 20 1
2 30 1
3 40 1
I want to update "FemaleCnt" at table t1 with table t2
(shoud have same id and flag)
I just wrote some query but dont work, so far.
Could you give me some tip??
Just do JOIN & update :
UPDATE t1 INNER JOIN
t2
ON t2.id = t1.id AND t2.flag = t1.flag
SET t1.FemaleCnt = t2.FemaleCnt;
This should work.
UPDATE t1 SET t1.FemaleCnt = t2.FemaleCnt
WHERE t1.id = t2.id AND t1.flag = t2.flag

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

Get next and previous primary keys that match a pattern

I have a database similar to the following...
ID ! Value
...
654 ! Blue
656 ! Green
659 ! Blue
665 ! Blue
...
I have the value of a numerical primary key. I'm wanting to do a query that pulls the previous and next primary keys that match a pattern.
For example, I have ID 659, I want to do something like
SELECT NEXT, PREV FROM TABLE WHERE VALUE = 'Blue';
And I'm trying to do it efficiently instead of fetching the whole table.
1 row and 2 columns:
SELECT
(SELECT ID FROM test WHERE ID < 659 AND Value = 'Blue' ORDER BY ID DESC LIMIT 1) AS PREV,
(SELECT ID FROM test WHERE ID > 659 AND Value = 'Blue' ORDER BY ID ASC LIMIT 1) AS NEXT;
2 rows and 1 column:
(SELECT ID AS PREV FROM test WHERE ID < 659 AND Value = 'Blue' ORDER BY ID DESC LIMIT 1)
UNION
(SELECT ID AS NEXT FROM test WHERE ID > 659 AND Value = 'Blue' ORDER BY ID ASC LIMIT 1);
DROP TABLE IF EXISTS T;
CREATE TABLE T (ID INT PRIMARY KEY,VAL VARCHAR(10));
INSERT INTO T (ID,VAL) VALUES (654,'BLUE'),(656,'GREEN'),(659,'BLUE'),(665,'BLUE');
SELECT CURRENT.ID CURRENTID,CURRENT.VAL,
(SELECT MIN(ID) FROM T NEXT WHERE NEXT.ID > CURRENT.ID AND NEXT.VAL = CURRENT.VAL) NEXT,
(SELECT MAX(ID) FROM T PREV WHERE PREV.ID < CURRENT.ID AND PREV.VAL = CURRENT.VAL) PREV
FROM T CURRENT;
+-----------+-------+------+------+
| CURRENTID | VAL | NEXT | PREV |
+-----------+-------+------+------+
| 654 | BLUE | 659 | NULL |
| 656 | GREEN | NULL | NULL |
| 659 | BLUE | 665 | 654 |
| 665 | BLUE | NULL | 659 |
+-----------+-------+------+------+
4 rows in set (0.00 sec)
Or less elegantly (can't say about performance)
SELECT CURRENT.ID CURRENTID,CURRENT.VAL,
NEXT.ID NEXTID,PREV.ID PREVID
FROM
(
SELECT T.ID, T.VAL, IF(T.VAL<>#P,#RN:=1,#RN:=#RN+1) RN, #P:=T.VAL
FROM T,(SELECT #RN:=0,#P:=0) R
ORDER BY T.VAL,T.ID
) CURRENT
LEFT JOIN
(
SELECT T.ID, T.VAL, IF(T.VAL<>#P1,#RN1:=1,#RN1:=#RN1+1) RN1, #P1:=T.VAL
FROM T,(SELECT #RN1:=0,#P1:=0) R1
ORDER BY T.VAL,T.ID
) NEXT ON NEXT.VAL = CURRENT.VAL AND NEXT.RN1 = CURRENT.RN + 1
LEFT JOIN
(
SELECT T.ID, T.VAL, IF(T.VAL<>#P2,#RN2:=1,#RN2:=#RN2+1) RN2, #P2:=T.VAL
FROM T,(SELECT #RN2:=0,#P2:=0) R2
ORDER BY T.VAL,T.ID
) PREV ON PREV.VAL = CURRENT.VAL AND PREV.RN2 = CURRENT.RN - 1
;
+-----------+-------+--------+--------+
| CURRENTID | VAL | NEXTID | PREVID |
+-----------+-------+--------+--------+
| 654 | BLUE | 659 | NULL |
| 659 | BLUE | 665 | 654 |
| 665 | BLUE | NULL | 659 |
| 656 | GREEN | NULL | NULL |
+-----------+-------+--------+--------+
4 rows in set (0.00 sec)

Advanced SQL Select and update items from the same table

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.

MySQL return alternative record if no record returned

I have a table like the following
-------------------------
| aid | tid | dft |
-------------------------
| 1 | 1 | Y |
-------------------------
| 1 | 2 | N |
-------------------------
| 2 | 3 | Y |
-------------------------
| 3 | 4 | Y |
-------------------------
| 3 | 5 | N |
-------------------------
I want to query the table to get the tid out based on aid and tid but if the tid does not exist for that aid then it should return the default tid (identified by Y in the dft column).
I have tried the following which does not throw an error but returns NULL
SELECT
IF (
t1.tid IS NOT NULL,
t1.tid,
(
SELECT
t2.tid
FROM
table t2
WHERE
t2.aid = 1
AND t2.dft = 'Y'
)
) AS tid
FROM
table t1
WHERE
t1.aid = 1
AND t1.tid = 3
As that code is looking up tid 3 with aid 1 that doesn't exist so should return tid of 1 as that is what is marked as Y in the dft column.
Can anybody help?
Try this:
SELECT tid
FROM table t1
WHERE t1.aid = 1
AND t1.tid = 3
UNION
SELECT tid
FROM table t1
WHERE t1.aid = 1
AND t1.tid <> 3
AND dft = 'Y'
If the combination of aid and tid is unique then you can use this version:
SELECT tid
FROM table t1
WHERE t1.aid = 1
AND (t1.tid = 3 OR dft = 'Y')
ORDER BY dft LIMIT 1
This would work in MSSQL, but I dont have access to a MySQL server to try it
SELECT TOP 1 *
FROM table t1
WHERE t1.aid=1
ORDER BY CASE WHEN t1.tid=3 THEN 0 ELSE 1 END, CASE WHEN t1.dft='Y' THEN 0 ELSE 1 END