I currently have a table that has a parent_id field for multiple entries, ie the same ID number for 4 entries (as per the screenshot below). I would like to convert the parent_id to run from 9000 upwards, so in the screenshot 000004 would become 9000 in 4 entries, 000007 would become 9001 in 4 entries and so on (as shown in the example outcome). Does anyone know of an easy way to implement this please as I'd rather not have to manually change 2224 entries!?
Thanks in advance guys!
Table screenshot:
Example outcome:
You seem to want an update. If so:
update t join
(select t.*, row_number() over (order by id) as seqnum
from t
) tt
on t.id = tt.id
set t.parent_id = 9000 + floor( (seqnum - 1) / 4);
Note that this ignores the current parent_id, assigning the same value to groups of 4 rows based on the id.
EDIT:
In older versions of MySQL:
update t join
(select t.*, (#rn := #rn + 1) as seqnum
from (select t.* from t order by id) t cross join
(select #rn := 0) params
) tt
on t.id = tt.id
set t.parent_id = 9000 + floor( (seqnum - 1) / 4);
If you are runnig MySQL 8.0, you can use dense_rank() for this:
select
t.*,
8999 + dense_rank() over(order by parent_id) new_parent_id
from mytable t
On earlier versions, one (less efficient) option uses a correlated subquery:
select
t.*,
9000 + (select count(distinct t1.parent_i) from mytable t1 where t1.parent_id < t.parent_id) new_parent_id
from mytable t
Related
I'm trying to generate a random sample of half of a table (or some other percentage). The table is small enough that I can use the ORDER BY RAND() LIMIT x approach. I'd like the code to sample 50% of recipients as the table changes size over time. Below was my first attempt but you can't put a subquery in a LIMIT clause. Any ideas?
SELECT
recipient_id
FROM
recipient
ORDER BY RAND()
LIMIT (
/* Find out how many recipients are on half the list */
SELECT
COUNT(*) / 2
FROM
recipient
);
If you are running MysQL 8.0, you can use window functions:
select *
from (select t.*, ntile(2) over(order by random()) nt from mytable t) t
where nt = 1
In earlier versions, one approach uses user variables:
select t.*
from (
select t.*, #rn := #rn + 1 rn
from (select * from mytable order by random()) t
cross join (select #rn := 0) x
) t
inner join (select count(*) cnt from mytable) c on t.rn <= c.cnt / 2
I have a table in MySQL (phpMYAdmin) with the following columns
I am trying to determine the percentile for each row and update that value in the G1Ptile column. G1Ptile column is the percentile calculation based on G1%. I am using the following based on John Woo's answer given here
SELECT `G1%`,
(1-ranks/totals)*100 Percentile FROM (
SELECT distinct `G1%`,
#rank:=#rank + 1 ranks,
(SELECT COUNT(*) FROM PCount) totals
FROM PCount a,
(SELECT #rank:=0) s
ORDER BY `G1%` DESC ) s;
and get the following output
The output is in a select statement, I want to be able to update it to the G1Ptile column in my table, however I am unable to update it using
UPDATE `PCount` SET `G1Ptile`= --(All of the select query mentioned above)
Can you please help with modifying the query/suggest an alternative so that I can use the percentile values obtained using the above query and update it into G1Ptile in the same table. One more problem I have is that there are two 20% values in G1%, however the percentile assigned to one is 20 and other is 30. I want both of them to be 20 and the next row in the series to be 30.
I would write your calculation as:
SELECT `G1%`,
(1 - ranks / totals) * 100 as Percentile
FROM (SELECT `G1%`,
(#rank := #rank + 1) ranks,
(SELECT COUNT(*) FROM PCount) as totals
FROM (SELECT DISTINCT `G1%`
FROM PCount
ORDER BY `G1%` DESC
) p CROSS JOIN
(SELECT COUNT(*) as totals, #rank := 0
FROM Pcount
) params
) p;
I made certain changes more consistent with how MySQL processes variables. In particular, the SELECT DISTINCT and ORDER BY are in a subquery. This is necessary in more recent versions of MySQL (although in the most recent you can use window functions).
This can now be incorporated into an update using JOIN:
UPDATE PCount p JOIN
(SELECT `G1%`,
(1 - ranks / totals) * 100 as Percentile
FROM (SELECT `G1%`,
(#rank := #rank + 1) ranks,
(SELECT COUNT(*) FROM PCount) as totals
FROM (SELECT DISTINCT `G1%`
FROM PCount
ORDER BY `G1%` DESC
) p CROSS JOIN
(SELECT COUNT(*) as totals, #rank := 0
FROM Pcount
) params
) pp
) pp
ON pp.`G1%` = p.`G1%`
SET p.G1Ptile = pp.percentile;
I already googled but couldn't find a solution.
I have two columns called order_id and name. I want to ORDER BY name and then SET ascending order_id.
Like this:
order_id name
1 Arya
2 Herbert
3 Paul
4 Peter
5 Tiffany
My id column is int(4) and by default value is 0. It's not PRIMARY or UNIQUE. (It'a also not the main id. Main id is of course PRIMARY.
How can I do this with SQL?
You could use ROW_NUMBER(MySQL 8.0+):
SELECT name, ROW_NUMBER() OVER(ORDER BY name) AS rn
FROM tab
ORDER BY rn;
Update:
UPDATE tab
SET order_id = (SELECT rn FROM (SELECT name,ROW_NUMBER() OVER(ORDER BY name) AS rn
FROM tab)s
WHERE s.name = tab.name); -- assuming that name is UNIQUE
DBFidde Demo
For versions < 8.0 you can use this:
select #rn := 0;
UPDATE tbl T1
JOIN (select #rn := #rn + 1 rn, `name` from tbl order by `name`) T2
ON T1.`name` = T2.`name`
SET T1.order_id = T2.rn
Demo
Useful article related to your problem: MySQL UPDATE JOIN
As your mysql version is below 8.0 so you have to manually generate orderid
below can help you
select t.*,
#rownum := #rownum + 1 AS order_id from
(
select * from
tab o order by name asc
) as t , (SELECT #rownum := 0) r
http://www.sqlfiddle.com/#!9/ae3fda/3
Is it possible to get specific row in query using like SUM?
Example:
id tickets
1 10 1-10 10=10
2 35 11-45 10+35=45
3 45 46-90 10+35+45=90
4 110 91-200 10+35+45+110=200
Total: 200 tickets(In SUM), I need to get row ID who have ticket with number like 23(Output would be ID: 2, because ID: 2 contains 11-45tickets in SUM)
You can do it by defining a local variable into your select query (in form clause), e.g.:
select id, #total := #total + tickets as seats
from test, (select #total := 0) t
Here is the SQL Fiddle.
You seem to want the row where "23" fits in. I think this does the trick:
select t.*
from (select t.*, (#total := #total + tickets) as running_total
from t cross join
(select #total := 0) params
order by id
) t
where 23 > running_total - tickets and 23 <= running_total;
SELECT
d.id
,d.tickets
,CONCAT(
TRIM(CAST(d.RunningTotal - d.tickets + 1 AS CHAR(10)))
,'-'
,TRIM(CAST(d.RunningTotal AS CHAR(10)))
) as TicketRange
,d.RunningTotal
FROM
(
SELECT
id
,tickets
,#total := #total + tickets as RunningTotal
FROM
test
CROSS JOIN (select #total := 0) var
ORDER BY
id
) d
This is similar to Darshan's answer but there are a few key differences:
You shouldn't use implicit join syntax, explicit join has more functionality in the long run and has been a standard for more than 20 years
ORDER BY will make a huge difference on your running total when calculated with a variable! if you change the order it will calculate differently so you need to consider how you want to do the running total, by date? by id? by??? and make sure you put it in the query.
finally I actually calculated the range as well.
And here is how you can do it without using variables:
SELECT
d.id
,d.tickets
,CONCAT(
TRIM(d.LowRange)
,'-'
,TRIM(
CAST(RunningTotal AS CHAR(10))
)
) as TicketRange
,d.RunningTotal
FROM
(
SELECT
t.id
,t.tickets
,CAST(COALESCE(SUM(t2.tickets),0) + 1 AS CHAR(10)) as LowRange
,t.tickets + COALESCE(SUM(t2.tickets),0) as RunningTotal
FROM
test t
LEFT JOIN test t2
ON t.id > t2. id
GROUP BY
t.id
,t.tickets
) d
I have the table with data:
And for this table I need to create pegination by productId column. I know about LIMIT N,M, but it works with rows and not with groups. For examle for my table with pegination = 2 I expect to retrieve all 9 records with productId = 1 and 2 (the number of groups is 2).
So how to create pegination by numbers of groups ?
I will be very thankfull for answers with example.
One way to do pagination by groups is to assign a product sequence to the query. Using variables, this requires a subquery:
select t.*
from (select t.*,
(#rn := if(#p = productid, #rn + 1,
if(#rn := productid, 1, 1)
)
) as rn
from table t cross join
(select #rn := 0, #p := -1) vars
order by t.productid
) t
where rn between X and Y;
With an index on t(productid), you can also do this with a subquery. The condition can then go in a having clause:
select t.*,
(select count(distinct productid)
from t t2
where t2.productid <= t.productid)
) as pno
from t
having pno between X and Y;
Try this:
select * from
(select * from <your table> where <your condition> group by <with your group>)
LIMIT number;