How to use special characters in SQL Server LIKE clause - sql

I have a table in which I want to get the strings which are like ab aabb aaabbb ...... a n times followed by b n times as shown below.
Eg TABLE:
value
----------
ab
aabb
aaabbb
aaaabbbb
1
1a
abababa
I want the result TABLE to be:
value
----------
ab
aabb
aaabbb
aaaabbbb
I've tried like this
select * from [NumTest] where value LIKE '[a]+[b]+'
but it's returning zero rows.
Can anybody help me how to use special characters in SQL Server's LIKE ?

Here is something that can work:
(EDIT - after O/P comment, commented parts not needed)
--WITH CTE_GoodValues AS
--(
SELECT value
FROM Table1
WHERE LEFT(VALUE,LEN(VALUE)/2) = REPLICATE('a',LEN(VALUE)/2)
AND RIGHT(VALUE,LEN(VALUE)/2) = REPLICATE('b',LEN(VALUE)/2)
AND LEN(VALUE)%2=0
--)
--SELECT REPLICATE(' ', (SELECT MAX(LEN(VALUE))/2 FROM CTE_GoodValues)- LEN(VALUE)/2) + VALUE
--FROM CTE_GoodValues
In the CTE - select values that have left half all a-s and right half all b-s. Then find MAX length and use it to replicate needed empty spaces in front
DEMO (after edit)

Related

NOT IN is not working as expected with Listagg function

Below is the DDL of the table
create or replace table tempdw.blk_table;
(
db_name varchar,
tbl_expr varchar
);
insert into tempdw.blk_table values ('edw','ABC%');
insert into tempdw.blk_table values ('edw','EFG%');
select * from tempdw.blk_table;
Below code is not working, expected output should not return any
select * from tempdw.blk_table where tbl_expr not in (
select regexp_replace(regexp_replace(replace(listagg(tbl_expr,','),',','\',\''),'^','\''),'$','\'') from tempdw.blk_table);
When I run below code it works fine , Trying to understand why it's not working for above code
select * from tempdw.blk_table where tbl_expr NOT IN('ABC%','EFG%');
Au contraire The code is working just fine. You don't understand the difference between a string that has commas and a list of strings.
Unfortunately, it is rather hard to figure out what you do want to do, because your question does not explain that.
I can speculate that you want something like:
select bt.*
from blk_table bt
where db_name like tbl_expr;
This is just a guess, however.
with data as (
select * from values ('edw','ABC%'),('edw','ABC%') v(db_name,tbl_expr )
)
select * from data
where tbl_expr not in (
select regexp_replace(regexp_replace(replace(listagg(tbl_expr,','),',','\',\''),'^','\''),'$','\'') from data);
does indeed give the results you don't want. aka:
DB_NAME TBL_EXPR
edw ABC%
edw ABC%
because your sub-query only has one row of results, because you have aggregated the two input into one row.
REGEXP_REPLACE( REGEXP_REPLACE( REPLACE( LISTAGG( TBL_EXPR,','),',','\',\''),'^','\''),'$','\'')
'ABC%','ABC%'
and NOT IN is a exact match .. thus if we change from strings to numbers:
SELECT num, num in (2,3,4) FROM values (1),(3),(5) v(num);
gives:
NUM NUM IN (2,3,4)
1 0
3 1
5 0
so your NOT IN would only return strings that are not in the list of one you have... and given your list is the aggregate of the same input, that are by definition not that same.
back to strings..
SELECT str
,str in ('str_a', 'str_b')
,str not in ('str_a', 'str_b')
from values ('a'),('str_b') v(str);
gives:
STR STR IN ('STR_A', 'STR_B') STR NOT IN ('STR_A', 'STR_B')
a 0 1
str_b 1 0
Thus the results you are getting..
now I suspect you are want LIKE type behavior OR a REGEX match, but given you are building the list you know what you are doing there..
also note:
listagg(tbl_expr,',') AS a
,replace(a,',','\',\'') AS b
,regexp_replace(b,'^','\'') AS c
,regexp_replace(c,'$','\'') AS d
is the effect of what you are doing can be replaced with
listagg('\'' || tbl_expr || '\'',',')
unless you want strings with embedded comma to become independent "list" items..

