I have recently switched over from OpenOffice Base to MySQL community. In ooBase you can customize integers upon entering them into the database. For example I could type 2013_00000 and then every number in this column would be formatted in this way (2013_00001, 2013_00002, ...). After playing around with MySQL community for a while I noticed that there is no obvious way to format a custom integer like this. I might be overlooking something basic, but if anyone knows how to do this please let me know. Thank you
In order to manipulate data before inserting them you need a trigger.
Something like that:
CREATE TRIGGER ins_sn BEFORE INSERT ON tbl
FOR EACH ROW
SET NEW.sn = CONCAT(LEFT(NEW.sn, 4), '_', RIGHT(NEW.sn,5));
If you need to update your rows, you need a second trigger:
CREATE TRIGGER upd_sn BEFORE UPDATE ON tbl
FOR EACH ROW
SET NEW.sn = CONCAT(LEFT(NEW.sn, 4), '_', RIGHT(NEW.sn,5));
See http://sqlfiddle.com/#!2/01428/1 for the complete example.
Here, I use the CONCAT(), LEFT() and RIGHT() functions for simplicity. Maybe your data require more complex manipulations (i.e.: padding). MySQL has a rich set of string functions. Anyway this is the principle.
Not the most flexible (here locked down to an underscore separator), but you can do it with a trigger, something like this;
CREATE TRIGGER trig_MyTable BEFORE INSERT ON MyTable
FOR EACH ROW
BEGIN
SELECT seq into #seq FROM MyTable_Seq FOR UPDATE;
SET NEW.id = #seq, #cutoff = LOCATE('_', #Seq);
UPDATE MyTable_Seq SET Seq =
CONCAT(LEFT(#seq, #cutoff),
LPAD(SUBSTR(#seq, #cutoff+1)+1, LENGTH(#seq)-#cutoff, '0'));
END;
//
An SQLfiddle to test with.
Related
I successfully executed the sql code below from an msql editor (phpmyadmin), testing it with one customer (where Customer No=1). I need to now run the sql script for all the customers.
START TRANSACTION;
INSERT INTO `addresses` (`AddressLine1`,`CityID`,`ProvStateCode`,`AddressPostCode`,`CountryIso`) SELECT `Bill To Address`,`Bill To City`,`Bill To Province`,`Bill Code`,`Country` FROM `pdx_customers` where `Customer No`=1;
SELECT #last_id := LAST_INSERT_ID();
SELECT `Customer No` FROM `pdx_customers`
INSERT INTO `customer_addresses` (`CustID`,`AddressID`,`AddressTypeID`) Values(1,#last_id,1);
COMMIT;
It seems I would need to create a stored procedure ? In a loop, I need to get the Customer No dynamically for each row in the pdx_customers table, and enter into the Values clause in the insert command, i.e Values(#CustID,#last_id,1). Not sure how I would do this ?
Any help would be appreciated.
Thanks
This is a really common problem, and I would say that doing a loop in sql is almost never a good idea. Here is another option, which you may or may not consider good as it does introduce a new column. I've used it in some apps I've done, and its made things very simple. Does depend on your use case though so it wont be for everyone.
1) Firstly, add a new column to the address table, call it something that wont be confused by anyone looking at the table like TempInsertId.
2) When writing the new address, include the CustomerId in the TempInsertId column
3) Now you can easily read the AddressId and CustomerId back and write it into the CustomerAddress table
4) If you wish, do a final update to set the TempInsertId back to null.
As I said, not advocating in all cases, but it can be a very simple solution to the problem.
You can use the below statement to create a loop:
start transaction;
while counter < max do
insert into . . . ;
set counter=counter+1;
end while;
I have a column in MySQL table which has 'messy' data stored as text like this:
**SIZE**
2
2-5
6-25
2-10
26-100
48
50
I want to create a new column "RevTextSize" that rewrites the data in this column to a pre-defined range of values.
If Size=2, then "RevTextSize"= "1-5"
If Size=2-5, then "RevTextSize"= "1-5"
If Size=6-25, then "RevTextSize"="6-25"
...
This is easy to do in Excel, SPSS and other such tools, but how can I do it in the MySQL table?
You can add a column like this:
ALTER TABLE messy_data ADD revtextsize VARCHAR(30);
To populate the column:
UPDATE messy_data
SET revtextsize
= CASE
WHEN size = '2' THEN '1-5'
WHEN size = '2-5' THEN '1-5'
WHEN size = '6-25' THEN '6-25'
ELSE size
END
This is a brute-force approach, identifying each distinct value of size and specifying a replacement.
You could use another SQL statement to help you build the CASE expression
SELECT CONCAT(' WHEN size = ''',d.size,''' THEN ''',d.size,'''') AS stmt
FROM messy_data d
GROUP BY d.size
Save the result from that into your favorite SQL text editor, and hack away at the replacement values. That would speed up the creation of the CASE expression for the statement you need to run to set the revtextsize column (the first statement).
If you want to build something "smarter", that dynamically evaluates the contents of size and makes an intelligent choice, that would be more involved. If was going to do that, I'd do it in the second statement, generating the CASE expression. I'd prefer to review that, befor I run the update statement. I prefer to have the update statement doing something that's easy to understand and easy to explain what it's doing.
Use InStr() to locate "-" in your string and use SUBSTRING(str, pos, len) to get start & End number. Then Use Between clause to build your Case clause.
Hope this will help in building your solution.
Thanks
I have a source of data from where I extract some fields, among the fields there are some date fields and the source sends their values like this
#DD/MM/YYYY#
almost all the fields can be sent into the query with no modificaction, except this of course.
I have written a program the gets the data from an internet connection and sends it to the MySQL server and it's sending everything as it should, I am sure because I enabled general logging in the MySQL server and I can see all the queries are correct, except the ones with date fields.
I would like to avoid parsing the fields this way because it's a lot of work since it's all written in c, but if there is no way to do it, I understand and would accept that as an answer of course.
As an example suppose we had the following
INSERT INTO sometable VALUES ('#12/10/2015#', ... OTHER_VALUES ..., '#11/10/2015#');
in this case I send the whole thing as a query using mysql_query() from libmysqlclient.
In other cases I can split the parts of the message in something that is like an instruction and the parameters, something like this
iab A,B,C,#12/10/2015#,X,Y,#11/10/2015#
which could mean INSERT INTO table_a_something_b_whatever VALUES, and in this situation of course, I capture all the parameters and send a single query with a list of VALUES in it. Also in this situation, it's rather simple because I can handle the date like this
char date[] = "#11/10/2015#";
int day;
int month;
int year;
if (sscanf(date, "#%d/%d/%d#", &day, &month, &year) == 3)
{
/* it's fine, build a sane YYYY-MM-DD */
}
So the question is:
How can I tell the MySQL server in what format the date fields are?
Clarification to: Comment 1
Not necessarily INSERT, it's more complex than that. They are sometimes queries with all their parameters in it, sometimes they are just the parameters and I have to build the query. It's a huge mess but I can't do anything about it because it's a paid database and I must use it for the time being.
The real problem is when the query comes from the source and has to be sent as it is, because then there can be many occurrences. When I split the parameters one by one there is no real problem because parsing the above date format and generating the appropriate value of MySQL is quite simple.
You can use STR_TO_DATE() in MySQL:
SELECT STR_TO_DATE('#08/10/2015#','#%d/%m%Y#');
Use this as part of your INSERT process:
INSERT INTO yourtable (yourdatecolumn) VALUES (STR_TO_DATE('#08/10/2015#','#%d/%m%Y#'));
The only Thing I could imagine at the Moment would be to Change your Column-Type from DateTime to varchar and use a BEFORE INSERT Trigger to fix "wrong" Dates.
Something like this:
DELIMITER //
CREATE TRIGGER t1 BEFORE INSERT on myTable FOR EACH ROW
BEGIN
IF (NEW.myDate regexp '#[[:digit:]]+\/[[:digit:]]+\/[[:digit:]]+#') THEN
SET NEW.myDate = STR_TO_DATE(NEW.myDate,'#%d/%m/%Y#');
END IF;
END; //
DELIMITER ;
If you are just Need to run the Import in question once, use the Trigger to generate a "proper" dateTimeColumn out of the inserts - and drop the varchar-column afterwards:
('myDate' := varchar column to be dropped afterwards;`'myRealDate' := DateTime Column to Keep afterwards)
DELIMITER //
CREATE TRIGGER t1 BEFORE INSERT on myTable FOR EACH ROW
BEGIN
IF (NEW.myDate regexp '#[[:digit:]]+\/[[:digit:]]+\/[[:digit:]]+#') THEN
SET NEW.myRealDate = STR_TO_DATE(NEW.myDate,'#%d/%m/%Y#');
else
#assume a valid date representation
SET NEW.myRealDate = NEW.myDate;
END IF;
END; //
DELIMITER ;
Unfortunately you cannot use a Trigger to work on the datetime-column itself, because mysql will already mess up the NEW.myDate-Column.
this is server_var_dump row one output http://pastebin.com/e1qHG64Q
now how do I query to get just the HTTP_USER_AGENT line and save it in separate field?
I have done this with php script but I want to do it with mysql query so that it will be fast because the database is huge.
Something like this?
UPDATE your_table
SET user_agent = SUBSTR(server_var_dump,
#p, INSTR(SUBSTR(server_var_dump, #p, 100), "\n")-1)
WHERE #p := INSTR(server_var_dump,'[HTTP_USER_AGENT]')+21;
I found an answer too. :) thought would be useful for others:
UPDATE tablename SET useragent= SUBSTRING_INDEX(SUBSTR(server_var_dump,INSTR(server_var_dump,'[HTTP_USER_AGENT]')+21,200), '[', 1);
how? substring_index fetches the substring until the first occurence of "[" delimeter defined. and substring defined is beginning from [HTTP_USER_AGENT]+21 +21 TO remove the [HTTP_USER_AGENT] stuff. now we have clean just what we want is useragent. :)
now I have one doubt. if I update this to entire column. will the update be corrosponding to the server_var_dump row which we fetched user_agent from ? or it ll just update from first ?
So that when you insert 'abc',it'll be converted to 'ABC' automatically.
I'm using MySQL,is it possible?
You could write an INSERT trigger that does this for you.
Something like:
CREATE TRIGGER Capitalize BEFORE INSERT ON MyTable
SET NEW.MyColumn = UPPER(NEW.MyColumn)
What about using Upper function while executing query ?
lets say You are using a SP to insert the values ... cast the value to upper case using UPPER function and then insert ?
this really should be done before it is passed to the DB