Function to check for NULL and concatenating the strings - sql

I have a SQL statement that concatenates First Name and Last Name of the person. I use the following SQL statement.
ISNULL(FullName.FirstName, '') + ' ' + ISNULL(FullName.LastName, '')
What I need is to change this to add the FirstName and LastName only if they are not both NULL. If one of them is not NULL, use that value.
Examples:
FirstName and LastName are NULL -> NULL
FirstName is John and LastName is NULL -> John
FirstName is NULL and LastName is Doe -> Doe
-> indicates the result

Use CONCAT() to concatenate without any NULL issues
TRIM() to remove any spaces for when one or both fields are missing
NULLIF() to replace '' with NULL if first and last name are both
missing
SQL Server 2017+ Solution
DROP TABLE IF EXISTS #emp
CREATE TABLE #emp (ID INT IDENTITY(1,1), FirstName VARCHAR(25), LastName VARCHAR(25));
INSERT INTO #emp
VALUES(null,null)
,('John',null)
,('Doe',null)
,('John', 'Doe');
SELECT FullName = NULLIF(TRIM(CONCAT(FirstName,' ',LastName)),'')
,*
FROM #emp

Actually if you just wrap you current expression inside TRIM() it should give you the behavior you want:
SELECT TRIM(ISNULL(FullName.FirstName, '') + ' ' +
ISNULL(FullName.LastName, '')) AS FullName
FROM yourTable;
In the event that only the first or last name be present, your original expression would leave a dangling leading/trailing space. The call to TRIM() fixes that by removing this extra space.

You can use simple case statement to solve this:
create table emp (emp_id int4, fname varchar(10), lname varchar(10));
insert into emp (emp_id) values(1);
insert into emp (emp_id,fname) values(2, 'John');
insert into emp (emp_id,lname) values(3, 'Doe');
insert into emp (emp_id,fname,lname) values(4, 'John', 'Doe');
select emp_id,fname, lname,
case
WHEN FNAME is not null and LNAME is not null then
FNAME||' '||LNAME
WHEN FNAME is not null and LNAME is NULL then
FNAME
WHEN FNAME is null and LNAME is not NULL then
LNAME
else null
end as FULL_NAME
from emp;

A better SQL Server 2017 solution:
Use the new CONCAT_WS function, which concatenates with a separator, ignoring nulls
CREATE TABLE #emp (ID INT IDENTITY(1,1), FirstName VARCHAR(25), LastName VARCHAR(25));
INSERT INTO #emp
VALUES(null,null)
,('John',null)
,('Doe',null)
,('John', 'Doe');
SELECT FullName = CONCAT_WS(' ', FirstName, LastName)
,*
FROM #emp;
db<>fiddle

Related

How to update a column supposed to be only numbers

