MySQL counter for specific situations - mysql

I need to generate unique "ids", the catch is, it can be only between 1 - 99999.
The "good" thing is, that it has to be unique only in group with another column.
We have groups, each group has its own "group_id" and each group need something like unique('group_id', 'increment_id')
The 99999 records is enough for several years for each group right now, but it is not enough for all groups together, therefore I cant just create table with AUTO_INCREMENT and inserting there records and taking its auto increment.
For example, if I need 5 records for Group one and three records for Group two, I suppose to get something like this:
group_id, increment_id
1, 1,
1, 2,
1, 3,
1, 4,
1, 5,
2, 1
2, 2,
2, 3
Also, the conflict is not an option, therefore using something like "length" can be tricky, if done programatically (there can be i.e. 10 requests at once, each of them first select length for given group_id and then tries to create 10 rows with same increment_id)
However I am thinking - if I set it up as the value of subselect of count, than it will always be "ok"?

You can create a auxiliar table named counters to manage that:
table: counters
columns: group_id, current_counter
OR
Each time you insert a row increment_id = select max(increment_id)+1 from table_xxx where group_id = group_xxxx

You can use user variables to get the incrementing number within each group_id:
select
t.*,
#rn := if(#group_id = group_id,
#rn + 1,
if(#group_id := group_id, 1, 1)
) increment_id
from (
select group_id
from your_table t
/* some where clauses */
order by group_id
) t
cross join (
select #rn := 0,
#group_id := - 1
) t2

Related

Loop through results of sql query

