How can i order when update multi row in Zend ?
For example, when I updated my table as follows :
SET #pos = 0 ;
UPDATE table SET sort = ( SELECT #pos := #pos + 1 ) where status = 1 ORDER BY id ASC;
Related
I would write my cmd line statements more sophistically. How can this be done by using a loop?
update refs set custom_7 = '';
update refs set custom_7='1' where custom_7 = '' limit 220 ;
update refs set custom_7='2' where custom_7 = '' limit 220 ;
update refs set custom_7='3' where custom_7 = '' limit 220 ;
...
update refs set custom_7='100' where custom_7 = '' limit 220 ;
thanks a lot.
If there is a column, like an id, that defines the order of the rows by which you want to update the rows, use ROW_NUMBER() window function to rank the rows and join to the table:
WITH cte AS (SELECT *, ROW_NUMBER() OVER (ORDER BY id) rn FROM refs)
UPDATE refs r
INNER JOIN cte c ON c.id = r.id
SET r.custom_7 = (c.rn - 1) DIV 220 + 1
WHERE c.rn <= 100 * 220; -- remove the WHERE clause if there is actually no limit to the values of custom_7
If there is no column like the id, you may remove ORDER BY id from the OVER() clause of ROW_NUMBER(), but then the rows will be updated arbitrarily.
See a simplified demo.
You can try something like this (please replace datatype(length) with the type of custom7)
DECLARE #count INT;
SET #count = 1;
WHILE #count<= 100
BEGIN
UPDATE refs SET custom_7 = CAST(#count AS **datatype(length)**) WHERE custom_7 = '' LIMIT 220;
SET #count = #count + 1;
END;
I have a routine. But it' s too slow. How can I improve the query?
My records: http://www.sqlfiddle.com/#!9/14cceb/1/0
My query:
CREATE DEFINER = 'root'#'localhost'
PROCEDURE example.ssa()
BEGIN
drop table if exists gps_table;
drop table if exists exam_datas;
CREATE TEMPORARY TABLE gps_table(ID int PRIMARY KEY AUTO_INCREMENT,timei
int,
trun_date_time datetime, tadd_meter int, tin_here int null);
insert into gps_table(timei,trun_date_time,tadd_meter,tin_here) select
imei, run_date_time, add_meter, in_here from example_table;
CREATE TEMPORARY TABLE exam_datas(ID int PRIMARY KEY AUTO_INCREMENT,vimei
int, vbas_run_date_time datetime, vbit_run_date_time datetime, vdifff int);
select tin_here from gps_table limit 1 into #onceki_durum;
select count(id) from gps_table into #kayit_sayisi;
set #i = 1;
set #min_mes = 0;
set #max_mes = 0;
set #frst_id = 0;
set #imei = 0;
set #run_date_time = '0000-00-00 00:00:00';
set #run_date_time2 = '0000-00-00 00:00:00';
myloop: WHILE (#i <= #kayit_sayisi) DO
select tin_here from gps_table where id = #i into #in_here_true;
if (#in_here_true = 1) then
select id,trun_date_time, tadd_meter from gps_table where id = #i into #frst_id,#run_date_time2, #min_mes;
select id from gps_table where id > #frst_id and tin_here =0 order by id asc limit 1 INTO #id;
SET #id = #id-1;
select id, timei, trun_date_time, tadd_meter from gps_table
where id = #id and tin_here =1 limit 1 into #i, #imei, #run_date_time, #max_mes;
if(#i-#frst_id>3) then
set #i:=#i+1;
insert into exam_datas(vimei,vbas_run_date_time,vbit_run_date_time,vdifff) Values (#imei, #run_date_time2, #run_date_time, #max_mes-#min_mes);
SELECT * FROM exam_datas;
SET #asd =1;
elseif 1=1 then
set #i:=#i+1;
End if;
ELSEIF 1=1
THEN SET #i:=#i+1;
End if;
IF (#i = #kayit_sayisi)
THEN set #tamam =1; LEAVE myloop;
END IF;
END WHILE myloop;
select DISTINCT * from exam_datas;
drop table if exists exam_datas;
drop table if exists gps_table;
END
I need: id= 6 first true and id= 11 last_true
firs_trure - last_true = 304-290= 14
id=14 first true and id=18 last_true
firs_true - last_true = 332-324= 8
This routine is too slow.
MySql version is 5.7 and There are 2 milions record in the table.
UPDATE:
Query is here. HERE
Thank you #LukStorms
It's possible to get such results in 1 query.
Thus avoiding a WHILE loop over records.
This example works without using window functions. Just using variables inside the query to calculate a rank. Which is then used to get the minimums and maximums of the groups.
select
imei,
min(run_date_time) as start_dt,
max(run_date_time) as stop_dt,
max(add_meter) - min(add_meter) as diff
from
(
select imei, id, run_date_time, add_meter, in_here,
case
when #prev_imei = imei and #prev_ih = in_here then #rnk
when #rnk := #rnk + 1 then #rnk
end as rnk,
#prev_imei := imei as prev_imei,
#prev_ih := in_here as prev_ih
from example_table t
cross join (select #rnk := 0, #prev_ih := null, #prev_imei := null) vars
order by imei, id, run_date_time
) q
where in_here = 1
group by imei, rnk
having count(*) > 4
order by imei, min(id);
In the procedure such query can be used to fill that final temporary table.
A test on db<>fiddle here
I have the query working, just wondering if there is a better way to do this without cursors/loops/php side. I've been a DBA for 5+ years and just came across the := statement. Very cool.
Table (tblPeople) with the person ID and the number of tickets they bought.
PersonId NumTickets
1 3
2 1
3 1
I then want to assign individual tickets to each person in a new table (tblTickets), depending on how many tickets they bought. The TicketId is a key, auto increment column.
TicketId PersonId
100 1
101 1
102 1
103 2
104 3
Here is the code. It loops through the whole tblPeople over and over again incrementing a new calculated column called rowID. Then I filter out the rows based on the number of tickets they bought in the WHERE clause. The problem I see is the subquery is huge, the more people I have, the bigger the subquery gets. Just not sure if there is a better way to write this.
INSERT INTO tblTickets (PersonId)
SELECT PersonId
FROM (
SELECT s.PersonId, s.NumTickets,
#rowID := IF(#lastPersonId = s.PersonId and #lastNumTickets = s.NumTickets, #rowID + 1, 0) AS rowID,
#lastPersonId := s.PersonId,
#lastNumTickets := s.NumTickets
FROM tblPeople m,
(SELECT #rowID := 0, #lastPersonId := 0, #lastNumTickets := 0) t
INNER JOIN tblPeople s
) tbl
WHERE rowID < NumTickets
I'd add a utility table Numbers which contains all the numbers from 1 up to the maximal number of tickets a person may buy. Then you can do something like this:
INSERT INTO tblTickets (PersonId)
SELECT s.PersonId
FROM tblPeople s, Numbers n
WHERE n.number <= s.NumTickets
Following Stored procedure will serve your purpose...
DELIMITER $$
USE <your database name> $$
DROP PROCEDURE IF EXISTS `update_ticket_value2`$$
CREATE PROCEDURE `update_ticket_value2`()
BEGIN
DECLARE index_value INT;
DECLARE loop_variable INT;
SET #KeyValue = 100;
SET #LastPersonID = 0;
SET #TicketNum = 0;
SET #PersonIDToHandle = 0;
SELECT #PersonIDToHandle = PersonID, #TicketNum = NumTickets
FROM tblPeople
WHERE PersonId > #LastPersonID
ORDER BY PersonId
LIMIT 0,1;
WHILE #PersonIDToHandle IS NOT NULL
DO
SET loop_variable = 0;
WHILE(loop_variable < #TicketNum) DO
INSERT INTO tblTickets(TicketId, PersonId) VALUES(#KeyValue + loop_variable, #PersonIDToHandle);
SET loop_variable = loop_variable + 1;
END WHILE;
SET #LastPersonID = #PersonIDToHandle;
SET #PersonIDToHandle = NULL;
SET #KeyValue = #KeyValue + #TicketNum;
SELECT #PersonIDToHandle := PersonID, #TicketNum := NumTickets
FROM tblPeople
WHERE PersonId > #LastPersonID
ORDER BY PersonId
LIMIT 0,1;
END WHILE;
END$$
DELIMITER ;
Call the procedure as:
CALL update_ticket_value2();
Hope it helps...
Lets say I have these columns
uniqueID|Money|Quantity|MoneyOrder|QuantityOrder
1|23|12||
2|11|9||
3|99|100||
What I want to do is update MoneyOrder and QuantityOrder based on the value of ORDER BY.
So the results would be:
uniqueID|Money|Quantity|MoneyOrder|QuantityOrder
1|23|12|2|1
2|11|90|1|2
3|99|100|3|3
I want the update to operate like an identity column without actually making it an identity column. I know that I could just order by 'x' and the order would be the result but I want to generate a report where you can see the item line by line.
Is something like this possible update mytable set Moneyorder = 'imnotsure' order by MoneyOrder asc ?
SET #rownumber = 0;
update mytable set Moneyorder = (#rownumber:=#rownumber+1)
order by MoneyOrder asc
or to do it in a single query you can try
update mytable target
join
(
select id, (#rownumber := #rownumber + 1) as rownum
from mytable
cross join (select #rownumber := 0) r
order by MoneyOrder asc
) source on target.id = source.id
set Moneyorder = rownum
See answers to this question:
Updating column so that it contains the row position
SET #counter = 0;
UPDATE
my_table
SET MoneyOrder = #counter := #counter + 1
ORDER BY Money;
SET #counter = 0;
UPDATE
my_table
SET QuantityOrder = #counter := #counter + 1
ORDER BY Quantity;
I have a table which has columns UserID,DIFFTIME. when I select these columns from the table, I also want to have a derived column which is : If the DiffTime is > 20 I want to increment the count per user id.
For example if the table has:
User ID DIFF TIME
1 0
1 5
1 10
2 0
2 21
2 5
I want a result set that is something like this:
User ID DIFF TIME SESSION NUMBER
1 0 1
1 5 1
1 10 1
2 0 1
2 21 2
2 5 2
How do I accomplish this.
Ideas and suggestions are much appreciated!
Use this statement:
select t1.User_Id, t1.Diff_Time,
isnull(count(t2.User_Id), 0) + 1 as Session_Number
from #table t1
left join #table t2
on t1.User_Id = t2.User_Id
and t1.eventTime >= t2.eventTime
and t2.Diff_Time > 20
group by t1.User_Id, t1.Diff_Time, t1.eventTime
order by t1.User_Id, t1.eventTime
(replace #table with your actual table name)
Note: I assume that the fifth row of your table has the value 21 in the Diff_Time column, and there's a typo in the question, as #AaronBertrand pointed out in the comments
create table #t
(
id int,
Diff int,
SessionNumber int
)
insert into #t(id, diff)values(1, 0)
insert into #t(id, diff)values(1, 5)
insert into #t(id, diff)values(1, 10)
insert into #t(id, diff)values(2, 0)
insert into #t(id, diff)values(2, 21)
insert into #t(id, diff)values(2, 5)
Select ROW_NUMBER() over(order by Id) as RowID, * into #Temp1 from #t
Declare #diff int
Declare #RowId int
Declare #Previous int
Declare #NewValue int
DECLARE #Cur CURSOR SET #Cur = CURSOR FOR select RowId, diff from #Temp1
OPEN #Cur
FETCH NEXT FROM #Cur INTO #RowId, #diff
WHILE ##FETCH_STATUS = 0
BEGIN
if(#RowId = 1)
Begin
Update #Temp1 Set SessionNumber = 1 Where rowid = 1
Set #Previous = #Diff
Set #NewValue = 1
End
Else
Begin
if(#Diff - #Previous > 20)
Begin
Set #Previous = #Diff
Set #NewValue = #NewValue + 1
Update #Temp1 Set SessionNumber = #NewValue Where rowid = #RowId
End
else
Update #Temp1 Set SessionNumber = #NewValue Where rowid = #RowId
End
FETCH NEXT FROM #Cur INTO #RowId, #diff
END
CLOSE #Cur
DEALLOCATE #Cur
select * from #temp1
drop table #t
drop table #temp1