Where x character equal value

How can I select records where in the column Value the 5th character is letter A?
For example the following records:
ID Value
-------------------------
1 1234A5636A6363
2 1234A4343B6363
3 1234B5353A6363
if I run
select * from table
where Value like '%A%'
this will return all records
but all I want is the first 2 where the 5th character is A, regardless if there are more A characters in the text or not
select *
from your_table
where substring(Value, 5, 1) = 'A'
The LIKE operator, in addition to %, which matches any number of any character, can use _, which matches any one single character. You may try:
SELECT *
FROM yourTable
WHERE Value LIKE '____A%'; -- 4 underscores here
use like below by using _(underscore)
LIKE '____A%'
SQL Server
select *
from YourTableName
where CHARINDEX('A', ColumnName) = 5
Note:- This finds where string 'A' starts at position 5
AND specify Your ColumnName

Deleting records with number repeating more than 5

I have data in a table of length 9 where data is like
999999969
000000089
666666689
I want to delete only those data in which any number from 1-9 is repeating more than 5 times.
OK, so the logic here can be summed up as:
Find the longest series of the same consecutive digit in any given number; and
Return true if that longest value is > 5 digits
Right?
So, lets split it into series of consecutive digits:
regress=> SELECT regexp_matches('666666689', '(0+|1+|2+|3+|4+|5+|6+|7+|8+|9+)', 'g');
regexp_matches
----------------
{6666666}
{8}
{9}
(3 rows)
then filter for the longest:
regress=>
SELECT x[1]
FROM regexp_matches('6666666898', '(0+|1+|2+|3+|4+|5+|6+|7+|8+|9+)', 'g') x
ORDER BY length(x[1]) DESC
LIMIT 1;
x
---------
6666666
(1 row)
... but really, we don't actually care about that, just if any entry is longer than 5 digits, so:
SELECT x[1]
FROM regexp_matches('6666666898', '(0+|1+|2+|3+|4+|5+|6+|7+|8+|9+)', 'g') x
WHERE length(x[1]) > 5;
can be used as an EXISTS test, e.g.
WITH blah(n) AS (VALUES('999999969'),('000000089'),('666666689'),('15552555'))
SELECT n
FROM blah
WHERE EXISTS (
SELECT x[1]
FROM regexp_matches(n, '(0+|1+|2+|3+|4+|5+|6+|7+|8+|9+)', 'g') x
WHERE length(x[1]) > 5
)
which is actually pretty efficient and return the correct result (always nice). But it can be simplified a little more with:
WITH blah(n) AS (VALUES('999999969'),('000000089'),('666666689'),('15552555'))
SELECT n
FROM blah
WHERE EXISTS (
SELECT x[1]
FROM regexp_matches(n, '(0{6}|1{6}|2{6}|3{6}|4{6}|5{6}|6{6}|7{6}|8{6}|9{6})', 'g') x;
)
You can use the same WHERE clause in a DELETE.
This can be much simpler with a regular expression using a back reference.
DELETE FROM tbl
WHERE col ~ '([1-9])\1{5}';
That's all.
Explain
([1-9]) ... a character class with digits from 1 to 9, parenthesized for the following back reference.
\1 ... back reference to first (and only in this case) parenthesized subexpression.
{5} .. exactly (another) 5 times, making it "more than 5".
Per documentation:
A back reference (\n) matches the same string matched by the previous
parenthesized subexpression specified by the number n [...] For example, ([bc])\1 matches bb or cc but not bc or cb.
SQL Fiddle demo.
Horrible and terrible in terms of performance, but it should work:
DELETE FROM YOURTABLE
WHERE YOURDATA LIKE '%111111%'
OR YOURDATA LIKE '%222222%'
OR YOURDATA LIKE '%333333%'
OR YOURDATA LIKE '%444444%'
OR YOURDATA LIKE '%555555%'
OR YOURDATA LIKE '%666666%'
OR YOURDATA LIKE '%777777%'
OR YOURDATA LIKE '%888888%'
OR YOURDATA LIKE '%999999%'

