is there any `backspace` character in mssql for string? - sql

Below is the query to form a string containing company details by concatenating Name, address1 and address2. Here I am using the ISNULL() function to concatenate an empty string ('') if the column is null.
select Name+' ,'+isnull(Address1,'')+' ,'+isnull(Address2,'') as compDeatils
from tableCompany where ID = 4
This query's issue is in the case where Address1 or Address2 is null, it will concatenate a comma before the empty space which I don't want.
For example, if Address1 and Address2 are NULL then the result will be name,,.
How i can overcome this?
Is there a backspace character in mssql?

i got the answer it is simple logic.. add commas within the ISNULL() function
select Name+isnull(','+Address1,'')+isnull(','+Address2,'') as compDeatils
from tableCompany where ID = 4
Note: Name will not give NULL in my case. in case name also null this answer is not applicable.

Related

Oracle SQL - combine two columns

How can I combine two columns in Oracle SQL without using CASE?
I have to combine FirstName and LastName in the same row.
I have a table as below:
FirstName LastName
-----------------------
Ken Chan
John Ng
Joe Lam
The data type of these columns is VARCHAR2.
I try to apply the code as follow
SELECT
CONCAT(LastName, ‘,’, FirstName) AS FullName
FROM
LIST
ORDER BY
Place;
SELECT
LastName, ‘,’, FirstName AS FullName
FROM
LIST
ORDER BY
Place;
But both of them result in the the same error
ORA-00909: invalid number of arguments.
May I also ask how can I not adding the ‘,’ while there is missing LastName or FirstName?
Such as not adding ‘,’ when there is only having LastName Chan. The FullName only display as Chan but not ,Chan.
Thanks a lot for helping me.
Use Concatenation Operator that is ||. It concatenates character strings and results in another character string.
To make , comma optional in case if any of the LastName or firstName field is empty or null, use CASE statement.
Solution for your problem:
SELECT LastName || (CASE WHEN LastName IS NOT NULL AND FirstName IS NOT NULL THEN ',' END) || FirstName as FullName
FROM LIST
ORDER BY place;
Working Example: db<>fiddle Link
For more info on Concatenation Operator follow below link to official docs:
https://docs.oracle.com/cd/B19306_01/server.102/b14200/operators003.htm
Oracle's implementation of the concat() function only permits 2 parameters, and you have tried 3, that is why you got the error message.
It is simpler, in Oracle, to use the more traditional double pipe operator to form a concatenated string.
SELECT LastName || ‘,’ || FirstName as FullName
from LIST
order by Place;

Update Column from Columns within same table using SQLite

I’m trying to update an email address value from users first- and lastname within the same table.
Pattern for generated Mail: <Firstname>.<Lastname>#test.org
Example Table “Persons”:
Firstname Lastname email
Henley Figueroa none#none.com
Samina Morrison none#none.com
Dev Rowe none#none.com
Wished result for table “Persons”:
Firstname Lastname email
Henley Figueroa Henley.Figueroa#test.org
Samina Morrison Samina.Morrison#test.org
Dev Rowe Dev.Rowe#test.org
SQL Code
UPDATE Persons
SET
email = (SELECT FirstName || "." || LastName ||"#"||"test.org" FROM Persons)
Actual result for table “Persons”:
Firstname Lastname email
Henley Figueroa Henley.Figueroa#test.org
Samina Morrison Henley.Figueroa#test.org
Dev Rowe Henley.Figueroa#test.org
Only the first record of the returned result table is used over and over. Why?
If I ommit the SELECT:
UPDATE Persons
SET
email = FirstName || "." || LastName ||"#"||"test.org"
I get the expected result.
Referring to your answers, I'm extending my question with an example of two tables. One with only names, the second for mail addresses.
Table Persons:
ID*
Firstname
Lastname
1
Henley
Figueroa
2
Samina
Morrison
3
Dev
Rowe
Table Addresses:
ID*
email
1
wrong#wrong.ng
2
wrong#wrong,ng
3
wrong#wro.ng
UPDATE Addresses
SET email = (SELECT Firstname ||"."|| Lastname || "#test.org"
FROM Persons WHERE Persons.id = Addresses.id)
Demo
Here the UPDATE with SET and SELECT works (Every person gets a unique mail address). Shouldn’t I get the same problem here?
From the output of SELECT I see that I get again (as expected) three records.
You have the right syntax for your problem. So the question is why does this not do what you want?
UPDATE Persons
SET email = (SELECT FirstName || "." || LastName ||"#"||"test.org"
FROM Persons
);
In fact, this should produce an error in any SQL engine -- although SQLite can be a bit lax about such errors. Why? The SET is expecting a single value. This code has a subquery that returns three values.
Note: The SQL Fiddle does show that SQLite accepts this syntax. Argggh! You can switch this to Postgres to see the error. With some modifications, to the create code you could also see the same error (subquery returns more than one row) using SQL Server or Oracle or just about any database.
Apparently, SQLite is just arbitrarily choosing one of those values -- the one that it first encounters. And this is the same value for all three rows.
You already know that a subquery is not correct here. You have the correct code in your question.
From Subquery Expressions:
A SELECT statement enclosed in parentheses is a subquery. All types of
SELECT statement, including aggregate and compound SELECT queries
(queries with keywords like UNION or EXCEPT) are allowed as scalar
subqueries. The value of a subquery expression is the first row of
the result from the enclosed SELECT statement. The value of a
subquery expression is NULL if the enclosed SELECT statement returns
no rows.
So the value you get by the subquery is the first row of the rows returned.
Of course, you don't need the SELECT statement.
This is a simple UPDATE statement that involves only the values of the columns of the current row:
UPDATE Persons
SET email = FirstName || '.' || LastName || '#' || 'test.org'
See the demo.
Results:
Firstname
Lastname
email
Henley
Figueroa
Henley.Figueroa#test.org
Samina
Morrison
Samina.Morrison#test.org
Dev
Rowe
Dev.Rowe#test.org
For the 2nd query with the 2 tables:
Shouldn’t I get the same problem here?
No, because the subquery is a correlated subquery, which returns for each row in the table Addresses only 1 row (provided there are no duplicate ids in Persons), the row which matches the condition Persons.id = Addresses.id.
If there is no row that matches the condition then it will return NULL.

