LIKE with Multiple Consecutive White Spaces - sql

I have following query with LIKE predicate in SQL Server 2012. It replaces white spaces with %. I have two records in the table.
DECLARE #MyTable TABLE (ITMEID INT, ITMDESC VARCHAR(100))
INSERT INTO #MyTable VALUES (1,'Healty and Alive r')
INSERT INTO #MyTable VALUES (2, 'A liver patient')
DECLARE #SearchCriteria VARCHAR(100)
SET #SearchCriteria = 'Alive'
SELECT *
FROM #MyTable
WHERE (ITMDESC LIKE '%'+REPLACE(#SearchCriteria,' ','%')+'%' ESCAPE '\')
I got this query from a friend to consider multiple consequent white spaces as a single space. The challenge is I don't see any reference for this.
Is there a pitfall in the approach?

REPLACE(#SearchCriteria,' ','%') always returns Alive. There is no Alive word in the second row, therefore it's not returned.
In fact, WHERE clause will look like this: WHERE (ITMDESC LIKE '%Alive%' ESCAPE '\')
The second row doesn't meet it.
Probably, you want something like this:
SELECT *
FROM #MyTable
WHERE (REPLACE(ITMDESC,' ','') LIKE '%'+#SearchCriteria+'%' ESCAPE '\')

you can use as below
DECLARE #MyTable TABLE (ITMEID INT, ITMDESC VARCHAR(100))
INSERT INTO #MyTable VALUES (1,'Healty and Alive r')
INSERT INTO #MyTable VALUES (2, 'A liver patient')
ECLARE #SearchCriteria VARCHAR(100)
SET #SearchCriteria = 'Alive'
SELECT *
FROM #MyTable
WHERE (REPLACE(ITMDESC,' ','') LIKE '%'+#SearchCriteria+'%' ESCAPE '\')
it will return both records as you want

The simplest solution is to replace all spaces with some moniker and then replace that moniker with a single space.
Select Replace(Replace(ItmDesc, ' ', '<z>'), '<z>', ' ')
From MyTable
SQL Fiddle version

Related

'LIKE' issues with FLOAT: SQL query needed to find values >= 4 decimal places

I have a conundrum....
There is a table with one NVARCHAR(50) Float column that has many rows with many numbers of various decimal lengths:
'3304.063'
'3304.0625'
'39.53'
'39.2'
I need to write a query to find only numbers with decimal places >= 4
First the query I wrote was:
SELECT
Column
FROM Tablename
WHERE Column LIKE '%.[0-9][0-9]%'
The above code finds all numbers with decimal places >= 2:
'3304.063'
'3304.0625'
'39.53'
Perfect! Now, I just need to increase the [0-9] by 2...
SELECT
Column
FROM Tablename
WHERE Column LIKE '%.[0-9][0-9][0-9][0-9]%'
this returned nothing! What?
Does anyone have an explanation as to what went wrong as well and/or a possible solution? I'm kind of stumped and my hunch is that it is some sort of 'LIKE' limitation..
Any help would be appreciated!
Thanks.
After your edit, you stated you are using FLOAT which is an approximate value stored as 4 or 8 bytes, or 7 or 15 digits of precision. The documents explicitly state that not all values in the data type range can be represented exactly. It also states you can use the STR() function when converting it which you'll need to get your formatting right. Here is how:
declare #table table (columnName float)
insert into #table
values
('3304.063'),
('3304.0625'),
('39.53'),
('39.2')
--see the conversion
select * , str(columnName,20,4)
from #table
--now use it in a where clause.
--Return all values where the last digit isn't 0 from STR() the conversion
select *
from #table
where right(str(columnName,20,4),1) != 0
OLD ANSWER
Your LIKE statement would do it, and here is another way just to show they both work.
declare #table table (columnName varchar(64))
insert into #table
values
('3304.063'),
('3304.0625'),
('39.53'),
('39.2')
select *
from #table
where len(right(columnName,len(columnName) - charindex('.',columnName))) >= 4
select *
from #table
where columnName like '%.[0-9][0-9][0-9][0-9]%'
One thing that could be causing this is a space in the number somewhere... since you said the column type was VARCHAR this is a possibility, and could be avoided by storing the value as DECIMAL
declare #table table (columnName varchar(64))
insert into #table
values
('3304.063'),
('3304. 0625'), --notice the space here
('39.53'),
('39.2')
--this would return nothing
select *
from #table
where columnName like '%.[0-9][0-9][0-9][0-9]%'
How to find out if this is the case?
select *
from #table
where columnName like '% %'
Or, anything but numbers and decimals:
select *
from #table
where columnName like '%[^.0-9]%'
The following is working fine for me:
declare #tab table (val varchar(50))
insert into #tab
select '3304.063'
union select '3304.0625'
union select '39.53'
union select '39.2'
select * from #tab
where val like '%.[0-9][0-9][0-9][0-9]%'
Assuming your table only has numerical data, you can cast them to decimal and then compare:
SELECT COLUMN
FROM tablename
WHERE CAST(COLUMN AS DECIMAL(19,4)) <> CAST(COLUMN AS DECIMAL(19,3))
You'd want to test the performance of this against using the character data type solutions that others have already suggested.
You can use REVERSE:
declare #vals table ([Val] nvarchar(50))
insert into #vals values ('3304.063'), ('3304.0625'), ('39.53'), ('39.2')
select [Val]
from #Vals
where charindex('.',reverse([Val]))>4

Find text of a column in other column with T-SQL

I have a doubt to find text from one column in a table; in other column from other table.
Imagine that you have this columns:
And you want to find the COMPLETE text of [A].X in [B].Y
And to discover where do you have the match. The colour yellow show this choice:
I have been thinking to use the "CONTAINS" function, but I think that it could be not the best idea. Because you have to write the text that you need to find (instead of a complete text of a column).
CONTAINS T-SQL
I thought that it could be like this:
Use AdventureWorks2012;
GO
SELECT [B].Y
FROM Production.Product
WHERE CONTAINS(([A].Y), [A].X);
But it doesn't work.
Which is the best option?
I am using SQL SERVER V17.0
Thanks!!!
I would go for like:
select b.y, a.x
from b join
a
on b.y like '%' + a.x + '%' ;
There is not, however, a really efficient way to do this logic in SQL Server.
Here is a quick example searching a list of strings for a particular set of words defined in another table. This example just searches through the system error messages text and looks for the words 'overflow' and 'CryptoAPI', but you'll substitute the words table with your 'A' and the 'sys.messages' table with your table 'B'
NOTE: this isn't the most efficient way to search large amounts of text.
-- CREATE TEMP TABLE WITH WORDS TO MATCH
CREATE TABLE #words (
[Word] nvarchar(100)
)
-- SAMPLE STRINGS
INSERT INTO #words VALUES ('overflow')
INSERT INTO #words VALUES ('CryptoAPI')
-- SEARCH THROUGH SYSTEM ERROR MESSAGES FOR SAMPLE STRINGS
SELECT [W].[Word] AS 'Matched word'
, [M].[text]
FROM [sys].[messages] AS [M]
JOIN #words AS [W]
ON [M].[text] LIKE '%' + [W].[Word] + '%'
CREATE TABLE #TempA
(ColumnX VARCHAR(10)
);
CREATE TABLE #TempB
(ColumnY VARCHAR(100)
);
INSERT #TempA
VALUES('fish'),('burguer'),('sugar'),('tea'),('coffee'),('window'),('door');
INSERT #TempB
VALUES('I like potatoes'),('I eat sugar'),('I eat sugar with onions'), ('I have a car'),('I don''t like dogs');
SELECT *
FROM #TempB b
WHERE EXISTS(SELECT 1 FROM #TempA a WHERE CHARINDEX(a.ColumnX, b.ColumnY,1) > 0);
I agree with #GordonLinoff. Like is what i would also go for but i want to make one improvement in the answer provided.
CREATE TABLE #TempA (ColumnX VARCHAR(10));
CREATE TABLE #TempB (ColumnY VARCHAR(100));
INSERT #TempA
VALUES ('fish')
,('burguer')
,('sugar')
,('tea')
,('coffee')
,('window')
,('door');
INSERT #TempB
VALUES ('I steam potatoes')
, ('I like potatoes')
,('I eat sugar')
,('I eat sugar with onions')
,('I have a car coffee')
,('I don''t like dogs')
,('Window is clean')
,('Open the door')
;
SELECT b.ColumnY
,a.ColumnX
FROM #TempB b
INNER JOIN #TempA a ON ' '+ b.ColumnY + ' ' LIKE '% ' + a.ColumnX + ' %'
This will take care of the TEA to be not found in STEAM.

How to manipulate comma-separated list in SQL Server

I have a list of values such as
1,2,3,4...
that will be passed into my SQL query.
I need to have these values stored in a table variable. So essentially I need something like this:
declare #t (num int)
insert into #t values (1),(2),(3),(4)...
Is it possible to do that formatting in SQL Server? (turning 1,2,3,4... into (1),(2),(3),(4)...
Note: I can not change what those values look like before they get to my SQL script; I'm stuck with that list. also it may not always be 4 values; it could 1 or more.
Edit to show what values look like: under normal circumstances, this is how it would work:
select t.pk
from a_table t
where t.pk in (#place_holder#)
#placeholder# is just a literal place holder. when some one would run the report, #placeholder# is replaced with the literal values from the filter of that report:
select t.pk
from a_table t
where t.pk in (1,2,3,4) -- or whatever the user selects
t.pk is an int
note: doing
declare #t as table (
num int
)
insert into #t values (#Placeholder#)
does not work.
Your description is a bit ridicuolus, but you might give this a try:
Whatever you mean with this
I see what your trying to say; but if I type out '#placeholder#' in the script, I'll end up with '1','2','3','4' and not '1,2,3,4'
I assume this is a string with numbers, each number between single qoutes, separated with a comma:
DECLARE #passedIn VARCHAR(100)='''1'',''2'',''3'',''4'',''5'',''6'',''7''';
SELECT #passedIn; -->: '1','2','3','4','5','6','7'
Now the variable #passedIn holds exactly what you are talking about
I'll use a dynamic SQL-Statement to insert this in a temp-table (declared table variable would not work here...)
CREATE TABLE #tmpTable(ID INT);
DECLARE #cmd VARCHAR(MAX)=
'INSERT INTO #tmpTable(ID) VALUES (' + REPLACE(SUBSTRING(#passedIn,2,LEN(#passedIn)-2),''',''','),(') + ');';
EXEC (#cmd);
SELECT * FROM #tmpTable;
GO
DROP TABLE #tmpTable;
UPDATE 1: no dynamic SQL necessary, all ad-hoc...
You can get the list of numbers as derived table in a CTE easily.
This can be used in a following statement like WHERE SomeID IN(SELECT ID FROM MyIDs) (similar to this: dynamic IN section )
WITH MyIDs(ID) AS
(
SELECT A.B.value('.','int') AS ID
FROM
(
SELECT CAST('<x>' + REPLACE(SUBSTRING(#passedIn,2,LEN(#passedIn)-2),''',''','</x><x>') + '</x>' AS XML) AS AsXml
) as tbl
CROSS APPLY tbl.AsXml.nodes('/x') AS A(B)
)
SELECT * FROM MyIDs
UPDATE 2:
And to answer your question exactly:
With this following the CTE
insert into #t(num)
SELECT ID FROM MyIDs
... you would actually get your declared table variable filled - if you need it later...

SQL Find Replacement Character as a part of a string

I need help with writing a query which will find Replacement Character in SQL table.
I have multiple cells which contain that character and I want to find all those cells. This is how the value of cell looks like this:
Thank you for your help!
The UNICODE suggestion didn't work for me - the � character was being treated as a question mark, so the query was finding all strings with question marks, but not those with �.
The fix posted by Tom Cooper at this link worked for me: https://social.msdn.microsoft.com/forums/sqlserver/en-US/2754165e-7ab7-44b0-abb4-3be487710f31/black-diamond-with-question-mark
-- Find rows with the character
Select * From [MyTable]
Where CharIndex(nchar(65533) COLLATE Latin1_General_BIN2, MyColumn) > 0
-- Update rows replacing character with a !
Update [MyTable]
set MyColumn = Replace(MyColumn, nchar(65533) COLLATE Latin1_General_BIN2, '!')
Use the Unicode function:
DECLARE #TEST TABLE (ID INT, WORDS VARCHAR(10))
INSERT INTO #TEST VALUES (1, 'A�AA')
INSERT INTO #TEST VALUES (2, 'BBB')
INSERT INTO #TEST VALUES (3, 'CC�C')
INSERT INTO #TEST VALUES (4, 'DDD')
SELECT * FROM #TEST WHERE WORDS LIKE '%' + NCHAR(UNICODE('�')) + '%'
UPDATE #TEST
SET WORDS = REPLACE(WORDS, NCHAR(UNICODE('�')), 'X')
SELECT * FROM #TEST WHERE WORDS LIKE '%' + NCHAR(UNICODE('�')) + '%'
SELECT * FROM #TEST
In Sql you can able to replace the black diamond symbol.
Input : You�ll be coached through alternating
Output : You will be coached through alternating
select replace(description, nchar(65533) COLLATE Latin1_General_BIN2,' wi') from [Fitnesstable]
where description LIKE '%' + '. You'+NCHAR(55296) +'ll'+ '%'
Try the following code to search the query for the character you wish to find.
select field_name from tbl_name where instr(field_name, 'charToBeSearched') > 0;
This query will find and selects the records which has replacement character.

Look for trailing spaces in a table

I'd like to know how I can identify trailing spaces in a table. I'm using SQL Server 2008 and create the following table as a test
CREATE TABLE first_test_name
(
firstName varchar(255)
)
And then inserted a record like this:
insert into first_test_name (firstName)
values('Bob')
I then tried inserting a space and then adding a new record like this:
insert into first_test_name (firstName)
values('Bob ') -- just 1 space
And for a 3rd time,
insert into first_test_name (firstName)
values('Bob ') -- two spaces used this time.
Now if I query for for 'Bob' (no spaces), I still get a count of 3.
My query was:
select count(*) from first_test_name WHERE firstName = 'Bob'
Shouldn't the answer have been 1?
Also, I used sp_help on this table and the value for "Trim Trailing Blanks" is set to no.
So why am I getting a count of 3? I was expecting just 1.
On a related note, if I search using this query
select * from first_test_name
where firstName like '% '
I then get the right answer of two rows found.
So just to reiterate, the question is why I get a count of 3 when searching for 'Bob'.
Also, what does "Trim Trailing Blanks" mean in this case?
Why I get a count of 3 when searching for 'Bob'?
SQL Server ignores trailing spaces in most string comparisons.
Also, what does "Trim Trailing Blanks" mean in this case?
This tells you the ANSI_PADDING option set when the table was created.
How can I identify those two with 1 or 2 trailing spaces?
Here's one way.
SELECT *
FROM first_test_name
WHERE firstName LIKE 'Bob '
And to find ones with no trailing space
SELECT *
FROM first_test_name
WHERE firstName LIKE 'Bob' AND firstName NOT LIKE 'Bob '
SQL Server will expand strings with whitespace during comparisons.
This is what I would do:
SELECT COUNT(*)
FROM first_test_name
WHERE REPLACE(firstName, ' ', '_') = 'Bob'
SELECT *
FROM USERS
WHERE DATALENGTH(Username) <> DATALENGTH(RTrim(Username))
Another way might be to append something on the string.
declare #test table(
id varchar(4) not null,
firstname varchar(255) not null)
insert into #test values('1', 'Bob')
insert into #test values('2', 'Bob ')
insert into #test values('3', 'Bob ')
insert into #test values('4', ' Bob')
select count((firstname + 'end')) from #test
where (firstname + 'end') not like '% %'
The query will return a count of 1.
A good clean way to do this would be to compare your original string against an Rtrim version of itself where they don't match e.g.:
SELECT *
FROM First_Test_Name
WHERE Firstname <> RTrim(Firstname)
This should return all records where Firstname has trailing spaces (I think ...)
I was looking recently and couldn't find the answer to this. Thought I'd share since coming across one.
https://stackoverflow.com/a/14188944/1953837
LEN trims trailing whitespaces by default. Using the below they are moved to the front and then the field length is counted.
Hope this helps anyone searching in the future.
(LEN(REVERSE(FieldName))