select where string doesn't match exactly

It's my table rows:
++ id ---- text ++++++++++++++
-- 1 ---- '90','80,'50' -----
-- 2 ---- '30','2','1_2' --
-- 3 ---- '10_2','5_3' -----
as you see, text contains 2 types of numbers, one doesn't have underscore, and the other does.
I want to select rows which have at least one number without underscore (type 1). Something like this: (result-set)
++ id ---- text ++++++++++++++
-- 1 ---- '90','80,'50' -----
-- 2 ---- '30','2','1_2' --
(3 is ignored)
How to do that? (I think it's possible with NOT LIKE, but I don't know how to write)
How long may be your numbers? Try this:
SELECT t1.id,t1.txt FROM t t1, t t2 WHERE t1.txt LIKE "%'__'%" AND t2.txt NOT LIKE "%\__',%"
The below query counts the number of commas in the strings, number of distinct numbers can be calculated as 1 more than the number of commas as the numbers are separated by commas, number of underscores in the string:
select id,
len(text) - len(replace(text,',','')) as count_of_commas,
len(text) - len(replace(text,',','')) + 1 as count_of_number,
len(text) - len(replace(text,'_','')) as count_of_underscore,
len(text) - len(replace(text,',','')) + 1 - (len(text) - len(replace(text,'_',''))) as zero_if_no_number_without_underscore_exists
from t1
The above query gives the following results:
Now using the logic of above query, following query can be used to get the desired result:
select * from t1
where len(text) - len(replace(text,',','')) + 1 - (len(text) - len(replace(text,'_',''))) != 0
i.e. it returns the rows where atleast one number exists without the underscore.
You can't do it with LIKE, but you can with a RLIKE, which uses regular expressions:
select * from mytable
where `text` rlike "'\d+_\d+'"

Select only integers from char column using SQL Server

How can I write a select statement to select only integers (and nothing more) from a char column in SQL Server. For example, my table name is POWDER with 2 columns, ID (int) and Name(char (5))
ID Name
-- ----------
1 AXF22
2 HYWWW
3 24680
4 8YUH8
5 96635
I want to be able to select only those rows that contain an integer and nothing more (ID 3 and ID 5 in this example)
If I try:
SELECT *
FROM POWDER
WHERE Name LIKE '[0-9]%'
...it will return:
ID Name
-- ----------
3 24680
4 8YUH8
5 96635
Any ideas how to get the rows containing just integers?
SELECT * FROM POWDER WHERE IsNumeric(Name) = 1
IsNumeric returns 1 for some other characters that are valid in numbers, such as + and - and $ but for your input you should be fine.
Try this:
SELECT * FROM Table WHERE Name LIKE '[0-9]%%'
To avoid issues with ISNUMERIC and all spaces, -, +, . etc, use the fact that the column is char(5)
SELECT *
FROM POWDER
WHERE Name LIKE '[0-9][0-9][0-9][0-9][0-9]'
Edit: for any number of characters. Double negative...
SELECT *
FROM POWDER
WHERE Name NOT LIKE '%[^0-9]%'
Use positive and negative checks to make sure we have an integer: It must contain a digit. Only digits and spaces are allowed. No spaces are allowed between digits.
SELECT *
FROM POWDER
WHERE Name LIKE '%[0-9]%'
AND Name NOT LIKE '%[^0-9 ]%'
AND Name NOT LIKE '%[0-9]% %[0-9]%'
Try:
SELECT *
FROM POWDER
WHERE Name patindex ('%[a-z]%',name) != 0
The last one is the best,kind of works really really well.
SELECT * FROM POWDER
WHERE Name LIKE '%[0-9]%'
AND Name NOT LIKE '%[^0-9 ]%'
AND Name NOT LIKE '%[0-9]% %[0-9]%'