How to update the same row with condition in MySql? - mysql

Here's data
KeyID | Queue | Pay
65 1 0
60 2 0
58 3 1
57 4 1
55 5 0
54 6 0
53 7 1
50 8 1
if the data like this , I need a single MySql query to update it to be like below data table which update only Queue column.
KeyID | Queue | Pay
65 0 0
60 0 0
58 1 1
57 2 1
55 0 0
54 0 0
53 3 1
50 4 1
I have try this
update tabl1
set Queue = case when Pay = 0 then Queue=Queue-1 else Queue
But Queue number not look like this.
Please suggest.
Thank you in advance

We can try joining to a subquery which computes the sequence:
UPDATE yourTable k1
INNER JOIN
(
SELECT KeyID, rn
FROM
(
SELECT t1.KeyID,
(SELECT SUM(t2.Pay = 1) FROM yourTable t2
WHERE t2.KeyID >= t1.KeyID) rn
FROM yourTable t1
) t
) k2
ON k1.KeyID = k2.KeyID
SET
Queue = CASE WHEN Pay = 0 THEN 0 ELSE k2.rn END;
To see how the above logic is working, here is what the intermediate join table looks like:
KeyID | Queue | Pay | rn
65 | 1 | 0 | 0
60 | 2 | 0 | 0
58 | 3 | 1 | 1
57 | 4 | 1 | 2
55 | 5 | 0 | 2
54 | 6 | 0 | 2
53 | 7 | 1 | 3
50 | 8 | 1 | 4
That is, the innermost correlated subquery generates the queue sequence by counting the number of times Pay is 1.
Note that if you are using MySQL 8+, then there is a much simpler query using analytic functions:
UPDATE yourTable
SET Queue = CASE WHEN Pay = 0
THEN 0
ELSE SUM(Pay = 1) OVER (ORDER BY KeyID DESC) END;

Related

Sorting issue with limit and offset MYSQL

I am facing sorting issue in mysql
See the output of below query:
select astrologers.id,astrologers.name,chat_online,online,experience from `astrologers`
where `astrologers`.`status` = '1'
order by experience asc limit 10;
id
name
chat_online
online
experience
15
Astro Anoop
0
0
3
20
Test Astro2
0
0
3
3
Test anoop
0
0
5
4
Anoop Kumar trivedi
0
0
5
7
Test
0
0
5
58
Neeraj yadav
1
0
5
45
Satish Kumar Gupta
1
1
10
56
AP Sharma
1
0
15
40
VG Astrologer App
1
0
55
In above result id 58 (Neeraj yadav) is at 6th position but when I run the same query with limit 3, same id 58 (Neeraj yadav) is at 3rd position:
select astrologers.id,astrologers.name,chat_online,online,experience
from `astrologers`
where `astrologers`.`status` = '1'
order by experience asc limit 3;
id
name
chat_online
online
experience
20
Test Astro2
0
0
3
15
Astro Anoop
0
0
3
58
Neeraj yadav
1
0
5
The 3rd row in above result should be id 3 (Test anoop) but it gives id 58 (Neeraj yadav)
Is this bug in mysql?
Is this a bug in MySQL?
No. The problem is that your sort is not deterministic, and gives ties in the third position:
| 3 | Test anoop | 0 | 0 | 5 |
| 4 | Anoop Kumar trivedi | 0 | 0 | 5 |
| 7 | Test | 0 | 0 | 5 |
| 58 | Neeraj yadav | 1 | 0 | 5 |
All 4 users have the same experience, hence leaving the database to figure out how they should be sorted.
When asked to return to top 3 rows, the database picks the first two, and then one of the 4 ties. The result that you get might not be consistent over consequent executions of the same query, as you are starting to see.
Bottom line: know you data; if you want a deterministic result, then use a deterministic sort. We could, for example, use id to break the ties, hence making the result predictable:
order by experience, id limit 3

how to select the row where sum reach 1000?

