split a column in two and sort in mssql - sql-server

I'm new to sql and i need to do this
in MSSQL:
I have a simple tble with userid, fullname,age and so on
where fullname is obviously firstname lastname like 'Adam Smith'
I need to sort the table according to surname only. Is there anyway?

If there's only 1 lastname then you could use the PARSENAME trick.
It's a function that's normally used to get a specified part from an object name.
For example to get '[mytable]' from '[myschema].[mydatabase].[mytable]'.
So it splits the string by the dot.
Your string has spaces.
When the spaces are replaced by dot, then it's easy to get the first element from the right via PARSENAME.
SELECT *
FROM yourtable
ORDER BY parsename(replace(fullname,' ','.'),1)
But do note that PARSENAME returns NULL when there's more than 4 elements.

You can use right with charindex and reverse to get the part of the string after the last space, like this:
First, create and populate sample table(Please save us this step in your future questions):
DECLARE #T AS TABLE
(
FullName nvarchar(100)
)
INSERT INTO #T(FullName) VALUES
(N'Zohar Peled'),
(N'Amir Shahbabaie'),
(N'Madona'),
(N'Gabriel José de la Concordia García Márquez')
The query:
SELECT *
FROM #T
ORDER BY RIGHT(FullName, CHARINDEX(' ',REVERSE(FullName)))
Results:
FullName
Madona
Gabriel José de la Concordia García Márquez
Zohar Peled
Amir Shahbabaie
As you can see, this will also work if your strings are not what you expect (and when dealing with names, they rarely are what you expect)

Related

Change wrong french characters on table

For some reason we found on the database characters like this: Ã
I can assume this character represent the character: é
Now I need to revise the whole table but checking all other characters to make sure there are no others.
Where I can find the relation of characters for example between this à and é? or probably find an SQL function that is already done to make those replacement.
I'm using SQL Server 2014
As mentioned by Daniel E, your dirty data might have been caused by the use of incorrect code pages (UTF-8 that was interpreted as ISO 8859-1).
One way to find entries with dirty data, is to use a "not exists" ("^") like expression with the list of valid characters in that expression. See example below.
declare #t table (name varchar(20))
insert into #t values ('touché')
insert into #t values ('encore touché')
insert into #t values ('reçu')
insert into #t values ('hello world')
select * from #t where name like '%[^a-zA-Z., -]%'
select * from #t where name like '%[^a-zA-Z.,èêé -]%' COLLATE Latin1_General_BIN

Separating Numeric Values from string

I'm having an issue, whereby I need to separate the following BPO007 to show BPO and 007. In some cases another example would be GFE0035, whereby I still need to split the numeric value from the characters.
When I do the following select isnumeric('BPO007') the result is 0, which is correct, however, I'm not sure how split these from each other.
I've had a look at this link, but it does not really answer my question.
I need the above split for a separate validation purpose in my trigger.
How would I develop something like this?
Thank you in advance.
As told in a comment before:
About your question How would I develop something like this?:
Do not store two pieces of information within the same column (read about 1.NF). You should keep separate columns in your database for BPO and for 007 (or rather an integer 7).
Then use some string methods to compute the BPO007 when you need it in your output.
Just not to let you alone in the rain.
DECLARE #tbl TABLE(YourColumn VARCHAR(100));
INSERT INTO #tbl VALUES('BPO007'),('GFE0035');
SELECT YourColumn,pos
,LEFT(YourColumn,pos) AS CharPart
,CAST(SUBSTRING(YourColumn,pos+1,1000) AS INT) AS NumPart
FROM #tbl
CROSS APPLY(SELECT PATINDEX('%[0-9]%',YourColumn)-1) AS A(pos);
Will return
YourColumn pos CharPart NumPart
BPO007 3 BPO 7
GFE0035 3 GFE 35
Hint: I use a CROSS APPLY here to compute the position of the first numeric character and then use pos in the actual query like you'd use a variable. Otherwise the PATINDEX would have to be repeated...
Since the number and text varies, you can use the following codes
DECLARE #NUMERIC TABLE (Col VARCHAR(50))
INSERT INTO #NUMERIC VALUES('BPO007'),('GFE0035'),('GFEGVT003509'),('GFEMTS10035')
SELECT
Col,
LEFT(Col,LEN(Col)-LEN(SUBSTRING(Col,PATINDEX('%[0-9]%',Col),DATALENGTH(Col)))) AS TEXTs,
RIGHT(Col,LEN(Col)-LEN(LEFT(Col,LEN(Col)-LEN(SUBSTRING(Col,PATINDEX('%[0-9]%',Col),DATALENGTH(Col)))))) AS NUMERICs
FROM #NUMERIC

