Compare words in string to cell - mysql

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 + "%");

Related

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.

Find and replace '000L' from all rows

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.

Get non zero values including null

I have a table with column having value 0, null and 1. I need record having non 0 values, including null and 1. I need to query using eloquent.
My table looks like this:
id | user_id | medical | gsg |interview_result | flight | created_at
----------------------------------------------------------------------
1 | 1 | null | null | 1 | null | anydate
2 | 2 | 0 | null | 1 | null | anydate
3 | 3 | 1 | 1 | 1 | 1 | anydate
4 | 8 | 1 | 1 | 1 | 0 | anydate
Please answer this question. I want non 0 values including null. Mysql + Eloquent. Great if you give eloquent code.
Note: gsg, medical, interview_result should be non 0 including null. Other column needn't be used.
You have to use where clause to match rows that not include 0, here is an example:
DB::table('table')
->where('gsg', '<>', 0)
->where('medical', '<>', 0)
->where('interview_result', '<>', 0)
->get();
Hope this helps

SQL query returning empty set

I have this table
| BookID | BookTitle | NumberOfPages | NoOfCopies |
+--------+--------------------------------+---------------+------------+
| 1 | The Help | 444 | 4 |
| 2 | The Catcher in the Rye | 277 | 10 |
| 3 | Crime and Punishment | 545 | 2 |
| 4 | The Brothers Karamazov | 795 | 1 |
| 5 | A Crown of Wishes | 369 | 12 |
| 6 | The Fireman | 752 | 3 |
| 7 | Fahrenheit 451 | 174 | 9 |
| 8 | The Hobbit | 366 | 1 |
| 9 | Lord of Emperors | 560 | 4 |
| 10 | Holy Bible: King James Version | 1590 | 11 |
----------------------------------------------------------------------------
When I insert a book title and expect it to return the book id, it always returns an empty set
so far, I have tried these queries.->book_info is the name of the table:
select BookID from book_info where ucase(BookTitle) = ' THE HELP% ';
select BookID from book_info where BookTitle = ' The Help ';
select BookID from book_info where lcase(trim(BookTitle) = 'the help';
but none of them worked.
Note I don't rely on sql in my job.
you need to use like if you want to use "%"
when you use "=" you need to sure it is same. even space also count
select BookID from book_info where BookTitle LIKE 'THE HELP%';
The issue here is with the operator you are using and the value you are function you are expecting from it, = operator checks for the exact match that's why your queries are returning no records:
select BookID from book_info where ucase(BookTitle) = ' THE HELP% ';
select BookID from book_info where BookTitle = ' The Help ';
select BookID from book_info where lcase(trim(BookTitle) = 'the help';
And one more thing that is:
MySQL queries are not case-sensitive by default.
So you don't need to add the string methods here to change the values case.
We usually use the % with LIKE only like this:
select BookID from book_info where ucase(BookTitle) LIKE '%THE HELP%';
In this query LIKE %THE HELP% will match all the string having THE HELP in them;

Calculations of different columns in Mysql Query

I have a Table:-
+-----+--------------+--------------+----------+--------------------+---------------+-----------------+
| id | CustomerName | VideoQuality | IsActive | BufferedTime | ElapsedTime | TotalBufferTime |
+-----+--------------+--------------+----------+--------------------+---------------+-----------------+
| 139 | HotStar | 180 | Yes | 10.367167126617211 | 30.000000000 | NULL |
| 140 | HotStar | 1300 | NULL | 5.43524230876729 | 34.000000000 | NULL |
| 141 | HotStar | 1300 | NULL | 5.671054515212042 | 38.000000000 | NULL |
| 142 | HotStar | 1300 | NULL | 5.045639532902047 | 41.000000000 | NULL |
| 143 | HotStar | 1300 | NULL | 5.455747718023355 | 44.000000000 | NULL |
| 144 | HotStar | 1300 | NULL | 5.691559924468107 | 49.000000000 | NULL |
i want to calculate the columns BufferTime and ElapsedTime and insert that output to TotalBufferTime column but i want to skip the first row of the BufferTime.
So the fisrt calculation will be 5.43 + 30.000 second calculation will be 5.67 + 34.00 and so on.
I also have a column IsActive which shows the first row of Buffer time.
I want to do something like this :-
update RequestInfo SET `TotalBufferTime` = BufferedTime + ElapsedTime;
only thing i want to skip only the first row of the column buffered time.
Assuming you a field id that determines row order in your table, you can use a correlated subquery so as to get BufferedTime of previous row like this:
SELECT t1.CustomerName, t1.VideoQuality, t1.IsActive, t1.BufferedTime,
t1.ElapsedTime,
(SELECT t2.BufferedTime
FROM mytable AS t2
WHERE t2.td > t1.id
ORDER BY id LIMIT 1) + t1.ElapsedTime AS TotalBufferTime
FROM mytable AS t1
WHERE IsActive IS NULL
Edit:
To UPDATE you can use the following query:
SET #et = 0;
SET #ElapsedTime = NULL;
UPDATE RequestInfo
SET TotalBufferTime = CASE
WHEN (#et := #ElapsedTime) < 0 THEN NULL
WHEN #ElapsedTime := ElapsedTime THEN BufferedTime + #et
END
ORDER BY id;
The trick here is to use a CASE expression where the first WHEN clause is always evaluated (because it is the first one) but is never true. This way #et variable is initialized with the value of #ElapsedTime, i.e. the value of the previous record.
Demo here