Find and replace '000L' from all rows - mysql

I'm trying to remove certain letters from part numbers but I'm having difficulties trying to get it working correctly.
This is where I'm at right now. It's non functional.
SELECT REPLACE(`part`, '[0-9]L', '') FROM `table` WHERE (`part ` LIKE '%[0-9]L')
Essentially say I have these five items:
D39J02GEN
20F934L
2984CPL
29048L20GEN
1120934L
I only want the ones in bold to be detected. So where they end in L, only if they have a number before the L.
Edit: this one gets close:
SELECT * FROM `table ` WHERE `part` REGEXP '^[0-9].*L';
but still shows ones where there is anything after the L. This is also no closer to removing the letter L.

If you know the value is at the end, then do:
SELECT LEFT(part, LENGTH(part) - 2)
FROM `table`
WHERE part REGEXP '[0-9]L$';
This would be much trickier if the pattern were in the middle of the string.

Something like this should also work if the match is always required at the end of the text.
Query
SELECT
*
FROM
t
WHERE
SUBSTRING(REVERSE(t.text_string), 1, 1) = 'L'
AND
SUBSTRING(REVERSE(t.text_string), 2) >> 0 <> 0
Result
| text_string |
| ----------- |
| 20F934L |
| 1120934L |
see demo
Note
SUBSTRING(REVERSE(t.text_string), 2) >> 0 basically means CAST(SUBSTRING(REVERSE(t.text_string), 2) AS UNSIGNED) here
Why this works?
I use MySQL's loose autocasting feature which can convert 439F02 in a INT 439 but it can't convert PC4892 into a INT it would be converted into 0
See the below resultset based on the query
Query
SELECT
*
, SUBSTRING(REVERSE(t.text_string), 1, 1)
, SUBSTRING(REVERSE(t.text_string), 2)
, SUBSTRING(REVERSE(t.text_string), 2) >> 0
, SUBSTRING(REVERSE(t.text_string), 2) >> 0 <> 0
FROM
t
Result
| text_string | SUBSTRING(REVERSE(t.text_string), 1, 1) | SUBSTRING(REVERSE(t.text_string), 2) | SUBSTRING(REVERSE(t.text_string), 2) >> 0 | SUBSTRING(REVERSE(t.text_string), 2) >> 0 <> 0 |
| ----------- | --------------------------------------- | ------------------------------------ | ----------------------------------------- | ---------------------------------------------- |
| D39J02GEN | N | EG20J93D | 0 | 0 |
| 20F934L | L | 439F02 | 439 | 1 |
| 2984CPL | L | PC4892 | 0 | 0 |
| 29048L20GEN | N | EG02L84092 | 0 | 0 |
| 1120934L | L | 4390211 | 4390211 | 1 |
Here is a demo to see the above results for yourself.

Related

MySQL: Add Default Value to Joined Table when Row not Found