id | amount
1 | 96
2 | 0.63
3 | 351.03
4 | 736
5 | 53
6 | 39
7 | 105
8 | 91
I want to get the row where sum(amount) reach 1000
please note only the row that trigger 1000
This query should do what (I think) you want:
select id, (select sum(amount)
from table1 t1
where t1.id <= table1.id) as total
from table1
having total >= 1000
limit 1
For your sample table, it gives
id total
4 1183.66

MySQL - Select rows whose timestamp is within a set time of another row

I have a table of events with timestamps, and types (1 or 0). Im looking to select all the type 0 rows where a type 1 row has a timestamp within 10 (or whatever) seconds.
event_id | type | timestamp
1 | 0 | 2012-1-1 00:00:00
2 | 0 | 2012-1-1 00:00:01
3 | 1 | 2012-1-1 00:00:09
4 | 1 | 2012-1-1 00:00:10
5 | 0 | 2012-1-1 00:00:14
6 | 0 | 2012-1-1 00:00:20
7 | 1 | 2012-1-1 00:00:25
8 | 0 | 2012-1-1 00:00:40
9 | 0 | 2012-1-1 00:00:50
10 | 1 | 2012-1-1 00:01:00
So in this example it would grab rows 1,2, and 6
I know how to do it if I run a new query for each type 0 event, but obviously that can be incredibly slow once the table becomes thousands of rows.
As you suggested, doing this query for each row would be inefficient. However, a JOIN seems to fit your need nicely:
SELECT ones.*
FROM my_table ones
JOIN my_table zeroes
ON zeroes.type = 0 AND
TIME_TO_SEC(TIMEDIFF(ones.timestamp, zeroes.timestamp)) <= 10
WHERE ones.type = 1
SQLFiddle demo
select distinct t1.* from t as t1
JOIN t as t2 on (t2.type=1) and
(t2.timestamp between t1.timestamp
AND t1.timestamp + INTERVAL 10 SECOND
)
where t1.type=0

Mysql Between Clause inside Case when statement and count number of items in column

Here i am trying to get the count of products by using case when in mysql .
My sample data is
ID | Proname | led | lcd | hd | fullhd | 3d | displaysize (inches) | brandID
1 tv1 1 0 0 1 0 22 3
2 tv2 0 1 1 0 0 26 3
3 tv3 1 0 1 0 0 32 3
4 tv4 1 0 0 1 1 55 3
5 tv5 1 0 0 1 0 42 3
Now my expected out put
lcdcnt | ledcnt | hdcnt | fullhdcnt | 3dcnt | dispcntlessthan32 | displaycntbetwwen32and42 | displaycntabove42
1 4 2 3 1
Here is my Query . but i am not getting the correct output as i expected
select
sum(lcdtv) lcdcnt,
sum(ledtv) ledcnt,
sum(3dtv) 3dcnt,
sum(plasmatv) plasmacnt,
sum(smarttv) smatcnt,
sum(hdtv) hdnt,
sum(fullhdtv) fullhdcnt,
sum(ultrahdtv) ultrahdcnt,
sum(4ktv) 4kcnt,
sum(8ktv) 8kcnt,
sum(oledtv) oledcnt,
case
when (displayinches between 1 and 32) then count(displayinches)
end as dispcntlessthan32
case
when (displayinches between 32 and 42) then count(displayinches)
end as displaycntbetwwen32and42
from
tv
where
brandID = 3 and (ledtv = 1) and price != 0
Here is the SQLFiddel Demo
Below is the Approach :
select
sum(lcd) lcdcnt,
sum(led) ledcnt,
sum(3d) 3dcnt,
sum(hd) hdnt,
sum(fullhd) fullhdcnt,
sum(3d) 3dcnt,
sum(case when displaysize between 1 and 32 then 1 else 0 end) as dispcntlessthan32,
sum(case when displaysize between 33 and 42 then 1 else 0 end) as displaycntbetween32and42
from table1
where brandID = 3