I have a table with 50 records.
In that table, I just added a column name Number (int). For each of those 50 records the current value is (NULL).
How can I make a simple query ( LOOP ) which will go through all those records (rows) and for each set the row number example (1, 2, 3, 4, 5)
You can use variables with update. If you don't care about the ordering:
update t cross join
(select #rn := 0) params
t.number = (#rn := #tn + 1);
Alternatively, you could create a new table with an auto-increment column and load the data into that table. That way, new records will also be assigned new numbers.

How to add IDs to each unique value in a table

I have a table in mysql which has a column filled with text values, lets say pets. So I would have a column pets with values like: "cat", "dog", "turtle", "cat", "cat", "turtle". In reality there are hundreds of thousands of different pet types in that column, but many repeats.
What I would like to do is create a second column which has an index for each entry in the first column. So for instance, in the above case, we would assign 'cat' the id of 1, 'dog' an id of 2, 'turtle' of 3 etc. and end up with a column with the values: 1, 2, 3, 1, 1, 3
Is there a way to do this? (preferably a quick way as the table is over 7 million rows).
Create a new table with the lookup values. You can do this easily:
create table PetTypes as
select (#rn := #rn + 1) as pettypeid, pettype
from (select distinct pettype from pets) p cross join
(select #rn := 0) params;
Then you can readily add, update, or just use the column in the select:
alter table pets add petttypeid int;
update pets p join
pettypes pt
on p.pettype = pt.pettype
set p.pettypeid = pt.pettypeid;
I would then recommend that you remove the pettype column from the original table.
Note: you can do the above without making a new table. But I think creating a new lookup table for this column is the right way to go.

Re-sequence column data to fill in gaps left after row deletion?

I am trying to find a way to re-sequence the content of a column after deletions leave a missing value.
The troubles..
1 - the values are not unique, but can repeat any number of times, so SORT and ROW_NUMBER won't work.
2 - the values are not sequential in presentation, they can appear in any order, but must always -as a whole- progress from 1 to the maximum value without any gaps.
A visual of what I am trying to accomplish..
ID, Case, Othercols
1, 1, data
2, 3, data
6, 5, data
8, 3, data
I need to create a procedure to find the missing values in Case and pull all higher values down to fill in the gaps.
ID, Case, OtherCols
1, 1, data
2, 2, data
6, 3, data
8, 2, data
I know there are better ways to resolve the issue than this, but the database is part of a server so I cannot change how it operates, only the content, and even that only at specific times.
I am only able to remove the 'failed' data and re-sequence (so far by hand) to get the software to take the result as valid.
If I understand correctly, you can resequence the values using variables:
select case, (#rn := #rn + 1) as newval
from (select distinct case from table t order by case) t cross join
(select #rn := 0) vars;
With this as a lookup table, you can then renumber the values:
update table t join
(select case, (#rn := #rn + 1) as newval
from (select distinct case from table t order by case) t cross join
(select #rn := 0) vars
) tt
on t.case = tt.case
set t.case = tt.newval;
Note: this uses case as a column name even though that is not allowed in MySQL.

SQL Query to retrieve next available ID from table

I have a table which contains a column called ticket_id and it contains values as follows:
ticket_id
STK0000000001
STK0000000002
STK0000000001
STK0000000003
STK0000000002
STK0000000001
The ticket_id value will repeat in certain rows, so it is not unique.
I am using this query to get the next available id, but I am not able to get it working. It always returns STK0000000002.
Any help is appreciated!
SQL:
SELECT
CONCAT('STK', LPAD(seq, 10, '0')) AS nextID
FROM
(SELECT
#seq:=#seq+1 AS seq,
num
FROM
(SELECT
CAST(SUBSTR(ticket_id, 4) AS UNSIGNED) AS num
FROM
sma_support_tickets
UNION ALL
SELECT
MAX(CAST(SUBSTR(ticket_id, 4) AS UNSIGNED))+2 AS num
FROM
sma_support_tickets
ORDER BY
num) AS ids
CROSS JOIN
(SELECT #seq:=0) AS init
) AS pairs
WHERE
seq!=num
LIMIT 1
Maybe I'm missing something in your question, but it seems that this should do it:
SELECT CONCAT('STK',
LPAD(MAX(SUBSTRING(ticket_id, 4)) + 1,
10,
'0')
)
FROM sma_support_tickets;
Try: This table must have one serial number or unique number or ID for the table for each row. Find out that unique number(primary key) through code and add 1 or increment that number, but not to the ticket_id as you are doing it now. so that it can move forward to next row.

Get record id from looped records

Here is the story
i have two mysql tables like :
master
id, descr
1, master 1
2, master 2
details
id, descr, masterid
1, test 1, 1
2, test 2, 1
3, test 3, 1
4, test 1, 2
5, test 2, 2
6, test 3, 2
I need a query to get the rows from the first table and a looped column from the details
For example :
first execute :
1,master 1, 1
2,master 2, 4
second execute
1,master 1, 2<- From the details table
2,master 2, 5<- From the details table
third execute
1,master 1, 3<- From the details table
2,master 2, 6<- From the details table
Fourth execute :
1,master 1, 1
2,master 2, 4
I guess i have to add a column on master table to keep the last selected record from the details table but i can't design the query.
Any ideas?
Thank you
Vangelis
The thing is - you can do it with SQL only. But that will be session-related. By that, I mean this query:
SELECT
master.*,
o.id AS oid
FROM
master
INNER JOIN
(SELECT
d.*,
#num:=IF(#id=masterid, #num:=#num+1, 1) AS num,
#id:=masterid
FROM
(SELECT * FROM details ORDER BY masterid) AS d
CROSS JOIN
(SELECT #id:=0, #num:=0) AS init
) AS o
ON master.id=o.masterid
INNER JOIN
(SELECT
masterid,
COUNT(id) AS c
FROM
details
GROUP BY
masterid) AS counts
ON master.id=counts.masterid
CROSS JOIN
(SELECT #RUN_COUNT:=IF(#RUN_COUNT IS NULL, 1, #RUN_COUNT+1)) AS r
WHERE
o.num=IF(!(#RUN_COUNT%(counts.c)), counts.c, #RUN_COUNT%(counts.c));
Very important detail of it is #RUN_COUNT. It will be looped only in terms of one session. That is: if you'll start another session, then initializing of this variable will happen again:
(SELECT #RUN_COUNT:=IF(#RUN_COUNT IS NULL, 1, #RUN_COUNT+1)) AS r
-as you can see, this simply checks if it isn't initialized - and, if it's not, then it will initialize it. So, this will fail if you're acting in different sessions.
SQLFiddle behaves like one session, thus it's working there (but you'll need first to set #RUN_COUNT to NULL, of course - because I've already run this query)
The query above will work if there are different counts for different master ids (like I've done in fiddle, 4 for masterid=1 and 3 for masterid=2). But - again, you can not rely on #RUN_COUNT in common case. If your session isn't persistent between your application and your DBMS - then you'll have to handle it in application.
in reference to what I said earlier --- if you were to do it in php, this is the sql select you would want to do to get the data in the correct format.. from here you could do a loop inside a loop in php with a limit set to break at 2.. should probably do the trick
SELECT
m.id AS master_id,
m.descr,
d.id AS detail_id
FROM master m
JOIN details d ON d.masterid = m.id