System info:
$ uname -srvm
Linux 5.15.0-56-generic #62-Ubuntu SMP Tue Nov 22 19:54:14 UTC 2022 x86_64
$ mysql --version
mysql Ver 8.0.31-0ubuntu0.22.04.1 for Linux on x86_64 ((Ubuntu))
I am very inexperienced with MySQL & have been looking for an answer to this for about half a week. I am working with two tables named character_stats & halloffame that I want to join in a query. They look like this:
mysql> SELECT name, level FROM character_stats;
+-----------+-------+
| name | level |
+-----------+-------+
| foo | 0 |
| bar | 0 |
| baz | 3 |
| tester | 4 |
| testertoo | 2 |
+-----------+-------+
mysql> SELECT * from halloffame;
+----+-----------+----------+--------+
| id | charname | fametype | points |
+----+-----------+----------+--------+
| 1 | bar | T | 0 |
| 2 | foo | T | 0 |
| 3 | baz | T | 0 |
| 4 | tester | T | 0 |
| 5 | testertoo | T | 0 |
| 6 | tester | D | 40 |
| 7 | tester | M | 92 |
| 8 | bar | M | 63 |
+----+-----------+----------+--------+
In my query, I want to display all the rows from character_stats & I want to join the points column from halloffame for fametype='M'. If there is no row for fametype='M', I want to set points to 0 for that character name, instead of omitting the entire row as is done in the following:
mysql> SELECT name, level, points FROM character_stats JOIN
-> (SELECT charname, points FROM halloffame WHERE fametype='M')
-> AS hof ON (hof.charname=name);
+--------+-------+--------+
| name | level | points |
+--------+-------+--------+
| tester | 4 | 92 |
| bar | 0 | 63 |
+--------+-------+--------+
So I want it to output this:
+-----------+-------+--------+
| name | level | points |
+-----------+-------+--------+
| foo | 0 | 0 |
| bar | 0 | 63 |
| baz | 3 | 0 |
| tester | 4 | 92 |
| testertoo | 2 | 0 |
+-----------+-------+--------+
I have tried to learn how to use IFNULL, IF-THEN-ELSE, CASE, COALESCE, & COUNT statements from what I have found in documentation & answers on stackoverflow.com. But as I said, I am very inexperienced & don't know how to implement them.
The following works on its own:
SELECT IFNULL((SELECT points FROM halloffame WHERE fametype='M'
AND charname='foo' LIMIT 1), 0) as points;
But I don't know how to join it to the character_stats table. The following would work if I knew how to get the value of character_stats.name before COALESCE is called:
SELECT name, level, 'M' AS fametype, points FROM character_stats
JOIN (SELECT COALESCE((SELECT points FROM halloffame WHERE
fametype='M' AND charname=name LIMIT 1), 0) AS points) AS hof;
According to Adding Default Values on Joining Tables I should be able to use CROSS JOIN, but I am doing something wrong as it still results in Unknown column 'cc.name' in 'where clause':
SELECT name, level, points FROM character_stats
CROSS JOIN (SELECT DISTINCT name FROM character_stats) AS cc
JOIN (SELECT COALESCE((SELECT points FROM halloffame WHERE
fametype='M' AND charname=cc.name LIMIT 1), 0) AS points) AS hof;
Some references I have looked at:
Returning a value even if no result
Usage of MySQL's "IF EXISTS"
Return Default value if no row found
MySQL.. Return '1' if a COUNT returns anything greater than 0
How do write IF ELSE statement in a MySQL query
Simple check for SELECT query empty result
Is there a function equivalent to the Oracle's NVL in MySQL?
MySQL: COALESCE within JOIN
Unknown Column In Where Clause With Join
Adding Default Values on Joining Tables
https://www.tutorialspoint.com/returning-a-value-even-if-there-is-no-result-in-a-mysql-query
I found that I can do the following:
SELECT name, level, COALESCE((SELECT points FROM
halloffame WHERE fametype='M' AND charname=name
LIMIT 1), 0) AS points FROM character_stats;
Though I would still like to know how to do it within a JOIN statement.

mysql by order by case when cast()