How to select all records where a field is of a certain value until a record shows up that has a different value?

Let's say that we have a table with COLUMN1 and COLUMN 2. Here's a sample of the records:
COLUMN 1 | COLUMN 2
124 | 12
124 | 11
124 | 10
124 | 9
26 | 8
65 | 7
65 | 6
65 | 5
65 | 4
23 | 3
124 | 2
124 | 1
124 | 0
There is absolutely no pattern to this, but what I'd like to do is get:
COUNT(*) | COLUMN 1 | Smallest Column 2
4 | 124 | 9
1 | 26 | 8
4 | 65 | 4
1 | 23 | 3
3 | 124 | 0
So far, I've been doing this with PHP, but I'd like to find a way to do this in MySQL, as I'm sure it'd be a lot more efficient. The problem is, I can't even think of where to start with this. A regular GROUP BY COLUMN 1 wouldn't work because I want two results for 124, since it appears in two different instances. I've been fiddling around for hours and looking into the documentation and Google, but I haven't been able to find anything yet, and I was wondering if any of you would be able to point me in the right direction. Is this even possible with MySQL?
Well, it took a bit of fiddling, but here it is!
This assumes you have an id column in your table that you order by to get a consistent ordering (if you don't have an id column, order by timestamp or whatever in the inner query).
set #prev := '', #low := 0, #cnt := 0, #grp :=0;
select cnt, column1, low
from (
select
column2,
#low := if(#prev = column1, least(column2, #low), column2) low,
#cnt := if(#prev = column1, #cnt + 1, 1) cnt,
#grp := if(#prev = column1, #grp, #grp + 1) grp,
#prev := column1 column1
from (select column1, column2 from so9091342 order by id) x
order by grp, cnt desc) y
group by grp;
Here's the sql needed to set up a table for testing:
create table so9091342 (id int primary key auto_increment, column1 int, column2 int);
insert into so9091342 (column1, column2) values (124,12),(124,11),(124,10),(124,9),(26,8),(65,7),(65,6),(65,5),(65,4),(23,3),(124,2),(124,1),(124,0);
Output of above query:
+------+---------+------+
| cnt | column1 | low |
+------+---------+------+
| 4 | 124 | 9 |
| 1 | 26 | 8 |
| 4 | 65 | 4 |
| 1 | 23 | 3 |
| 3 | 124 | 0 |
+------+---------+------+
p.s. I named the table so9091342 because this is SO question ID #9091342.
Interesting question. I know Oracle much better than MySQL so I was able to get it working in Oracle. Might be a better way but this is what I came up with.
select count(col1) as cnt, col1, min(col2) as smallestCol2
from (
select col1, col2, col2-rnk as rnk
from
(
select col1, col2, RANK() OVER (PARTITION by col1 order by col2 asc) as rnk
from tmp_tbl
)
)
group by col1,rnk
order by min(col2) desc
I'm not quite sure how rank and partition work in MySQL but this might be helpful:
Rank function in MySQL
EDIT: To clarify what is going on in my query:
The inner query assigns a unique counter (RNK) to each value in column 1. The result of the most inner query is:
COL1 COL2 RNK
23 3 1
26 8 1
65 4 1
65 5 2
65 6 3
65 7 4
124 0 1
124 1 2
124 2 3
124 9 4
124 10 5
124 11 6
124 12 7
By subtracting the rank from column 2, you can get a unique value for each grouping of column 1 values. The result of the second nested query is:
COL1 COL2 RNK
23 3 2
26 8 7
65 4 3
65 5 3
65 6 3
65 7 3
124 0 -1
124 1 -1
124 2 -1
124 9 5
124 10 5
124 11 5
124 12 5
Then you can group on column 1 and that unique value. The final result:
CNT COL1 SMALLESTCOL2
4 124 9
1 26 8
4 65 4
1 23 3
3 124 0