Updating with a select one table

I want to update a column with a concatenation of other columns within the same table.
This is for customer names in a table. There are separate columns for "Title" i.e. Mr, Ms, Mrs etc, "FirstName", "MiddleName" and "LastName". I altered the table by adding a new "FullName" column, which I tried to fill with a concatenation of the former columns.
SET [SalesLT].[Customer].[FullName] = (SELECT
Title,
FirstName,
MiddleName,
LastName,
CONCAT(Title,' ',FirstName,' ',MiddleName,' ',LastName) as FullName
FROM [AdventureWorksLT2008R2].[SalesLT].[Customer])
WHERE FullName = NULL;
I'm getting this
Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
Since you are updating a column value based on other columns in the same table, you not select them again.
UPDATE [SalesLT].[Customer]
SET [SalesLT].[Customer].[FullName] =
CONCAT(Title,' ',FirstName,' ',MiddleName,' ',LastName)
WHERE FullName is NULL;
Note: I did not change your where clause condition, neither concat function. In some databases you may need to do FullName is NULL instead of FullName = NULL. And in some databases, you may need to concat multiple values with ||.

How to return both null and not-null values in one query

I have an integer field person_id with the default value of NULL. I am using a stored procedure and pulling people names and address. if a user does not pass a value all records are pulled both, null and not nulls. How do I do it. May be Case statement or otherwise?
my_procedure( <--- this is pseudo code
#person_id int null
begin
select name, address from PERSON
WHERE person_id like case NULL then NULL else '%'
end
Null requires -> IS NULL
number requires = 123
EDIT
I need a condition too, if nothing is passed, all values are pulled. If something is passed, that value is searched
WHERE (#personID is NULL OR personid IS NULL OR personid = #personid)
Just put both your cases in a parenthetical WHERE clause.
EDIT
Added another OR clause to cover what I THINK you are asking for.
The correct code in this case is
IsNULL(mycolum,'') LIKE CASE when person_id is null then '%' else '%' + person_id + '%'
IsNULL coverts null values into empty string and then you can worry about only strings, not null values.

How can I compare two name strings that are formatted differently in SQL Server?

What would be the best approach for comparing the following set of strings in SQL Server?
Purpose: The main purpose of this Stored Procedure is to compare a set of input Names of Customers to names that Exist in the Customer database for a specific accounts. If there is a difference between the input name and the name in the Database this should trigger the updating of the Customer Database with the new name information.
Conditions:
Format of Input: FirstName [MiddleName] LastName
Format of Value in Database: LastName, FirstName MiddleName
The complication arises when names like this are presented,
Example:
Input: Dr. John A. Mc Donald
Database: Mc Donald, Dr. John A.
For last names that consist of 2 or more parts what logic would have to be put into place
to ensure that the lastname in the input is being compared to the lastname in the database and likewise for the first name and middle name.
I've thought about breaking the database values up into a temp HASH table since I know that everything before the ',' in the database is the last name. I could then check to see if the input contains the lastname and split out the FirstName [MiddleName] from it to perform another comparison to the database for the values that come after the ','.
There is a second part to this however. In the event that the input name has a completely New last name (i.e. if the name in the database is Mary Smith but the updated input name is now Mary Mc Donald). In this case comparing the database value of the last name before the ',' to the input name will result in no match which is correct, but at this point how does the code know where the last name even begins in the input value? How does it know that her Middle name isn't MC and her last name Donald?
Has anyone had to deal with a similar problem like this before? What solutions did you end up going with?
I greatly appreciate your input and ideas.
Thank you.
Realistically, it's extremely computationally difficult (if not impossible) to know if a name like "Mary Jane Evelyn Scott" is first-middle-last1-last2, first1-first2-middle-last, first1-first2-last1-last2, or some other combination... and that's not even getting into cultural considerations...
So personally, I would suggest a change in the data structure (and, correspondingly, the application's input fields). Instead of a single string for name, break it into several fields, e.g.:
FullName{
title, //i.e. Dr., Professor, etc.
firstName, //or given name
middleName, //doesn't exist in all countries!
lastName, //or surname
qualifiers //i.e. Sr., Jr., fils, D.D.S., PE, Ph.D., etc.
}
Then the user could choose that their first name is "Mary", their middle name is "Jane Evelyn", and their last name is "Scott".
UPDATE
Based on your comments, if you must do this entirely in SQL, I'd do something like the following:
Build a table for all possible combinations of "lastname, firstname [middlename]" given an input string "firstname [middlename] lastname"
Run a query based on the join of your original data and all possible orderings.
So, step 1. would take the string "Dr. John A. Mc Donald" and create the table of values:
'Donald, Dr. John A. Mc'
'Mc Donald, Dr. John A.'
'A. Mc Donald, Dr. John'
'John A. Mc Donald, Dr.'
Then step 2. would search for all occurrences of any of those strings in the database.
Assuming MSSQL 2005 or later, step 1. can be achieved using some recursive CTE, and a modification of a method I've used to split CSV strings (found here) (SQL isn't the ideal language for this form of string manipulation...):
declare #str varchar(200)
set #str = 'Dr. John A. Mc Donald'
--Create a numbers table
select [Number] = identity(int)
into #Numbers
from sysobjects s1
cross join sysobjects s2
create unique clustered index Number_ind on #Numbers(Number) with IGNORE_DUP_KEY
;with nameParts as (
--Split the name string at the spaces.
select [ord] = row_number() over(order by Number),
[part] = substring(fn1, Number, charindex(' ', fn1+' ', Number) - Number)
from (select #str fn1) s
join #Numbers n on substring(' '+fn1, Number, 1) = ' '
where Number<=Len(fn1)+1
),
lastNames as (
--Build all possible lastName strings.
select [firstOrd]=ord, [lastOrd]=ord, [lastName]=cast(part as varchar(max))
from nameParts
where ord!=1 --remove the case where the whole string is the last name
UNION ALL
select firstOrd, p.ord, l.lastName+' '+p.part
from lastNames l
join nameParts p on l.lastOrd+1=p.ord
),
firstNames as (
--Build all possible firstName strings.
select [firstOrd]=ord, [lastOrd]=ord, [firstName]=cast(part as varchar(max))
from nameParts
where ord!=(select max(ord) from nameParts) --remove the case where the whole string is the first name
UNION ALL
select p.ord, f.lastOrd, p.part+' '+f.firstName
from firstNames f
join nameParts p on f.firstOrd-1 = p.ord
)
--Combine for all possible name strings.
select ln.lastName+', '+fn.firstName
from firstNames fn
join lastNames ln on fn.lastOrd+1=ln.firstOrd
where fn.firstOrd=1
and ln.lastOrd = (select max(ord) from nameParts)
drop table #Numbers
Since I had my share of terrible experience with data from third parties, it is almost guaranteed that the input data will contain lots of garbage not following the specified format.
When trying to match data multipart string data like in your case, I preprocessed both input and our data into something I called "normalized string" using the following method.
strip all non-ascii chars (leaving language-specific chars like "č" intact)
compact spaces (replace multiple spaces with single one)
lower case
split into words
remove duplicates
sort alphabetically
join back to string separated by dashes
Using you sample data, this function would produce:
Dr. John A. Mc Donald ->
a-donald-dr-john-mc Mc Donald, Dr.
John A.-> a-donald-dr-john-mc
Unfortunaly it's not 100% bulletproof, there are cases where degenerated inputs produce invalid matches.
Your name field is bad in the database. Redesign and get rid of it. If you havea a first name, middlename, lastname, prefix and suffix sttructure, you can hava computed filed that has the structure you are using. But it is a very poor way to store data and your first priority should be to stop using it.
Since you have a common customer Id why aren't you matching on that instead of name?