I need to sort the ID field, but the id field is dynamic, I need to judge before sorting, if it is a pure number, then I convert it to a numeric type and then sort. But I have some problems in order by case when cast(),can somebody help me?
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for BASIS_EXP_ORG
-- ----------------------------
DROP TABLE IF EXISTS `BASIS_EXP_ORG`;
CREATE TABLE `BASIS_EXP_ORG` (
`NAME` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'name',
`ORG_ID` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT 'org',
PRIMARY KEY (`ORG_ID`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of BASIS_EXP_ORG
-- ----------------------------
INSERT INTO `BASIS_EXP_ORG` VALUES ('OU_2', '101');
INSERT INTO `BASIS_EXP_ORG` VALUES ('INV_2', '141');
INSERT INTO `BASIS_EXP_ORG` VALUES ('OU_1', '85');
SET FOREIGN_KEY_CHECKS = 1;
----------------------------------------------------------------
select distinct ORG_ID as id,
NAME as text
from BASIS_EXP_ORG
where 1 = 1
and ORG_ID in (101,141,85)
order by
case when ORG_ID REGEXP '(^[0-9])'
then ORG_ID +0
ELSE ORG_ID END
asc
Is this what you want?
I think you just need to place (ORG_ID + 0) at the order by phase to cast it to numeric type.
Please try this.
select distinct ORG_ID,
NAME as text
from BASIS_EXP_ORG
where 1 = 1
and ORG_ID in (101,141,85)
order by (ORG_ID + 0) DESC
If you're using MySQL version 8+ and MariaDB 10+, you can use REGEXP_REPLACE to remove strings then CAST it:
SELECT DISTINCT ORG_ID AS id,CAST(REGEXP_REPLACE(ORG_ID,'[a-zA-Z]','') AS SIGNED),
NAME AS TEXT
FROM BASIS_EXP_ORG
WHERE 1 = 1
ORDER BY CAST(REGEXP_REPLACE(ORG_ID,'[a-zA-Z]','') AS SIGNED) ASC;
Check demo here: https://www.db-fiddle.com/f/itK8PM7WjURn5Jaynurz4N/0
I added a few row data in the fiddle and remove the and ORG_ID in (101,141,85) in WHERE condition for testing purpose.
EDIT:
This query below should be able to get it working on older MySQL:
SELECT DISTINCT ORG_ID AS id,SUBSTRING(ORG_ID,
LEAST(
IF(LOCATE(1,org_id)=0,99,LOCATE(1,org_id)),
IF(LOCATE(2,org_id)=0,99,LOCATE(2,org_id)),
IF(LOCATE(3,org_id)=0,99,LOCATE(3,org_id)),
IF(LOCATE(4,org_id)=0,99,LOCATE(4,org_id)),
IF(LOCATE(5,org_id)=0,99,LOCATE(5,org_id)),
IF(LOCATE(6,org_id)=0,99,LOCATE(6,org_id)),
IF(LOCATE(7,org_id)=0,99,LOCATE(7,org_id)),
IF(LOCATE(8,org_id)=0,99,LOCATE(8,org_id)),
IF(LOCATE(9,org_id)=0,99,LOCATE(9,org_id))),99)+0 AS num,
NAME AS TEXT
FROM BASIS_EXP_ORG
WHERE 1 = 1
ORDER BY num ASC;
Demo on MySQL 5.7: https://www.db-fiddle.com/f/itK8PM7WjURn5Jaynurz4N/3
As you can see, I'm using a series of functions to remove the strings from the original data. First I use LOCATE to find numbers range from 1-9 and their location. The following query and result can help to clarify more:
SELECT *,
LOCATE(1,org_id),
LOCATE(2,org_id),
LOCATE(3,org_id),
LOCATE(4,org_id),
LOCATE(5,org_id),
LOCATE(6,org_id),
LOCATE(7,org_id),
LOCATE(8,org_id),
LOCATE(9,org_id) FROM BASIS_EXP_ORG;
+-------+----------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| NAME | ORG_ID | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE | LOCATE |
| | | (1,org_id) | (2,org_id) | (3,org_id) | (4,org_id) | (5,org_id) | (6,org_id) | (7,org_id) | (8,org_id) | (9,org_id) |
+-------+----------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
| OU_1 | 00000001 | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| OU_2 | 101 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| INV_2 | 141 | 1 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 |
| OU_3 | 81 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| OU_1 | 85 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 1 | 0 |
| INV_2 | a101 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| OU_1 | b40 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 |
| OU_1 | c0001 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| OU_2 | c101 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
+-------+----------+------------+------------+------------+------------+------------+------------+------------+------------+------------+
The logic behind this is to know where is the location of the number stated in LOCATE (if any). Then if it returns 0 (meaning the number doesn't exists), give it 99 so when the LEAST happen, it won't see zeros. The main reason of using LEAST however is to get the first number found instead of the smallest number found. That being said, refer to the example above and look for the data with ORG_ID=81. (LOCATE(1,org_id) found number 1 in location 2 while (LOCATE(8,org_id) found the number 8 in location 1. If we took the smallest number to judge, then we will get number 1 instead of 81 in the SUBSTRING function (this took me a while to figure out ;P). Then we use them all in the SUBSTRING and we add +0 at the last value retrieved.
tl;dr > if we convert this into plain query, we will get basically something like this:
SELECT DISTINCT ORG_ID AS id, SUBSTRING(ORG_ID,**8**,99)+0 as num
FROM BASIS_EXP_ORG
WHERE 1 = 1
AND ORG_ID='00000001'
ORDER BY num ASC;
To obtain the **8** is where all the process happen.

how to select both true and false column value in mysql

I'm having a table called file_download.
I need to display
downloaded file list -
select * from file_download where downloaded = 1;
not downloaded file list -
select * from file_download where downloaded = 0;
all file list -
for all file list, what kind of condition has to mention?
below is the sample table.
+----+----------+---------+------------+
| pk | filename | file | downloaded |
+----+----------+---------+------------+
| 1 | aaa.txt | aaa.txt | 1 |
| 2 | bbb.txt | aaa.txt | 1 |
| 3 | ccc.txt | aaa.txt | 0 |
| 4 | ccc.txt | aaa.txt | 1 |
| 5 | ccc.txt | aaa.txt | 0 |
| 6 | ccc.txt | aaa.txt | 0 |
+----+----------+---------+------------+
Thanks in advance...
There are three ways to do the same
Using OR (cheaper in cost)
select * from file_download where downloaded = 1 or downloaded = 0
Using IN (short and accurate way)
select * from file_download where downloaded in (0, 1);
Using is not null (way not recommended)
select * from file_download where downloaded is not null
Thank you for your responses...
I have done it with
select * from file_download where downloaded <> ?
? - for random input value (0, 1)

Compare words in string to cell

Given the following:
create table original (
dbString VARCHAR(255),
c_Alfa TINYINT(4) Default 0,
c_Bravo TINYINT(4) default 0,
c_Charlie TINYINT(4) default 0
);
INSERT INTO original (dbString) VALUES
('Charlie Echo Delta',0,0,0),
('Foxtrot Golf Hotel',0,0,0),
('Alfa Oscar Tango',0,0,0),
('Charlie Bravo India',0,0,0);
SET #c_string := 'Alfa Bravo Charlie';
Is it possible in mysql to compare the words in the #c_string (words are: Alfa, Bravo and Charlie) to the column dbString in the table original and check if one ore more words appear in the cell.
Outcome should be
+---------------------+------------+------------+------------+
| dbString | c_Alfa | c_Bravo | c_Charlie |
+---------------------+------------+------------+------------+
| Charlie Echo Delta | 0 | 0 | 1 |
| Foxtrot Golf Hotel | 0 | 0 | 0 |
| Alfa Oscar Tango | 1 | 0 | 0 |
| Charlie Bravo India | 0 | 1 | 1 |
+---------------------+------------+------------+------------+
I also created a fiddle: http://sqlfiddle.com/#!2/8eb2b/1
Try this
SELECT dbString,
IF(locate('Alfa',dbString), 1, 0) AS c_Alfa,
IF(locate('Bravo',dbString), 1, 0) AS c_Bravo,
IF(locate('Charlie',dbString), 1, 0) AS c_Charlie
FROM original;
Check SQL Fiddle
I think you should use LIKE in where condition, for example:
Query:
SELECT * FROM original WHERE dbString LIKE ("%" + #c_string + "%");

MySql complex query - SUM on multiple and variable columns

I have the following table structure (simplified version)
+----------------+ +-----------------+ +------+
| fee_definition | | user_fee | | user |
+----------------+ +-----------------+ +------+
| id | | user_id | | id |
| label | | fee_id | | ... |
| case1 | | case | +------+
| case2 | | manual_override |
| case3 | +-----------------+
| case4 |
| case5 |
+----------------+
Base on a pretty simple algorithm id determine which case fits the user to determine the amount of money they have to pay. A user_fee can be base on 1 to no limit number of fees definitions. which mean i can have the following content in the intersection table
+-----------+----------+--------+-------------------+
| user_id | fee_id | case | manual_override |
+-----------+----------+--------+-------------------+
| 1 | 1 | case1 | |
| 1 | 3 | case1 | |
| 1 | 5 | case1 | 50.22 |
| 2 | 1 | case5 | |
| 3 | 1 | case2 | |
| 3 | 2 | case2 | 18.50 |
+-----------+----------+--------+-------------------+
If a user is setted to have the case 1, all the fees listed under the case 1 where the value is different from 0 get picked. Same goes for the four other cases.
Just for reference on how i did things here is the actual query that I execute which is written in french (sorry for that but since we are a team of french speaking developpers, we mostly write in our code and queries in french).:
SELECT
`etudiant_etu`.*,
`session_etudiant_set`.*,
SUM(ROUND(frais_session_etudiant.fse_frais_manuel*100)/100) AS `fse_frais_manuel`,
`frais_session_etudiant`.`des_colonne`,
SUM(ROUND(definition_frais_des.des_quebecCanada*100)/100) AS `des_quebecCanada`,
SUM(ROUND(definition_frais_des.des_etranger*100)/100) AS `des_etranger`,
SUM(ROUND(definition_frais_des.des_non_credite*100)/100) AS `des_non_credite`,
SUM(ROUND(definition_frais_des.des_visiteur*100)/100) AS `des_visiteur`,
SUM(ROUND(definition_frais_des.des_explore*100)/100) AS `des_explore`,
`type_etudiant_tye`.*,
`type_formation_tyf`.*,
`pays_pys`.*,
`province_prc`.*
FROM `etudiant_etu`
INNER JOIN `session_etudiant_set`
ON session_etudiant_set.etu_id = etudiant_etu.etu_id
INNER JOIN `frais_session_etudiant`
ON frais_session_etudiant.set_id = session_etudiant_set.set_id
INNER JOIN `definition_frais_des`
ON definition_frais_des.des_id = frais_session_etudiant.des_id
LEFT JOIN `type_etudiant_tye`
ON type_etudiant_tye.tye_id = session_etudiant_set.tye_id
LEFT JOIN `type_formation_tyf`
ON type_formation_tyf.tyf_id = session_etudiant_set.tyf_id
LEFT JOIN `pays_pys`
ON pays_pys.pys_code = etudiant_etu.pys_adresse_permanente_code
LEFT JOIN `province_prc`
ON province_prc.prc_code = etudiant_etu.prc_adresse_permanente_code
WHERE (set_session = 'P11')
GROUP BY `session_etudiant_set`.`set_id`
ORDER BY `etu_nom` asc, `etu_prenom` ASC
as for reference from the actual query with the simplified version:
simplified version actual version
fee_definition.id definition_frais_des.des_id
fee_definition.case1 definition_frais_des.des_quebecCanada
fee_definition.case2 definition_frais_des.des_etranger
fee_definition.case3 definition_frais_des.des_non_credite
fee_definition.case4 definition_frais_des.des_visiteur
fee_definition.case5 definition_frais_des.des_explore
user_fee.user_id frais_session_etudiant.set_id
user_fee.fee_id frais_session_etudiant.des_id
user_fee.case frais_session_etudiant.des_colonne
user_fee.manual_override frais_session_etudiant.fes_frais_manuel
user.id session_etudiant_set.set_id
The problem I have is when it comes to handling the manual override setting. What would be the best way of doing this?
I would rather this to be handled in the query itself than in the programmation.
the logic behind what I am looking for goes as follow
get the SUM of the fees to be charged for a user and if an override value as been set, use that value instead of the actual value setted in the fee_definition, else use the value in the fee_definition.
I don't mind to loose the 4 not used cases and only keep the right column
Edited to display final result
This is the query I ended with, five levels of IF's
'IF(`frais_session_etudiant`.des_colonne= "des_quebec_canada",
SUM(IF(`frais_session_etudiant`.fse_frais_manuel > 0,
ROUND(`frais_session_etudiant`.fse_frais_manuel*100)/100,
ROUND(definition_frais_des.des_quebec_canada*100)/100)
),
IF(`frais_session_etudiant`.des_colonne= "des_etranger",
SUM(IF(`frais_session_etudiant`.fse_frais_manuel > 0,
ROUND(`frais_session_etudiant`.fse_frais_manuel*100)/100,
ROUND(definition_frais_des.des_etranger*100)/100)
),
IF(`frais_session_etudiant`.des_colonne= "des_non_credite",
SUM(IF(`frais_session_etudiant`.fse_frais_manuel > 0,
ROUND(`frais_session_etudiant`.fse_frais_manuel*100)/100,
ROUND(definition_frais_des.des_non_credite*100)/100)
),
IF(`frais_session_etudiant`.des_colonne= "des_visiteur",
SUM(IF(`frais_session_etudiant`.fse_frais_manuel > 0,
ROUND(`frais_session_etudiant`.fse_frais_manuel*100)/100,
ROUND(definition_frais_des.des_visiteur*100)/100)
),
IF(`frais_session_etudiant`.des_colonne= "des_explore",
SUM(IF(`frais_session_etudiant`.fse_frais_manuel > 0,
ROUND(`frais_session_etudiant`.fse_frais_manuel*100)/100,
ROUND(definition_frais_des.des_explore*100)/100)
),
0
)
)
)
)
) as frais'
That's a monster! as said by Ted Hopp :D
You can use IFNULL(manual_override,non-override-value)