Zero padding : convert MD-1 to MD-001 with pure sql - mysql

guys I need help.
I am using Mysql / phpmyadim.
I have db with table which stores name and code id of people.
+--------+---------+
| Name | code_id |
+--------+---------+
| Nazeer | MD-1 |
+--------+---------+
I have 10 contacts and ids. I am using php program which used to generate automatic code.
recently i imported more records in to db from excel file and record increase to 5000+.
My php automatic code stopped generating codes giving me syntax error on code id.
I figured out that my excel import was having code id like MD-1, MD-2, etc. and my program used automatic code for number in 3 digits since my record is over thousands which 4 digit it give syntax error.
I did some research on solving that and the answer was to change all 2 digit numbers eg. "MD-1" ~ "MD-99" TO "MD-001" ~ "MD-099" and my program will work again.
so the question is how do i do that in phpmyadmin sql to change it. I need to keep 'MD-' and add '0' then add back the corresponding number.
thanks and appreciate your help in advance.
Regrds.

this sql will update all your data, but like I said in comments, you better off fixing your php code instead.
WARNING : this sql only works assuming all your data are in the format of [MD-xxx] with 3 or less numbers in it
UPDATE your_table SET
code_id=case length(substr(code_id,4))
WHEN 1 THEN concat("MD-00",substr(code_id,4))
WHEN 2 THEN concat("MD-0",substr(code_id,4))
ELSE code_id END;

I assume that you want to update the content MD-1 to MD-001 and MD-99 to MD-099. To do that you can write a PHP code to retrieve the rows one by one and have to match patterns and then update. Here are some useful links. link 1
HINT : you can check 5 digit string and then add another 0 in the position of 3.(use [exploid] to split by "-" and then concat with "-0" 2) There are no way to do the same only by using MYSQl since it's not a programming language. And other thing is PHP is not a program. It's a programming language.

run UPDATE query and use CONCAT function :
for ($x=0; $x=<upto>; $x++){
UPDATE <table_name>
SET <columnname>= CONCAT('MD-',0,$x)
WHERE <columnname>= CONCAT('MD-',$x)
}

Below simple update command can help you.
UPDATE mytable
SET code_id=IF(LENGTH(code_id)=4,CONCAT(SUBSTRING_INDEX(code_id,'-',1),'-00',SUBSTRING_INDEX(code_id,'-',-1)),IF(LENGTH(code_id)=5,CONCAT(SUBSTRING_INDEX(code_id,'-',1),'-0',SUBSTRING_INDEX(code_id,'-',-1)),code_id));

Related

MySQL search and remove some text in a field

I have to update 2 fields in a table, assuming I have the following data:
Date CategoryID
2019-04-19 1,92,10
2019-04-18 4,105,10
2019-04-17 3,106,7,78
2019-04-16 3,108,10
I have to update CategoryID and remove the following category numbers if there is/are in row: 106, 107, 108 and 92
So the result will be:
Date CategoryID
2019-04-19 1,10
2019-04-18 4,105,10
2019-04-17 3,7,78
2019-04-16 3,10
Normally I use the REPLACE function, but in this case I don't know how to use it to remove that category and keep the others.
Could someone drive me?
Thank you, Lucas
EDIT: REGEXP_REPLACE from #Joakim Danielson did the trick. Thank you to all people who partecipate/reply, however, to all those who have criticized, this is not my code, it's Datalife Engine Blog :)
I use REGEXP_REPLACE with two similar patterns but with the comma , before and after to support the numbers being first, last or somewhere in the. middle
UPDATE test
SET categoryID = REGEXP_REPLACE(categoryID, '((106|107|108|92)([,]{1}))|(([,]{1})(106|107|108|92))', '')
This query is somewhat limited since it will replace both 106 and 1060 for instance. Is this a problem or is the id's limited in range so this is good enough?
Since I assume this is more of a one time thing you could divide it into 3 different updates to make sure you only get exact hits
-- id in the middle
UPDATE test
SET categoryID = REGEXP_REPLACE(categoryID, ',(106|107|108|92),', ',')
-- id at the start
UPDATE test
SET categoryID = REGEXP_REPLACE(categoryID, '^(106|107|108|92),', '')
-- id at the end
UPDATE test
SET categoryID = REGEXP_REPLACE(categoryID, ',(106|107|108|92)$', '')
you could use multiple replace calls, i.e. first run queries for for each number with a comma after it. I.e. this replaces 107, with empty string.
Then run queries for each number as single entry. I.e. replace 107 with empty string.
In both cases be aware of partial matches. So if you replace 97 with empty string it will also change id 197 to 1. Or when replacing 97, with empty string you might turn 197,4 into 14.
That is a horrible schema, at least for use in a relational database.
However, for getting what you asked for, see if this will work:
UPDATE thetable
SET CategoryID = "1,10"
WHERE Date = "2019-04-19"
To make this work, the sql query will have to be generated by a programming language which inspects strings and has some other way to figure out which row to update.
REGEXP_REPLACE from #Joakim Danielson did the trick. Thank you to all people who partecipate/reply, however, to all those who have criticized, this is not my code, it's Datalife Engine Blog :)

