UPDATE and SELECT from same table in one query - mysql

I am trying to count the rows from table1, and depending the rows count to update a certain column. Below is the query I have tried, but am getting an arror saying that temp is not a table.
UPDATE table1 AS t1
INNER JOIN table1 AS temp ON temp.id = t1.id
SET
t1.field1 = (CASE
WHEN (SELECT COUNT(*) FROM temp WHERE temp.field1 = 1) < 100 THEN 1
WHEN (SELECT COUNT(*) FROM temp WHERE temp.field1 = 2) < 100 THEN 2
WHEN (SELECT COUNT(*) FROM temp WHERE temp.field1 = 3) < 100 THEN 3
WHEN (SELECT COUNT(*) FROM temp WHERE temp.field1 = 4) < 100 THEN 4
WHEN (SELECT COUNT(*) FROM temp WHERE temp.field1 = 5) < 100 THEN 5
END)
WHERE t1.id IN(100, 200, 300); --Example data

A couple things:
I would suggest making a temp table of the data in your case
statement, then joining that for an update.
Joining back on the table you're updating does not work.
You have a syntax error in your where clause. You don't need that
equals sign before IN.
Try:
DROP TABLE IF EXISTS temp_table1;
CREATE TEMPORARY TABLE temp_table1 AS
SELECT field1,count(*) as field_count FROM table1 group by field1;
UPDATE table1 AS t1
LEFT JOIN temp_table1 aa
ON aa.field1= t1.field1
SET t1.field1 = (CASE
WHEN aa.field1 = 1 AND aa.field_count < 100 THEN 1
WHEN aa.field1 = 2 AND aa.field_count < 100 THEN 2
WHEN aa.field1 = 3 AND aa.field_count < 100 THEN 3
WHEN aa.field1 = 4 AND aa.field_count < 100 THEN 4
WHEN aa.field1 = 5 AND aa.field_count < 100 THEN 5 END)
WHERE t1.id IN (100, 200, 300);

Following query will be helpful to you,
UPDATE table1 as t1
SET
t1.field1 = (CASE
WHEN (select p.cnt from (SELECT COUNT(*) as cnt FROM table1 t2 WHERE t2.field1= 1) as p) < 100 THEN 1
WHEN (select p.cnt from (SELECT COUNT(*) as cnt FROM table1 t2 WHERE t2.field1= 2) as p) < 100 THEN 2
WHEN (select p.cnt from (SELECT COUNT(*) as cnt FROM table1 t2 WHERE t2.field1= 3) as p) < 100 THEN 3
WHEN (select p.cnt from (SELECT COUNT(*) as cnt FROM table1 t2 WHERE t2.field1= 4) as p) < 100 THEN 4
WHEN (select p.cnt from (SELECT COUNT(*) as cnt FROM table1 t2 WHERE t2.field1= 5) as p) < 100 THEN 5
END)
WHERE t1.id IN(100, 200, 300)

Related

Mysql - reorder / reset position key

I have a MySQL table with position key (65,000 records). I deleted, updated some rows in the middle of the table. Now I have, for example, something like this in the position 1 - 6 - 2 - 9
id
category
position
1
1
1
2
1
6
3
2
2
4
2
9
I want to reset / reorder the position key
id
category
position
1
1
1
2
1
2
3
2
1
4
2
2
How can I reset position where category = 1
and where category = 2?
Try this:
UPDATE source_table
JOIN ( SELECT id, ROW_NUMBER() OVER (PARTITION BY category ORDER BY position) position
FROM source_table ) subquery USING (id)
SET source_table.position = subquery.position
mysql> SHOW VARIABLES LIKE "%version%"; 5.7.24 – sagittarius
UPDATE source_table
JOIN ( SELECT t1.id, COUNT(t2.id) position
FROM source_table t1
JOIN source_table t2 ON t1.category = t2.category
AND t1.position >= t2.position
GROUP BY t1.id ) subquery USING (id)
SET source_table.position = subquery.position;
fiddle
if position is duplicated everything crashes – sagittarius
UPDATE source_table
JOIN ( SELECT t1.id, COUNT(t2.id) position
FROM source_table t1
JOIN source_table t2 ON t1.category = t2.category
AND ( t1.position > t2.position
OR ( t1.position = t2.position
AND t1.id >= t2.id ))
GROUP BY t1.id ) subquery USING (id)
SET source_table.position = subquery.position;
fiddle
UPDATE source_table t1
INNER JOIN
(
SELECT id,category,position, ROW_NUMBER() OVER (PARTITION BY category
ORDER BY position) position2
FROM source_table
) t2
ON t2.id = t1.id
SET
t1.position = t2.position2
I think this code is easy to understand and apply.