how to separate and show data from one column?

I have a problem splitting single column values to multiple column values.
On this:
Name
------------
Tom Howard
Michael Black
Wiliam Cruise
Bet Moor
I need the output something like this:
first_name last_name
------------------------------
Tom Howard
Michael Black
Wiliam Cruise
Bet Moor
I have to show data(last_name) from one column(name).
Thank you
Depending on your version, you could use PARSENAME() or Substring()
Declare #YourTable table (Name varchar(50))
Insert into #YourTable values
('Tom Howard'),
('Michael Black'),
('Wiliam Cruise'),
('Bet Moor')
Select Name
,first_name=PARSENAME(Replace(Name,' ','.'),2)
,last_name =PARSENAME(Replace(Name,' ','.'),1)
From #YourTable
-- OR --
Select Name
,first_name=Substring(Name,1,charindex(' ',name)-1)
,last_name =Substring(Name,charindex(' ',name)+1,50)
From #YourTable
Returns
You can use the left and right function to find these items pretty quickly:
select Name, left(Name,charindex(' ',Name)-1) as first_name, right(Name,charindex(' ',Name)-1) as last_name from yourtable
As long as you have a single space in the Name field this should work fine, if you have more than one space then you will lose any data that is between the spaces.

Row numbers for a query in informix

I am using informix database, I want a query which you could also generate a row number along with the query
Like
select row_number(),firstName,lastName
from students;
row_number() firstName lastName
1 john mathew
2 ricky pointing
3 sachin tendulkar
Here firstName, lastName are from Database, where as row number is generated in a query.
The best way is to use a (newly initialized) sequence.
begin work;
create sequence myseq;
select myseq.nextval,s.firstName,s.lastName from students s;
drop sequence myseq;
commit work;
You may not be able to use ROWID in a table that's fragmented across multiple DBSpaces, so any solution that uses ROWID is not particularly portable. It's also strongly discouraged.
If you don't have a SERIAL column in your source table (which is a better way of implementing this as a general concept), have a look at
CREATE SEQUENCE, which is more or less the equivalent of an Orrible function that generates unique numbers when SELECTed from (as opposed to SERIAL, which generates the unique number when the row is INSERTed).
Given a table called Table3 with 3 columns:
colnum name datatype
======= ===== ===
1 no text;
2 seq number;
3 nm text;
NOTE:
seq is a field within the Table that has unique values in ascending order. The numbers do not have to be contiguous.
Here is query to return a rownumber (RowNum) along with query result
SELECT table3.no, table3.seq, Table3.nm,
(SELECT COUNT(*) FROM Table3 AS Temp
WHERE Temp.seq < Table3.seq) + 1 AS RowNum
FROM Table3;
I think the easiest way would be to use the following code and adjust its return accordingly.
SELECT rowid, * FROM table
It works for me but please note that it will return the row number in the database, not the row number in the query.
P.S. it's an accepted answer from Experts Exchange.
select sum(1) over (order by rowid) as row_number, M.* from systables M
I know its an old question, but since i just faced this problem and got a soultion not mentioned here, i tough i could share it, so here it is:
1- You need to create a FUNCTION that return numbers in a given range:
CREATE FUNCTION fnc_numbers_in_range (pMinNumber INT, pMaxNumber INT)
RETURNING INT as NUMERO;
DEFINE numero INT;
LET numero = 0;
FOR numero = pMinNumber TO pMaxNumber
RETURN numero WITH RESUME;
END FOR;
END FUNCTION;
2- You Cross the results of this Function with the table you want:
SELECT * FROM TABLE (fnc_numbers_in_range(0,10000)), my_table;
The only thing is that you must know before-hand the number of rows you want, you may get this with the COUNT(*) Function.
This works with my Informix Database, other implementations may need some tweaking.
Using OLAP expressions you need the OVER() with something in it, since you don't want partitions include a SORT clause, like this:
SELECT ROW_NUMBER() OVER(ORDER BY lastName, firstName) AS rn, firstName, lastName
FROM students;
and if you don't want to order by name, you could use the way records were entered in the system by ordering by ROWID.