Talend - Check columns lenght before inserting into mysql database

I'm trying to use Talend Open Studio for Data Integration for a BI school project. I have a txt file with some data like this :
NoClient;Name;Region;State;City;Postcode
24;Edna Thomas;West;California;Laguna Niguel;92677
I used jobs to transform data and insert it into tables. It works nicely.
Now, I'd like to handle SQL errors. For example, if the column length specified in the DB is 10 and if the job tries to insert a 11 length data in that column, I will get an SQL error.
How can I achieve it ? Is there a specific feature in tMysqlOutput or should I simply use triggers like this to check data before inserting :
CREATE TRIGGER my_trigger
BEFORE INSERT
ON my_table
FOR EACH ROW BEGIN
IF (SELECT LENGTH(NEW.Noclient)>255) THEN
// instructions
END IF
Hope it's clear enough ! Thanks in advance, sorry for bad english :-)
Maybe you can do a check in each variable in a tmap.
Like for example :
StringHandling.LEN(var) <= 10 ? var : StringHandling.LEFT(var,10)
And you adapt in function of the size of your field.
There's a component for this: tSchemaComplianceCheck
A nice example can be found at:
http://dwetl.com/2015/03/30/data-validation-using-tschemacompliancecheck/

TOS DI variable in tMySqlInput

I'm relatively new to Talend OSDI. I managed to do simple request in MySql with tMySqlInput component. However today I have a more ambitious request and have some trouble to make it work.
Indeed I need a request where the result depends on the previous line. I made it on MySQLWorkbench but not on Talend. Exemple : delay time between two dates.
Here is the request :
SET #var = NULL;
SELECT id, start_date, end_date, #var precedent, UNIX_TIMESTAMP(TIMEDIFF(start_date,#var)) AS diff, #var:=start_date AS temp
FROM ma_table
ORDER BY start_date;
and errors are :
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT id, start_date, end_date, id_process_type, #var precedent, UNIX_TIMESTAMP' at line 2
...Not very usefull, Is this syntax forbidden on Talend ? Do it exists others solutions to do such requests on Talend ? (for delay time between two dates for examples) or other component maybe ? I am searching with tMysqlRow.
Thanks for ideas !
As #Gabriele B mentions, you might want to consider doing this in a more "Talend" way.
I'd personally make use of the tMemorizeRows component to do this though.
To simplify this I've gone and made the start and end dates as integers but it should be trivial to handle this using proper dates.
If we have some data that shows the start and end date of a process and we want to work out the delay between finishing the last one and starting the next process we can read all of the data in and then use the tMemorizeRows component to remember the last 2 rows:
We then access the memorized data by looking at the array index. So here we go to a tJavaRow component that has an extra output column, startdelay. We then calculate it by comparing the current process' start day minus the last process' end date:
output_row.id = input_row.id;
output_row.startdate = input_row.startdate;
output_row.enddate = input_row.enddate;
if (id_tMemorizeRows_1[0] != 1) {
output_row.startDelay = startdate_tMemorizeRows_1[0] - enddate_tMemorizeRows_1[1];
} else {
output_row.startDelay = 0;
}
The conditional statement it to avoid null pointer errors on the first run of the data as the enddate_tMemorizeRows_1[1] will be null at that point. You could handle the null in other ways of course.
This process is reasonably easy to understand and maintain (although there is that small bit of Java code in there) and has the benefits of only needing the load the data once and only keep a small part of it in memory at any one time. It should also be very fast.
You should consider a statement refactory to do it in a "Talend" way, maybe little slower but most portable and robust.
If your table is not huge, for example, I would recommend to load it in memory using tCacheOutput/tCacheInput (you can find them on Talend Exchange) and this design:
tMySqlLoad----->tCacheOutput_1
|
|
|
OnSubjobOk
|
|
v
tCacheInput_1------->tMap_1--------+
|
|
tJoin-------------->tMap_3------------>[output]
|
|
tCacheInput_2------->tMap_2--------'
First of all you dump your table on a memory buffer
Then, you read two times this buffer. It's in memory, so it won't hurt performances
In tMap_1 you add a auto_increment index using a Numeric.sequence
You do the same in tMap_2 but with a starting number of 2 (basically, you shift the index)
Then you auto-join the table using these brand new columns
Finally in tMap_3 you're going to release your payload (ie make the diff)
This is going to be a verbose but robust solution if your table is small. If it's not and performance is not a issue you can try an even more verbose solution like Prepared Statements.

