Look for trailing spaces in a table - sql

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))

Related

How to search a full name in sql server database table with only firstname and lastname column?

We have a DB table, User with first_name, last_name columns but do not have a full_name column. We want to perform a search on the table, where the search query can contain the string which is a combination of both columns or one of them or simply a character. Search has to case insensitive.
Edit 1
The search needs to be fast enough as the request would be from a typeahead on a webclient.
The LIKE expressions by default are case insensitive. As #larnu suggested, adding a persistent column is a better way of going about it. And if you can do a prefix search on that, it will further speed things up. If those are not an option, try this to see if you can tolerate the performance:
SELECT CONCAT_WS (" ", first_name, last_name) full_name
FROM YourTable
WHERE CONCAT_WS (" ", first_name, last_name) LIKE '%some string%';
A db table and an example would be easier to work with, but the simple case, should be something like the query below
I would make sure the search string is converted to lower case.
Notice that such a query on a large scale database might not be that quick
SELECT
*
FROM
users u
WHERE
LOWER(CONCAT(u.first_name,u.last_name)) LIKE '%{#search_string_here}%'
If you're looking at the format of your search term being the same with a firstname[space]lastname combination, you could do something like the below:
SELECT *
FROM Names
WHERE LEFT([Firstname] + ' ' + [lastname], LEN(#searchname)) = #searchname
This would allow you to search by the length of your search name. An example of how this could work is below:
CREATE TABLE Names
(
firstname NVARCHAR(100),
lastname NVARCHAR(100)
)
INSERT INTO Names VALUES
('John', 'Smith'), ('Jane', 'Doe'), ('Harry', 'Potter')
DECLARE #searchname NVARCHAR(100)
--John (Fist Name match only)
SET #searchname = 'John'
SELECT *
FROM Names
WHERE LEFT([Firstname] + ' ' + [lastname], LEN(#searchname)) = #searchname
--Jane D (First name + Initial Last name)
SET #searchname = 'Jane D'
SELECT *
FROM Names
WHERE LEFT([Firstname] + ' ' + [lastname], LEN(#searchname)) = #searchname
--H (Single character only in correct order)
SET #searchname = 'H'
SELECT *
FROM Names
WHERE LEFT([Firstname] + ' ' + [lastname], LEN(#searchname)) = #searchname
You can use this query:
SELECT first_name,last_name, CONCAT(CONCAT(first_name,' '),last_name) full_name
FROM User_table WHERE CONCAT(CONCAT(first_name,' '),last_name) LIKE '%string%'
Or:
SELECT first_name,last_name, CONCAT(first_name,last_name) full_name
FROM User_table WHERE CONCAT(fistName,lastName) LIKE '%string%'
For example, I create a table like you, and run this query get the result you want.
TB3:
Restult1:
Restult2:
Hope this helps.

How to apply trim function inside this query [duplicate]

Below is simple sql query to select records using in condition.
--like this I have 6000 usernames
select * from tblUsers where Username in ('abc ','xyz ',' pqr ',' mnop ' );
I know there are LTrim & Rtrim in sql to remove the leading trailing spaces form left & right respectively.
I want to remove the spaces from left & right in all the usernames that I am supplying to the select query.
Note:-
I want to trim the values that I am passing in the in clause.(I don't want to pass LTrim & RTrim to each value passed).
There are no trailing space in the records but value that I am passing in the clause is copied from excel & then pasted in Visual Studio. Then using ALT key I put '(single quote) at the left & right sides of the string. Due to this some strings has spaces in the right side trailing.
How to use the trim function in the select query?
I am using MS SQL Server 2012
If I understand your question correctly you are pasting from Excel into an IN clause in an adhoc query as below.
The trailing spaces don't matter. It will still match the string foo without any trailing spaces.
But you need to ensure that there are no leading spaces.
As the source of the data is Excel why not just do it all there?
You can use formula
= CONCATENATE("'",TRIM(SUBSTITUTE(A1,"'","''")),"',")
Then copy the result (from column B in the screenshot above) and just need to trim off the extra comma from the final entry.
You can do like this:
select * from tblUsers where LTRIM(RTRIM(Username)) in (ltrim(rtrim('abc')),ltrim(rtrim('xyz')),ltrim(rtrim('pqr')),ltrim(rtrim('mnop')));
However, if you have permission to update the database. Please remove all the spaces in your Username field. It is really not good to do the query like this.
One way to tackle your problem and still be able to benefit from an index on username is to use a persisted computed column:
Setup
-- drop table dbo.tblUsers
create table dbo.tblUsers
(
UserId INT NOT NULL IDENTITY(1, 1) CONSTRAINT PK_UserTest PRIMARY KEY,
Username NVARCHAR(64) NOT NULL,
UsernameTrimmed AS LTRIM(RTRIM(Username)) PERSISTED
)
GO
-- other columns may be included here with INCLUDE (col1, col2)
CREATE INDEX IDX_UserTest ON dbo.tblUsers (UsernameTrimmed)
GO
insert into dbo.tblUsers (Username) VALUES ('abc '),('xyz '),(' pqr '), (' mnop '), ('abc'), (' useradmin '), ('etc'), (' other user ')
GO
-- some mock data to obtain a large number of records
insert into dbo.tblUsers (Username)
select top 20000 SUBSTRING(text, 1, 64) from sys.messages
GO
Test
-- this will use the index (index seek)
select * from tblUsers where UsernameTrimmed in (LTRIM(RTRIM('abc')), LTRIM(RTRIM(' useradmin ')));
This allows for faster retrievals at the expense of extra space.
In order to get rid of query construction (and the ugliness of many LTRIMs and RTRIMs), you can push searched users in a table that looks like tblUsers.
create table dbo.searchedUsers
(
Username NVARCHAR(64) NOT NULL,
UsernameTrimmed AS LTRIM(RTRIM(Username)) PERSISTED
)
GO
Push raw values into dbo.searchedUsers.Username column and the query should look like this:
select U.*
from tblUsers AS U
join dbo.searchedUsers AS S ON S.UsernameTrimmed = U.UsernameTrimmed
The big picture
It is way better to properly trim your data in the service layer of your application (C#) so that future clients of your table may rely on decent information. So, trimming should be performed both when inserting information into tblUsers and when searching for users (IN values)
select *
from tblUsers
where RTRIM(LTRIM(Username)) in ('abc','xyz','pqr','mnop');
Answer: SELECT * FROM tblUsers WHERE LTRIM(RTRIM(Username)) in ('abc','xyz','pqr','mnop');
However, please note that if you have functions in your WHERE clause it defeats the purpose of having an indexes on that column and will use a
scan than a seek.
I would propose you clean your data before inserting into tblUsers
I think you can try this:
Just replace the table2 with you table name form where you are getting the username
select * from tblUsers where Username in ((select distinct
STUFF((SELECT distinct ', ' + RTRIM(LTRIM(t1.Username))
from table2 t1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,2,'') UserName
from table2 t) );
I'd do it in two step:
1) populate a temp table with all your strings with blanks
2) do a select with a subselect
create table a (a char(1))
insert into a values('a')
insert into a values('b')
insert into a values('c')
insert into a values('d')
create table #b (atmp char(5))
insert into #b values ('a ')
insert into #b values (' b')
insert into #b values (' c ')
select * from a where a in (select ltrim(rtrim(atmp)) from #b)

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.

LIKE with Multiple Consecutive White Spaces

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

String manipulation SQL

I have a row of strings that are in the following format:
'Order was assigned to lastname,firsname'
I need to cut this string down into just the last and first name but it is always a different name for each record.
The 'Order was assigned to' part is always the same.......
Thanks
I am using SQL Server. It is multiple records with different names in each record.
In your specific case you can use something like:
SELECT SUBSTRING(str, 23) FROM table
However, this is not very scalable, should the format of your strings ever change.
If you are using an Oracle database, you would want to use SUBSTR instead.
Edit:
For databases where the third parameter is not optional, you could use SUBSTRING(str, 23, LEN(str))
Somebody would have to test to see if this is better or worse than subtraction, as in Martin Smith's solution but gives you the same result in the end.
In addition to the SUBSTRING methods, you could also use a REPLACE function. I don't know which would have better performance over millions of rows, although I suspect that it would be the SUBSTRING - especially if you were working with CHAR instead of VARCHAR.
SELECT REPLACE(my_column, 'Order was assigned to ', '')
For SQL Server
WITH testData AS
(
SELECT 'Order was assigned to lastname,firsname' as Col1 UNION ALL
SELECT 'Order was assigned to Bloggs, Jo' as Col1
)
SELECT SUBSTRING(Col1,23,LEN(Col1)-22) AS Name
from testData
Returns
Name
---------------------------------------
lastname,firsname
Bloggs, Jo
on MS SQL Server:
declare #str varchar(100) = 'Order was assigned to lastname,firsname'
declare #strLen1 int = DATALENGTH('Order was assigned to ')
declare #strLen2 int = len(#str)
select #strlen1, #strLen2, substring(#str,#strLen1,#strLen2),
RIGHT(#str, #strlen2-#strlen1)
I would require that a colon or some other delimiter be between the message and the name.
Then you could just search for the index of that character and know that anything after it was the data you need...
Example with format changing over time:
CREATE TABLE #Temp (OrderInfo NVARCHAR(MAX))
INSERT INTO #Temp VALUES ('Order was assigned to :Smith,Mary')
INSERT INTO #Temp VALUES ('Order was assigned to :Holmes,Larry')
INSERT INTO #Temp VALUES ('New Format over time :LootAt,Me')
SELECT SUBSTRING(OrderInfo, CHARINDEX(':',OrderInfo)+1, LEN(OrderInfo))
FROM #Temp
DROP TABLE #Temp