SQL Server Full Text Searching

I'm currently working on an application where we have a SQL-Server database and I need to get a full text search working that allows us to search people's names.
Currently the user can enter a into a name field that searches 3 different varchar cols. First, Last, Middle names
So say I have 3 rows with the following info.
1 - Phillip - J - Fry
2 - Amy - NULL - Wong
3 - Leo - NULL - Wong
If the user enters a name such as 'Fry' it will return row 1. However if they enter Phillip Fry, or Fr, or Phil they get nothing.. and I don't understand why its doing this. If they search for Wong they get rows 2 and 3 if they search for Amy Wong they again get nothing.
Currently the query is using CONTAINSTABLE but I have switched that with FREETEXTTABLE, CONTAINS, and FREETEXT without any noticeable differences in the results. The table methods are be preferred because they return the same results but with ranking.
Here is the query.
....
#Name nvarchar(100),
....
--""s added to prevent crash if searching on more then one word.
DECLARE #SearchString varchar(100)
SET #SearchString = '"'+#Name+'"'
SELECT Per.Lastname, Per.Firstname, Per.MiddleName
FROM Person as Per
INNER JOIN CONTAINSTABLE(Person, (LastName, Firstname, MiddleName), #SearchString)
AS KEYTBL
ON Per.Person_ID = KEYTBL.[KEY]
WHERE KEY_TBL.RANK > 2
ORDER BY KEYTBL.RANK DESC;
....
Any Ideas...? Why this full text search is not working correctly ?
If you're just searching people's names, it might be in your best interest to not even use the full text index. Full text index makes sense when you have large text fields, but if you're mostly dealing with one word per field, I'm not sure how much extra you would get out of full text indexes. Waiting for the full text index to reindex itself before you can search for new records can be one of the many problems.
You could just make a query such as the following. Split your searchstring on spaces, and create a list of the search terms.
Select FirstName,MiddleName,LastName
From person
WHERE
Firstname like #searchterm1 + '%'
or MiddleName like #searchterm1 + '%'
or LastName like #searchterm1 + '%'
or Firstname like #searchterm2 + '%'
etc....
FreeTextTable should work.
INNER JOIN FREETEXTTABLE(Person, (LastName, Firstname, MiddleName), #SearchString)
#SearchString should contain the values like 'Phillip Fry' (one long string containing all of the lookup strings separated by spaces).
If you would like to search for Fr or Phil, you should use asterisk: Phil* and Fr*
'Phil' is looking for exactly the word 'Phil'. 'Phil*' is looking for every word which is starting with 'Phil'
Thanks for the responses guys I finally was able to get it to work. With part of both Biri, and Kibbee's answers. I needed to add * to the string and break it up on spaces in order to work. So in the end I got
....
#Name nvarchar(100),
....
--""s added to prevent crash if searching on more then one word.
DECLARE #SearchString varchar(100)
--Added this line
SET #SearchString = REPLACE(#Name, ' ', '*" OR "*')
SET #SearchString = '"*'+#SearchString+'*"'
SELECT Per.Lastname, Per.Firstname, Per.MiddleName
FROM Person as Per
INNER JOIN CONTAINSTABLE(Person, (LastName, Firstname, MiddleName), #SearchString)
AS KEYTBL
ON Per.Person_ID = KEYTBL.[KEY]
WHERE KEY_TBL.RANK > 2
ORDER BY KEYTBL.RANK DESC;
....
There are more fields being searched upon I just simplified it for the question, sorry about that, I didn't think it would effect the answer. It actually searches a column that has a csv of nicknames and a notes column as well.
Thanks for the help.
Another approach could be to abstract the searching away from the individual fields.
In other words create a view on your data which turns all the split fields like firstname lastname into concatenated fields i.e. full_name
Then search on the view. This would likely make the search query simpler.
You might want to check out Lucene.net as an alternative to Full Text.

Resources