when using union that uses values from a form it creates a error?

I have this union statement when I try to take parameters from a form and pass it to a union select statement it says too many parameters. This is using MS ACCESS.
SELECT Statement FROM table 1 where Date = Between [Forms]![DateIN]![StartDate]
UNION
SELECT Statement FROM table 2 where Date = Between [Forms]![DateIN]![StartDate]
This is the first time I am using windows DB applications to do Database apps. I am Linux type of person and always use MySQL for my projects but for this one have to use MS Access.
Is there anther way to pass parameters to UNION Statement because this method of defining values in a form can work on Single SELECT statements. But I don't know why this problem exist.
Between "Determines whether the value of an expression falls within a specified range of values" like this ...
expr [Not] Between value1 And value2
But your query only gives it one value ... Between [Forms]![DateIN]![StartDate]
So you need to add And plus another date value ...
Between [Forms]![DateIN]![StartDate] And some_other_date
Also Date is a reserved word. If you're using it as a field name, enclose it in brackets to avoid confusing the db engine: [Date]
If practical, rename the field to avoid similar problems in the future.
And as Gord pointed out, you must also bracket table names which include a space. The same applies to field names.
Still getting problems when using this method of calling the values or dates from the form to be used on the UNION statement. Here is the actual query that I am trying to use.
I don't want to recreate the wheel but I was thinking that if the Date() can be used with between Date() and Date()-6 to represent a 7 days range then I might have to right a module that takes the values from the for and then returns the values that way I can do something like Sdate() and Edate() then this can be used with Between Sdate() and Edate().
I have not tried this yet but this can be my last option I don't even know if it will work but it is worth a try. But before i do that i want to try all the resources that Access can help me make my life easy such as its OO Stuff it has for helping DB programmers.
SELECT
"Expenditure" as [TransactionType], *
FROM
Expenditures
WHERE
(((Expenditures.DateofExpe) Between [Forms]!Form1![Text0] and [Forms]![Form1]![Text11]))
UNION
SELECT
"Income" as [TransactionType], *
FROM
Income
WHERE
(((Income.DateofIncom) Between [Forms]!Form1![Text0] and [Forms]![Form1]![Text11] ));
Access VBA has great power but I don't want to use it as of yet as it will be hard to modify changes for a user that does not know how to program. trying to keep this DB app simple as possible for a dumb user to fully operate.
Any comments is much appreciated.

How do I remove an email domain value and add a new one in a column - mysql

So I have a bunch of users in a column that get refreshed as:
Bill#test.comXYZ
Tom#test.comXYZ
John#test.comXYZ
We refresh the database each week and I need to update these appropriate emails to:
Bill#domain.com
Tom#domain.com
John#domain.com
I figured I can use concat to do the latter, but I am stuck on the former issue. Is there a way to split the values (like split Bill#test.comXYZ into Bill - #test.comXYZ and then remove the #TEXT values?).
Anyways, any help will be much appreciated.
You can use the mySQL replace function, i.e.
UPDATE mytable
set myfield = replace (myfield, '#test.comXYZ', 'domain.com')
http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_replace