I have a string that contains number with separated by comma like below.
15,22,20,26,33,445,40,44,22,225,115,2
I want to know if a number say 15 is in that string or not.The problem is that 15 and 115 both are a match.Same for other number say 2, for this case 20 , 25, and 225 are match.For both cases only it should return if there is 15 or 2 in the string.I tried using like keyword but it's not working. It also return the rows with 115 or 20, 225, 222 whille matching 15 and 2 respectively. Can anyone suggest a regex pattern?
Update
I have a query like below where I was using like keyword, but I was getting wrong result for above reason.
SELECT DISTINCT A.id,A.title,A.title_hi,A.cId,B.id as cid1,A.report_type ,A.icon_img_url, A.created_at , A.news_date
FROM tfs_report_news A, tfs_commodity_master B
WHERE (',' + RTRIM(A.cId) + ',') LIKE ('%,' + B.id + ',%')
AND A.ccId = B.ccId AND A.`report_type`= "M"
AND A.isDeleted=0 AND A.isActive=1 AND B.isDeleted=0
AND B.status=1
AND A.news_date= (SELECT MAX(T.news_date)
FROM tfs_report_news T WHERE (',' + RTRIM(T.cId) + ',')
LIKE ('%,' + B.id + ',%'))
ORDER BY created_at desc, id desc limit 100;
Here tfs_report_news has the string 15,22,20,26,33,445,40,44,22,225,115,2 as column name cId and individual cId like 15 or 2 is id of tfs_commodity_master
In MySQL, what you asked for is the purpose of string function find_in_set():
Returns a value in the range of 1 to N if the string str is in the string list strlist consisting of N substrings. A string list is a string composed of substrings separated by , characters [...] Returns 0 if str is not in strlist or if strlist is the empty string. Returns NULL if either argument is NULL.
So to check if a value is present in the list, you can just do:
find_in_set('15', '15,22,20,26,33,445,40,44,22,225,115,2') > 0
Side note: here is a recommended reading.
Use FIND_IN_SET:
SELECT
CASE WHEN FIND_IN_SET('15', csv) > 0 THEN 'yes' ELSE 'no' END AS result
FROM yourTable;
Another option would be to use LIKE:
SELECT
CASE WHEN CONCAT(',', csv, ',') LIKE '%,15,%' THEN 'yes' ELSE 'no' END AS result
FROM yourTable;
Finally, you could also use REGEXP here:
SELECT
CASE WHEN csv REGEXP '[[:<:]]15[[:>:]]' THEN 'yes' ELSE 'no' END AS result
FROM yourTable;
Related
I have a requirement where I need to mask all but characters in position 1,4,8,12,16.. for a variable length string with 'X'
For example:
Input string - 'John Doe'
Output String - 'JXXn xxE'
SPACE between the two strings must be retained.
Kindly help or reach out for more details if required.
I think maybe an external function would be best here, but if that's too much to bite off, you can get crafty with strtok_split_to_table, xml_agg and regexp_replace to rip the string apart, replace out characters using your criteria, and stitch it back together:
WITH cte AS (SELECT REGEXP_REPLACE('this is a test of this functionality', '(.)', '\1,') AS fullname FROM Sys_Calendar.calendar WHERE calendar_date = CURRENT_DATE)
SELECT
REGEXP_REPLACE(REGEXP_REPLACE((XMLAGG(tokenout ORDER BY tokennum) (VARCHAR(200))), '(.) (.)', '\1\2') , '(.) (.)', '\1\2')
FROM
(
SELECT
tokennum,
outkey,
CASE WHEN tokennum = 1 OR tokennum mod 4 = 0 OR token = ' ' THEN token ELSE 'X' END AS tokenout
FROM TABLE (strtok_split_to_table(cte.fullname, cte.fullname, ',')
RETURNS (outkey VARCHAR(200), tokennum integer, token VARCHAR(200) CHARACTER SET UNICODE)) AS d
) stringshred
GROUP BY outkey
This won't be fast on a large data set, but it might suffice depending on how much data you have to process.
Breaking this down:
WITH cte AS (SELECT REGEXP_REPLACE('this is a test of this functionality', '(.)', '\1,') AS fullname FROM Sys_Calendar.calendar WHERE calendar_date = CURRENT_DATE)
This CTE is just adding a comma between every character of our incoming string using that regexp_replace function. Your name will come out like J,o,h,n, ,D,o,e. You can ignore the sys_calendar part, I just put that in so it would spit out exactly 1 record for testing.
SELECT
tokennum,
outkey,
CASE WHEN tokennum = 1 OR tokennum mod 4 = 0 OR token = ' ' THEN token ELSE 'X' END AS tokenout
FROM TABLE (strtok_split_to_table(cte.fullname, cte.fullname, ',')
RETURNS (outkey VARCHAR(200), tokennum integer, token VARCHAR(200) CHARACTER SET UNICODE)) AS d
This subquery is the important bit. Here we create a record for every character in your incoming name. strtok_split_to_table is doing the work here splitting that incoming name by comma (which we added in the CTE)
The Case statement just runs your criteria swapping out 'X' in the correct positions (record 1, or a multiple of 4, and not a space).
SELECT
REGEXP_REPLACE(REGEXP_REPLACE((XMLAGG(tokenout ORDER BY tokennum) (VARCHAR(200))), '(.) (.)', '\1\2') , '(.) (.)', '\1\2')
Finally we use XMLAGG to combine the many records back into one string in a single record. Because XMLAGG adds a space in between each character we have to hit it a couple of times with regexp_replace to flip those spaces back to nothing.
So... it's ugly, but it does the job.
The code above spits out:
tXXs XX X XeXX oX XhXX fXXXtXXXaXXXy
I couldn't think of a solution, but then #JNevill inspired me with his idea to add a comma to each character :-)
SELECT
RegExp_Replace(
RegExp_Replace(
RegExp_Replace(inputString, '(.)(.)?(.)?(.)?', '(\1(\2[\3(\4', 2)
,'(\([^ ])', 'X')
,'(\(|\[)')
,'this is a test of this functionality' AS inputString
tXXs XX X XeXX oX XhXX fXXXtXXXaXXXy
The 1st RegExp_Replace starts at the 2nd character (keep the 1st character as-is) and processes groups of (up to) 4 characters adding either a ( (characters #1,#2,#4, to be replaced by X unless it's a space) or [ (character #3, no replacement), which results in :
t(h(i[s( (i(s[ (a( (t[e(s(t( [o(f( (t[h(i(s( [f(u(n(c[t(i(o(n[a(l(i(t[y(
Of course this assumes that both characters don't exists in your input data, otherwise you have to choose different ones.
The 2nd RegExp_Replace replaces the ( and the following character with X unless it's a space, which results in:
tXX[s( XX[ X( X[eXX( [oX( X[hXX( [fXXX[tXXX[aXXX[y(
Now there are some (& [ left which are removed by the 3rd RegExp_Replace.
As I still consider me as a beginner in Regular Expressions, there will be better solutions :-)
Edit:
In older Teradata versions not all parameters were optional, then you might have to add values for those:
RegExp_Replace(
RegExp_Replace(
RegExp_Replace(inputString, '(.)(.)?(.)?(.)?', '(\1(\2[\3(\4', 2, 0 'c')
,'(\([^ ])', 'X', 1, 0 'c')
,'(\(|\[)', '', 1, 0 'c')
Please take a look at a table below:
I need "the last part" of "what I have" to be number if it's all number and string if it contains character.
In Excel I've achieved this with the following function (as shown above):
=IFERROR(VALUE(TEXT(D2;"0"));TEXT(D2;"0"))
However I want to do this in mySQL in order to compute more effectively.
I've "floated" somwhere around CASE with CAST or CONVERT and also TRIM functions, but I haven't been able to put up something sensical.
A nice "bonus" would be to extract "the part part" by looking for the last "" character (so first "" from right of the string) but no idea at all how to achieve that.
Use SUBSTRING_INDEX.
Query
SELECT
CASE
WHEN SUBSTRING_INDEX(records.data, '_', -1) > 1 # is int check '00004949' returns 1
THEN SUBSTRING_INDEX(records.data, '_', -1) + 0 # converts '00004949' to 4949
ELSE SUBSTRING_INDEX(records.data, '_', -1)
END
AS word
FROM (
SELECT "TRA_PL_NWL_EMA_NWLY_DAI_000_20170610_IN1_01P002bc" AS DATA
UNION
SELECT "TRA_PL_NWL_EMA_NWLY_DAI_000_2017_0909_JET_00004949" AS DATA
) records
Result
word
----------
01P002bc
4949
Following query will somewhat achieve the task:
SELECT
case
when SUBSTRING_INDEX(value, "_", -1) REGEXP('(^[0-9]+$)')
then Trim(Leading 0 from SUBSTRING_INDEX(value, "_", -1))
else SUBSTRING_INDEX(value, "_", -1)
end as Value
From yourtable;
Click here for Demo
Hope it helps!
I hope this is what u want.
At least it does what you have asked for.
SELECT
CASE
WHEN (
CONVERT(
substring(
txt,
LENGTH(txt) - LOCATE('_', REVERSE(txt))+2,
length(txt)
)
, signed integer
)
) = 0
THEN substring(
txt,
LENGTH(txt) - LOCATE('_', REVERSE(txt))+2,
length(txt)
)
ELSE CONVERT(
substring(
txt,
LENGTH(txt) - LOCATE('_', REVERSE(txt))+2,
length(txt)
)
, signed integer
)
END as NUMBER
from test.test
This is my test Table and result of SQL:
txt NUMBER
DA_DA_ADAD_ADAD_ADAD_asd123 asd123
DA_DA_ADAD_ADAD_ADAD_000123 123
DA_DA_ADAD_ADAD_ADAD_444 444
DA_DA_ADAD_ADAD_ADAD_bsd123 bsd123
DA_DA_ADAD_ADAD_ADAD_csd123 csd123
DA_DA_ADAD_ADAD_ADAD_dsd123 dsd123
I have a table which looks like this: http://i.stack.imgur.com/EyKt3.png
And I want a result like this:
Conditon COL
ted1 4
ted2 1
ted3 2
I.e., the count of the number of '1' only in this case.
I want to know the total no. of 1's only (check the table), neglecting the 0's. It's like if the condition is true (1) then count +1.
Also consider: what if there are many columns? I want to avoid typing expressions for every single one, like in this case ted1 to ted80.
Using proc means is the most efficient method:
proc means data=have noprint;
var ted:; *captures anything that starts with Ted;
output out=want sum =;
run;
proc print data=want;
run;
Try this
select
sum(case when ted1=1 then 1 else 0 end) as ted1,
sum(case when ted2=1 then 1 else 0 end) as ted2,
sum(case when ted3=1 then 1 else 0 end) as ted3
from table
In PostgreSQL (tested with version 9.4) you could unpivot with a VALUES expression in a LATERAL subquery. You'll need dynamic SQL.
This works for any table with any number of columns matching any pattern as long as selected columns are all numeric or all boolean. Only the value 1 (true) is counted.
Create this function once:
CREATE OR REPLACE FUNCTION f_tagcount(_tbl regclass, col_pattern text)
RETURNS TABLE (tag text, tag_ct bigint)
LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE (
SELECT
'SELECT l.tag, count(l.val::int = 1 OR NULL)
FROM ' || _tbl || ', LATERAL (VALUES '
|| string_agg( format('(%1$L, %1$I)', attname), ', ')
|| ') l(tag, val)
GROUP BY 1
ORDER BY 1'
FROM pg_catalog.pg_attribute
WHERE attrelid = _tbl
AND attname LIKE col_pattern
AND attnum > 0
AND NOT attisdropped
);
END
$func$;
Call:
SELECT * FROM f_tagcount('tbl', 'ted%');
Result:
tag | tag_ct
-----+-------
ted1 | 4
ted2 | 1
ted3 | 2
The 1st argument is a valid table name, possibly schema-qualified. Defense against SQL-injection is built into the data type regclass.
The 2nd argument is a LIKE pattern for the column names. Hence the wildcard %.
db<>fiddle here
Old sqlfiddle
Related:
Select columns with particular column names in PostgreSQL
SELECT DISTINCT on multiple columns
I need to find the frequency of a string in a column, irrespective of its case and any white spaces.
For example, if my string is My Tec Bits and they occur in my table like this, as shown below :
061 MYTECBITS 12123
102 mytecbits 24324
103 MY TEC BITS 23432
247 my tec bits 23243
355 My Tec Bits 23424
454 My Tec BitS 23432
Then, the output should be 6, because, with whites pace removed and irrespective of case, all those strings are identical.
Is there any grep() equivalent in SQL as there is in R?
If your concern is only with the SPACE and the CASE, then you need two functions:
REPLACE
UPPER/LOWER
For example,
SQL> WITH DATA AS(
2 SELECT 'MYTECBITS' STR FROM DUAL UNION ALL
3 SELECT 'mytecbits' STR FROM DUAL UNION ALL
4 SELECT 'MY TEC BITS' STR FROM DUAL UNION ALL
5 SELECT 'my tec bits' STR FROM DUAL UNION ALL
6 SELECT 'MY TEC BITS' STR FROM DUAL UNION ALL
7 SELECT 'MY TEC BITS' STR FROM DUAL
8 )
9 SELECT UPPER(REPLACE(STR, ' ', '')) FROM DATA
10 /
UPPER(REPLA
-----------
MYTECBITS
MYTECBITS
MYTECBITS
MYTECBITS
MYTECBITS
MYTECBITS
6 rows selected.
SQL>
Then, the output should be 6
So, based on that, you need to use it in the filter predicate and COUNT(*) the rows returned:
SQL> WITH DATA AS(
2 SELECT 'MYTECBITS' STR FROM DUAL UNION ALL
3 SELECT 'mytecbits' STR FROM DUAL UNION ALL
4 SELECT 'MY TEC BITS' STR FROM DUAL UNION ALL
5 SELECT 'my tec bits' STR FROM DUAL UNION ALL
6 SELECT 'MY TEC BITS' STR FROM DUAL UNION ALL
7 SELECT 'MY TEC BITS' STR FROM DUAL
8 )
9 SELECT COUNT(*) FROM DATA
10 WHERE UPPER(REPLACE(STR, ' ', '')) = 'MYTECBITS'
11 /
COUNT(*)
----------
6
SQL>
NOTE The WITH clause is only to build the sample table for demonstration purpose. In our actual query, remove the entire WITH part, and use your actual table_name in the FROM clause.
So, you just need to do:
SELECT COUNT(*) FROM YOUR_TABLE
WHERE UPPER(REPLACE(STR, ' ', '')) = 'MYTECBITS'
/
You could use something like
UPPER(REPLACE(userString, ' ', ''))
to check for upper case only and to remove white space.
You could cast your statements to LOWER() before comparing them eg.
LOWER(column_name) = LOWER(variable)
more specific:
LOWER(First_name) = LOWER('JoHn DoE')
would become first name = 'john doe'
For the spacing you should use replace, the format for that is:
REPLACE(yourstring, ' ' , '')
' ' = a space character replace it by an empty string = ''
So you would do
WHERE LOWER(REPLACE(fieldname, ' ', '') = 'mytecbits'
You need to use count to bring back the number affected, Lower will place the data into lower case so that when you make a comparison you can make it lower case.
To remove spaces you then use Replace and replace the space with an empty string for your comparison:
Select COUNT(ColumnA)
from table
where Lower(Replace(ColumnB, ' ', '')) = 'mytecbits'
If you are looking for the number of instances of one specific string, irrespective of case / whitespace, then you need to do the following -
ignore whitespace
ignore case
count the number of instances of the string
So you want a query like the following -
SELECT
COUNT(field)
FROM
table
WHERE
UPPERCASE(REPLACE(field, ' ', '')) = UPPERCASE(REPLACE(userstring, ' ', ''))
This counts the number of rows in your table where field is the same as the userstring, when case is ignored (all set to the same case using UPPERCASE, so it is effecitvely ignored), and spaces are ignored (spaces are removed from the field and the userstring using REPLACE)
Since REGEXP is case insensitive, you can obtain a match by making the spaces optional, example:
SELECT count(field) FROM yourtable WHERE field REGEXP "MY *TEC *BITS";
Note: if needed, you can add a space or a [[:<:]] (word boundary) before "MY" and a space or a [[:>:]] after "BITS" to avoid false positive.
I need a single query which gives two middle characters of even string and one middle character of odd string.
Currently i am using this code but it is giving error.
SELECT S_name, MID(S_name, LENGTH(S_name)/2,1) WHERE (LENGTH(S_name) %2) = 1 OR/AND SELECT S_Name, MID(S_name,LENGTH(S_name)/2,2) WHERE (LENGTH(S_name)%2)=0 FROM Student;
I have also tried this code but it is returning empty view/table.
SELECT S_name FROM Student WHERE ((LENGTH(S_name) %2) = 1 AND SUBSTRING(S_name, LENGTH(S_name)/2+1, 1)) OR ((LENGTH(S_name) %2) = 0 AND SUBSTRING(S_name, LENGTH(S_name)/2-1, 2))
Please Just take a look at it and point out my mistake.
You want to use case in the select clause:
select s_name,
(case when length(s_name) % 2 = 0 then substring(s_name, length(s_name)/2, 2)
else substring(s_name, 1 + length(s_name) / 2, 1)
end)
from student;