MySQL search and remove some text in a field - mysql

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 :)

Related

MySQL Stored Procedure with Parameters for Recursive CTE

I'm working on a MySQL Way of printing an "affiliate tree" and got the thing working with Common Table Expression. I'm using the following code right now:
WITH RECURSIVE recUsers AS
(
SELECT ID, username, sponsorID, 1 AS depth, username AS path
FROM users
WHERE id = 1
UNION ALL
SELECT c.ID, c.username, c.sponsorID, sc.depth + 1, CONCAT(sc.path, ' > ', c.username)
FROM recUsers AS sc
JOIN users AS c ON sc.ID = c.sponsorID
)
SELECT * FROM recUsers;
This selects the tree underneath the user with the id 1.
Now what I'd need to get is a way to pass that id as a parameter, so I don't need to define everything from the beginning every time I want to get the result.. So my idea is to put everything in a stored prodecure and pass the id in as a parameter.. However, so far I didn't get it working and always getting various errors that are very self speaking...
Basically what I've tried was
DELIMITER //
CREATE PROCEDURE getAffiliateTree(IN userid INT())
BEGIN
---my code here, the userid 1 replaced with userid
END//
DELIMITER;
However, this doesn't seem to work.. How can I get this done?
Two things I would suggest:
Use INT, not INT(). The optional length argument to integer types is deprecated in MySQL 8.0 (which I know you're using, because you're using CTE syntax). Even if you did use the length argument, using an empty argument is not legal syntax.
Make sure that the userid input parameter name is distinct from all of the columns in the tables you reference. That is, if the table has a column named userid (any capitalization), then change the name of your input parameter. Otherwise you may make ambiguous expressions like:
... WHERE userid = userid
Even though you intend one of these to be the column and the other to be the parameter, the SQL parser has no way of knowing that. It ends up treating both as the column name, so it's trivially true on all rows of the table.
Actually, a third thing I would suggest: when you ask questions, "it doesn't seem to work" isn't clear enough. Did it produce an error? If so, what was the full error message? Did it produce no error, but didn't give you the result you wanted? If so, show a mocked-up example of what you expected, and what the query produced that didn't match. It helps to be as clear as you can when you post questions, so readers don't have to guess what trouble you need help with.

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

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));

count(*) on mysql giving me value 0

select count(*) FROM antecedente_delito WHERE rut_polichile = NEW.rut_polichile
this statement is giving de value 0, when it should give me 18 :/ ive been trying a lot to find any bug in it.
Here's the working solution that I mocked up using/changing your code in SqlFiddle. http://sqlfiddle.com/#!2/ac2e9/1
To trouble shoot this, I would view your actual values and verify that NEW. is returning what you think it should. Sometimes it may be doing some trims or removal of special characters, especially the _ and % signs are likely to stripped in subprocedures.
I would start with the query:
select top 50 rut_polichile, NEW.rut_plichile FROM antecedente_delito
If the issue is not obvious from that add in a varbinary check:
select top 50 cast( rut_polichile as varbinary), cast(NEW.rut_plichile as varbinary) from antecedente_delito
If the table only has 18 records, then you should be good to go with the above troubleshooting, but if there is more data, I would suggest limiting your results from the above by the rowid or other identifier in a where statement.
It's not the answer, but I hope it helps you find the answer.
The SELECT privilege for the subject table if references to table columns occur via OLD.col_name or NEW.col_name in the trigger definition.
but in your trigger i can't see any trigger definition. so try without NEW.
for more info: http://www.sqlinfo.net/mysqldocs/v51/triggers.html or
http://bugs.mysql.com/bug.php?id=31068

Many UPDATE WHERE in one SQL

I have a database with very bad architecture and no one wants to fix anything and i have to work with what i have. So the problem is in the screen
I need to update users connections and also some more fields... The solution which i see is SET ... WHERE AND SET .. WHERE AND SET ... WHERE (and yes, at this point i'm not even sure that it would work). So may be there is more common way to solve this problem?
As long as your values are different records I think you will need to make individual updates.
You could also consider something like this:
UPDATE categories
SET display_order = CASE id
WHEN 1 THEN 3
WHEN 2 THEN 4
WHEN 3 THEN 5
END,
title = CASE id
WHEN 1 THEN 'New Title 1'
WHEN 2 THEN 'New Title 2'
WHEN 3 THEN 'New Title 3'
END
WHERE id IN (1,2,3)
Is there a special reason why you should be updating all the fields in one single query. Why not try writing individual update queries and push it to database as a batch.

ORDERBY "human" alphabetical order using SQL string manipulation

I have a table of posts with titles that are in "human" alphabetical order but not in computer alphabetical order. These are in two flavors, numerical and alphabetical:
Numerical: Figure 1.9, Figure 1.10, Figure 1.11...
Alphabetical: Figure 1A ... Figure 1Z ... Figure 1AA
If I orderby title, the result is that 1.10-1.19 come between 1.1 and 1.2, and 1AA-1AZ come between 1A and 1B. But this is not what I want; I want "human" alphabetical order, in which 1.10 comes after 1.9 and 1AA comes after 1Z.
I am wondering if there's still a way in SQL to get the order that I want using string manipulation (or something else I haven't thought of).
I am not an expert in SQL, so I don't know if this is possible, but if there were a way to do conditional replacement, then it seems I could impose the order I want by doing this:
delete the period (which can be done with replace, right?)
if the remaining figure number is more than three characters, add a 0 (zero) after the first character.
This would seem to give me the outcome I want: 1.9 would become 109, which comes before 110; 1Z would become 10Z, which comes before 1AA. But can it be done in SQL? If so, what would the syntax be?
Note that I don't want to modify the data itself—just to output the results of the query in the order described.
This is in the context of a Wordpress installation, but I think the question is more suitably an SQL question because various things (such as pagination) depend on the ordering happening at the MySQL query stage, rather than in PHP.
My first thought is to add an additional column that is updated by a trigger or other outside mechanism.
1) Use that column to do the order by
2) Whatever mechanism updates the column will have the logic to create an acceptable order by surrogate (e.g. it would turn 1.1 into AAA or something like that).
Regardless...this is going to be a pain. I do not evny you.
You can create function which have logic to have human sort order like
Alter FUNCTION [dbo].[GetHumanSortOrder] (#ColumnName VARCHAR(50))
RETURNS VARCHAR(20)
AS
BEGIN
DECLARE #HumanSortOrder VARCHAR(20)
SELECT #HumanSortOrder =
CASE
WHEN (LEN(replace(replace(<Column_Name>,'.',''),'Figure ',''))) = 2
THEN
CONCAT (SUBSTRING(replace(replace(<Column_Name>,'.',''),'Figure ',''),1,1),'0',SUBSTRING(replace(replace(<Column_Name>,'.',''),'Figure ',''),2,2))
ELSE
replace(replace(<Column_Name>,'.',''),'Figure ','')
END
FROM <Table_Name> AS a (NOLOCK)
WHERE <Column_Name> = #ColumnName
RETURN #HumanSortOrder
END
this function give you like 104,107,119,10A, 10B etc as desired
And you can use this function as order by
SELECT * FROM <Table_Name> ORDER BY GetHumanSortOrder(<Column_Name>)
Hope this helps