I want to transform the values of a column in my table which is supposed to contain only numbers. It is the "TEL" column.
This column currently has special characters and spaces. I need to filter this.
The additional constraint is that if the very first character (only the first character) is a "+" I would have to transform the + into "00"
You will find below an example of what is expected.
Could you please help me to create such a query?
CREATE TABLE PersonsInitial (
tel varchar(255),
firstname varchar(255),
lastname varchar(255)
);
insert into PersonsInitial(tel,firstname,lastname) values
('+41/ jfakl2 eaf3efa54844','Manu','Johns'),
('01-afe fa-e8fa5a +e5+ e+234','Fernand','Wajk'),
(' +41/34 jfakl2 eaf3efa54844','Fred','Johns')
;
select tel, firstname, lastname from PersonsInitial
--if there is a person with the same tel number chose the customer id with 'C'
--if I don't have the choice add the customer without C
CREATE TABLE PersonsFinal (
tel varchar(255),
firstname varchar(255),
lastname varchar(255))
;
insert into PersonsFinal(tel,firstname,lastname) values
('00412354844','Manu','Johns'),
('01855234','Fernand','Wajk'),
('0041342354844','Fred','Johns')
;
select tel, firstname, lastname from PersonsFinal
Example
You can add a User-Defined Function for this.
For example:
CREATE FUNCTION dbo.fnCleanTel (#Input VARCHAR(255))
RETURNS VARCHAR(255)
AS
BEGIN
DECLARE #Output VARCHAR(255) = LTRIM(RTRIM(#Input));
IF LEFT(#Output, 1) = '+'
SET #Output = STUFF(#Output,1,1,'00');
WHILE PATINDEX('%[^0-9]%', #Output) > 0
SET #Output = REPLACE(#Output, SUBSTRING(#Output,PATINDEX('%[^0-9]%',#Output),1),'');
RETURN #Output;
END;
CREATE TABLE PersonsFinal (
tel varchar(255),
firstname varchar(255),
lastname varchar(255)
);
insert into PersonsFinal (tel, firstname, lastname)
select dbo.fnCleanTel(tel) as clean_tel, firstname, lastname
from PersonsInitial;
select tel, firstname, lastname from PersonsFinal
tel | firstname | lastname
:------------ | :-------- | :-------
00412354844 | Manu | Johns
01855234 | Fernand | Wajk
0041342354844 | Fred | Johns
db<>fiddle here
This is something that translate is useful for. You can define a string of characters to remove and replace them all with a single character also to be removed, eg a space, with some additional logic for your initial 00 criteria:
declare #replace varchar(30)='abcdefghijklmnopqrstuvwxyz/+-';
select *,
Replace(Translate(Iif(Left(Replace(tel,' ',''),1)='+',Concat('00',tel),tel), #replace, Replicate(' ',Len(#replace))),' ','')
from PersonsInitial;
You can then use an Updatable CTE to fix the original data, see example in Amended DBFiddle
I'd suggest once you have fixed your data you use a Check Constraint to ensure only valid data can be used.

Get all results in a single row

When I take a 'SELECT *' query from a table I would like all the results to be displayed in a single 'string' format.
For example:
SELECT * FROM Employees;
Returns:
Id FirstName LastName Age
1 John Smith 30
Instead I would like to get:
Id=1,FirstName=John,LastName=Smith,Age=30
But, if I do exactly the same for the query: SELECT * FROM Cars;
I want this query to adapt and just dynamically gets the columns from the table 'Cars' and do the same with it.
Does one of this select meets your requirements ?
Declare #Employees table(Id integer, FirstName varchar(100), LastName varchar(100), Age integer)
insert into #Employees values (1, 'John', 'Smith', 30), (2, 'John', 'Doe', 23)
select CONCAT('Id=', Id, ', FirstName=', FirstName, ', LastName=', LastName, ', Age=', Age) as Employees from #Employees
select
STUFF ((
select CONCAT('; ', 'Id=', Id, ', FirstName=', FirstName, ', LastName=', LastName, ', Age=', Age) from #Employees
FOR XML PATH('')),1,2, '') as employees
OUTPUT :
Employees
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Id=1, FirstName=John, LastName=Smith, Age=30
Id=2, FirstName=John, LastName=Doe, Age=23
Employees
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Id=1, FirstName=John, LastName=Smith, Age=30; Id=2, FirstName=John, LastName=Doe, Age=23
i don't have the Employees table so i made my own in a variable, but don't mind this, you can test this code without modifying the requests
I want to add that it's code I will use in a trigger, I will be using the 'inserted' and 'deleted' tables. This makes it much harder since I'm not able to use them in a stored procedure.

SQL Substring Functions

I have a column named full name. I want to split them into two columns, first name and last name.
I am having a trouble with a persons with two first names. If the first name encounters a space it was considered last name.
I want this:
Full name : John Michael Smith
Firstname: John Michael
Lastname: Smith
However, I am getting:
Firstname: John
Lastname: Michael Smith
Try:
declare #n varchar(max) = 'John Michael Smith'
select REVERSE(SUBSTRING(REVERSE(#n), CHARINDEX(' ', REVERSE(#n)), 100)) FirstName
Check the below link:
SQL SERVER – Reverse String Word By Word – Part 2
You can split the string by checking for the index of last space and using it with LEFT and RIGHT function.
DECLARE #name varchar(100)= 'John Michael Smith'
SELECT LEFT(#name,LEN(#name)-CHARINDEX(' ',REVERSE(#name))) AS [Firstname],RIGHT(#name,CHARINDEX(' ',REVERSE(#name))) AS [LastName]
--Create table from below script
create table users(id int IDENTITY(1,1) PRIMARY KEY, name varchar(50));
--Insert Record for query for testing
insert into users(name)
values('John Abraham'),
('John Mark Abraham'),
('John Vens Abraham'),
('John Abraham');
--Run below query for getting all inserted records.
select * from users;
--Run below query for getting first and last name from name
select id , name, SUBSTRING(name,0, CHARINDEX(last_name,name)) as first_name, last_name from
(
select id, name, REVERSE(SUBSTRING(REVERSE(name),0,CHARINDEX(' ',REVERSE(name)))) as last_name from users
) as A
You can hi-jack 'parsename'. This only works up to 4 intervals but a nice option;
declare #name varchar(100)
set #name='John Michael Smith'
select PARSENAME(REPLACE(#name,' ','.'),1) -- returns Smith
select PARSENAME(REPLACE(#name,' ','.'),2) -- returns Micheal
select PARSENAME(REPLACE(#name,' ','.'),3) -- Returns John
select PARSENAME(REPLACE(#name,' ','.'),4) -- returns NULL

How do I populate a column that already has URL's with values from 2 other columns?

I'm currently developing a report in SQL Server. Let's say I have 3 columns.
FirstName | LastName | URL's
----------+----------+------------------------------------------------
Tiffany | Smith | www.example.com/accountname=%3Dtiffany%7Lsmith
The format of the URL will always be:
www.example.com/accountname=%3Dname%7Lname
How would I populate the URL column with values from FirstName and LastName like the example above?
Using concatenate:
create table #temp
(
firstname varchar(50),
lastname varchar(50)
)
insert into #temp (firstname, lastname) values
('tiffany', 'smith'),
('john', 'doe')
select
firstname
, lastname
, concat('www.example.com/accountname=%3D', firstname, '%7L', lastname) as 'url'
from #temp
You could do something like this
declare #firstname varchar(10) = 'hello'
declare #lastname varchar(10) = 'there'
select 'www.example.com/accountname=%3D'+#firstname+'%7L'+#lastname as url
the URL that is return is this
www.example.com/accountname=%3Dhello%7Lthere
simply replace the variables with your column names
;With cte(FirstName , LastName , [URL's])
AS
(
SELECT 'Tiffany', 'Smith', 'www.example.com/accountname=%3D%7L' Union all
SELECT 'john', 'doe',Null
)
SELECT FirstName
,LastName
,ISNULL(STUFF(STUFF([URL's], CHARINDEX('%3D', [URL's]) + 3, 0, FirstName),
CHARINDEX('%7L', STUFF([URL's], CHARINDEX('%3D', [URL's]) + 3, 0, FirstName)),
LEN(LastName), '%7L' + LastName), 'NA') AS [URL's]
FROM cte
OutPut
FirstName LastName [URL's]
---------------------------------------------------------------------
Tiffany Smith www.example.com/accountname=%3DTiffany%7LSmith
john doe NA

Inserting multiple names in same cell with separated commas

Previously, I was trying to keep ALL previous last names of an employee in a table cell with commas (see below) but I didn’t know how. Someone then suggested using normalization which I’m not sure if it’ll be easier in this situation. My boss wants to display all previous last names of an employee on a web page each time she edits her account info. Simply put, when Judy changes her last name again – her last name Kingsley should be inserted behind Smith. So, my question is back to whether or not it is possible to add multiple last names in the same cell, separated with commas as I thought it’ll be simpler when I use a variable on the web page to display all the Alias at once? Yet, I’ve no clue the complexity to write the codes for this. Any help is truly appreciated.
Current SQL table
+---------------+-----------------+----------------+--------------------+
People FirstName LastName Alias
+---------------+-----------------+----------------+--------------------+
002112 Judy Smith Hall
Preferred
+---------------+-----------------+----------------+--------------------+
People FirstName LastName Alias
+---------------+-----------------+----------------+--------------------+
002112 Judy Kingsley Hall, Smith
Keep the database normalized.
People:
(Id, Firstname, Lastname)
LastnameHistory:
(PeopleId, OldLastname, NewLastname, DateChanged)
You can the create a view which would be a "GROUP_CONCAT" type of query to transform the data as required.
An example:
DECLARE #people TABLE ( id INT IDENTITY(1,1), fname VARCHAR(50), lname VARCHAR(50))
DECLARE #lnameHistory TABLE ( id INT IDENTITY(1,1), people_id INT, lname VARCHAR(50), date_changed DATETIME)
INSERT INTO #people (fname, lname)
VALUES ('john', 'smith'), ('jane', 'doe')
INSERT INTO #lnameHistory (people_id, lname, date_changed)
VALUES (2, 'shakespeare', '2012-01-01'), (2, 'einstein', '2013-12-12')
;WITH group_concat AS
(
SELECT people_id, LEFT(lnames , LEN(lnames )-1) AS lnames
FROM #lnameHistory AS o
CROSS APPLY
(
SELECT lname + ', '
FROM #lnameHistory AS i
WHERE o.people_id = i.people_id
ORDER BY date_changed ASC
FOR XML PATH('')
) pre_trimmed (lnames)
GROUP BY people_id, lnames
)
SELECT p.*, gc.lnames FROM #people p
JOIN group_concat gc ON gc.people_id = p.id
Some reference for syntax:
SQL Server CROSS APPLY and OUTER APPLY
XML Data (SQL Server)
Assuming your update statement is a stored procedure taking in parameters of #personId and #newLastName:
EDIT
Sorry, wrong version of SQL. Have to do it the old school way!
UPDATE PeopleTable
SET Alias = Alias + ', ' + LastName,
LastName = #newLastName
WHERE
People = #personId
When you update the table for a new LastName, use something like this:
UPDATE <table> SET Alias = Alias + ', ' + LastName, LastName = <newLastName>