calculate difference between two rows in mysql

I have the following two tables -
Table1
TR1 TR2
1 10
2 15
3 20
Table2
TC1 TC2
10 100
15 150
20 200
select count(*) from table1, table2 where table1.tr2 = table2.tc1 and table1.tr1 > 1 and table1.tr2 in (select table2.tc1 from table2 where table2.tc1 > 10)
select count(*) from table1, table2 where table1.tr2 = table2.tc1 and table1.tr1 > 1 and table1.tr1 < 5 and table1.tr2 in (select table2.tc1 from table2 where table2.tc1 > 10)
2nd query will return a subset of the first query, I want to find the difference in count(*)s given by the two queries. How do I go about it?
You can always do
select (select count(*) ...) - (select count(*) ...);
But as your queries are so similar, you can merge the queries instead:
select
count(*) - sum(t1.tr1 < 5)
from table1 t1
join table2 t2 on t1.tr2 = t2.tc1
where t1.tr1 > 1
and t1.tr2 > 10;
I've changed your comma-separated join to a proper ANSI join. Your join syntax was made redundant in 1992. You shouldn't use it anymore.
I've replaced your IN clause with a simple t1.tr2 > 10, because you are already joining on t1.tr2 = t2.tc1.
you can do the a diff this way
select (
select count(*)
from table1, table2
where table1.tr2 = table2.tc1
and table1.tr1 > 1
and table1.tr2 in (select table2.tc1 from table2 where table2.tc1 > 10)
) - (
select count(*)
from table1, table2
where table1.tr2 = table2.tc1
and table1.tr1 > 1
and table1.tr1 < 5
and table1.tr2 in (select table2.tc1 from table2 where table2.tc1 > 10)
) as my_diff
from dual;

MySQL select 1 row from multiple rows

Please Suggest to get single 0 type row from multiple (0 type rows) and selected row should be just before type 1 row
Emp_tbl (id,type,company_id,created_at)
1,0,121,2015-02-19 18:05
2,0,121,2015-02-19 18:15
3,0,121,2015-02-19 18:17
4,1,121,2015-02-19 19:22
5,2,121,2015-02-19 19:25
6,0,121,2015-02-19 22:05
7,0,121,2015-02-19 22:15
8,0,121,2015-02-19 22:17
9,1,121,2015-02-19 22:22
10,2,121,2015-02-19 22:25
Expected Result
3,0,121,2015-02-19 18:17
4,1,121,2015-02-19 19:22
5,2,121,2015-02-19 19:25
8,0,121,2015-02-19 22:17
9,1,121,2015-02-19 22:22
10,2,121,2015-02-19 22:25
So what you want is the MAX(Id) of the type = 0 rows for each row that has type = 1, where the Id is less. You can join and group to get that:
select max(t0.Id) Id
from Emp_tbl t1
join Emp_tbl t0 on t0.type = 0 and t0.Id < t1.Id
where t1.type = 1
group by t1.Id
The rest is just putting it together:
select *
from Emp_tbl
where type <> 0
union all
select t.*
from Emp_tbl t
join (
select max(t0.Id) Id
from Emp_tbl t1
join Emp_tbl t0 on t0.type = 0 and t0.Id < t1.Id
where t1.type = 1
group by t1.Id
) t0 on t.Id = t0.Id
SQL Fiddle demo

MySQl Query to select count until you hit a specific value

I have this table e.g.:
Id StatusDate Status
1 20-08-2014
1 15-08-2014
1 09-08-2014 P
2 17-08-2014
1 10-08-2014
2 12-08-2014
2 06-07-2014 P
1 30-07-2014
2 02-07-2014
2 01-07-2014 P
...... and so on
I want to select count by ID where status is blank until I hit the first 'P' in ascending order of date group by ID. So my results will be like this.
ID Count
1 3
2 2
Try it out. Not tested
SELECT t1.ID, count(*) FROM table t1
WHERE t1.StatusDate >= (SELECT MAX(t2.StatusDate) FROM table t2
WHERE t1.ID = t2.ID AND t2.Status = 'P')
GROUP BY t1.ID
Assuming your table name is StatusTable This will work:
SELECT
ID,
COUNT(*) AS `Count`
FROM StatusTable AS st
WHERE
st.Status = ''
AND st.StatusDate > (
SELECT st2.StatusDate
FROM `StatusTable` AS st2
WHERE st.ID = st2.ID
AND st2.Status = 'P'
ORDER BY st2.StatusDate DESC
LIMIT 1
)
GROUP BY st.ID
ORDER BY st.ID
One option is to use a JOIN and COUNT rows which have a lower statusdate value, like this:
SELECT t1.id, SUM(CASE WHEN t1.statusdate > t2.statusdate THEN 1 ELSE 0 END) AS mycount
FROM t t1 JOIN (
SELECT id, MIN(statusdate) statusdate
FROM t
WHERE status = 'P'
GROUP BY id
) t2
ON t1.id = t2.id
GROUP BY t1.id
Working Demo: http://sqlfiddle.com/#!2/d9d91/2

using a LEFT OUTER JOIN on something COALESCED

I have this table where I only want to look at AB
ID CODE COUNT
102 AB 9
101 AB 8
100 AC 23 //not important!!!!
99 AB 7
98 AB 6
97 AB 5
96 AB 0
Conversed to this
ID NEWID CODE COUNT
102 102 AB 9
101 101 AB 8
99 100 AB 7
98 99 AB 6
97 98 AB 5
96 97 AB 0
Using this query:
SELECT t.ID, #NEWID := COALESCE(#NEWID - 1, t.ID) AS NEWID, t.CODE, t.COUNT
FROM
(SELECT ID, CODE, COUNT FROM some_table WHERE CODE = 'AB' ORDER BY ID DESC) t,
(SELECT #NEWID := NULL) _uv;
http://sqlfiddle.com/#!2/e0b8b/1/0
And now I want to count the difference of each consecutive NEWID.
So
Step 1: 9 - 8 = 1
Step 2: 8 - 7 = 1
Step 3: 7 - 6 = 1
Step 4: 6 - 5 = 1
Step 5: 5 - 0 = 5
I'm used to doing this with
LEFT OUTER JOIN some_table t2 ON t.ID = ( t2.ID + 1 )
And then taking the difference between t2.count and t.count,
but now when I'm using COALESCE, I cannot select this NEWID, so the code below does not work.
LEFT OUTER JOIN some_table t2 ON t.NEWID = ( t2.NEWID + 1 )
So how should I resolve this issue?
Oh, so that's why you needed sequential IDs. Well, you can use user variables for this, too, and you don't even need NEWID! Since you're doing stuff like this, you'd do well to read up on how user variables work.
SELECT
t.ID, t.CODE, t.COUNT,
#PREVCOUNT - t.COUNT DIFFERENCE,
#PREVCOUNT := t.COUNT -- Updates for the next iteration, so it
-- must come last!
FROM
(SELECT ID, CODE, COUNT FROM some_table WHERE CODE = 'AB' ORDER BY ID DESC) t,
(SELECT #PREVCOUNT := NULL) _uv;
SQL Fiddle
Try this:
SELECT
t1.ID as ID1,
t2.ID as ID2,
t1.CODE as CODE,
t1.COUNT as C1,
t2.COUNT as C2,
t2.COUNT - t1.COUNT as DIFF
FROM
some_table t1
INNER JOIN some_table t2 ON t1.ID < t2.ID AND t1.CODE = t2.CODE
WHERE
t1.CODE='AB'
AND NOT EXISTS
(SELECT * FROM some_table t3
INNER JOIN some_table t4 ON t3.ID < t4.ID and t3.CODE = t4.CODE
WHERE
t3.CODE='AB'
AND t1.ID = t3.ID
AND t4.ID < t2.ID
)
ORDER BY t1.ID
Another way will be to use LIMIT:
SELECT
t.ID1 AS ID,
t.CODE as CODE,
t.C2-t.C1 AS DIFF
FROM
(
SELECT
t1.ID as ID1,
t1.CODE as CODE,
t1.COUNT as C1,
(SELECT t.COUNT
FROM some_table t
WHERE t.ID > t1.ID AND t.CODE=t1.CODE
ORDER BY t.ID
LIMIT 1) as C2
FROM
some_table t1
WHERE
t1.CODE='AB'
ORDER BY t1.ID) t
ORDER BY t.ID1
http://sqlfiddle.com/#!2/e0b8b/24