SQL Server - COALESCE WHEN NOTHING RETURNS , GET DEFAULT VALUE - sql

I'm trying to use Coalesce function in SQL Server to concatente multiple names. But when the conditon in the query returns no rows or nothing, I need to return a default value. I tried some condition using case statement but I can't figure it out what I missed.
declare #Names varchar(max) = '',
#Key varchar(max) = 'ABC'
select #Names = COALESCE(#Names, '') + isnull(T0.A, #Key) + ', '
from TData P
left join TNames T0 on T0.C + '\' + T0.D = P.#Key
where OBID=581464
and ID < 1432081
select #Names

You can do it with 2 minor changes to your current code, but I suspect this is an XYProblem, and you might benefit more from editing your question to include sample data and desired results (so perhaps we can suggest a better solution).
Anyway, what I had in mind is this:
declare #Names varchar(max), -- remove the = '', so that #Names starts as null
#Key varchar(max) = 'ABC'
select #Names = COALESCE(#Names, '') + isnull(T0.A, #Key) + ', '
from TData P
left join TNames T0 on T0.C + '\' + T0.D = P.#Key -- ' (This is just to fix the coding colors)
where OBID=581464
and ID < 1432081
select COALESCE(#Names, 'default value') -- since #Names started as null, and the query did not return any results, it's still null...

Related

SQL - concatenate strings in variable while loop with +=

I can't concatenate in this example bellow!
When I loop I get my 2 correct results.
When I concatenate #MaterialCompositionEn += ', ' it works fine
When I try to concatenate #MaterialCompositionEn += same query to get the 2nd row, I have a null!
DECLARE #MaterialCompositionId int = 475;
DECLARE #MaterialCompositionKey nvarchar(50) = '202071512324138';
DECLARE #Records nvarchar(250);
DECLARE #RecordProceed int;
DECLARE #MaterialCompositionEn nvarchar(500);
SET #Records = (SELECT STRING_AGG(Id, ',') FROM MaterialCompositions mc WHERE mc.MaterialCompositionId = #MaterialCompositionId)
WHILE len(#Records) > 0
BEGIN
SET #RecordProceed = CAST(LEFT(#Records,4) AS int)
if #RecordProceed > 0
BEGIN
SET #Records = REPLACE(#Records,substring(#Records, 1, 4),'')
END
if len(#Records) > 4
BEGIN
SET #Records = REPLACE(#Records,substring(#Records, 1, 1),'')
END
if len(#MaterialCompositionEn) > 0
BEGIN
SET #MaterialCompositionEn += ', '
END
PRINT 'MaterialCompositionEn1: ' + #MaterialCompositionEn
SET #MaterialCompositionEn =
(SELECT COALESCE (CAST(MaterialProportion AS nvarchar) + '% ', '') +
(SELECT mp.MaterialPrimaryEn +
COALESCE(
(SELECT ' (' + ms.MaterialSecondaryEn + ')' AS MS1 FROM dbo.MaterialSecondaries AS ms WHERE ms.Id = mc.MaterialSecondaryId)
, '')
FROM dbo.MaterialPrimaries AS mp WHERE mp.Id = mc.MaterialPrimaryId)
FROM MaterialCompositions mc WHERE mc.Id = #RecordProceed
)
PRINT 'MaterialCompositionEn2: ' + #MaterialCompositionEn
END
Result:
MaterialCompositionEn2: 20% Cashmere
MaterialCompositionEn1: 20% Cashmere,
MaterialCompositionEn2: 80% Wool
Now when I change to:
SET #MaterialCompositionEn +=
(SELECT COALESCE......
I am expecting 20% Cashmere, 80% Wool
instead my 3 prints are NULL
I tried to CAST but won't help.
Any idea?
Thanks in advance
I'm guessing there is a much simpler way to do what you want. However, I think the problem is that you need to initialize the string. So at the top of the code block put:
SET #MaterialCompositionEn = '';
SET #MaterialCompositionEn =
SELECT
CONCAT(
mp.MaterialPrimaryEn, ' ', MaterialProportion, '% ', --always show primary
', ' + ms.MaterialSecondaryEn + CONCAT(100 - MaterialProportion, '%') --sometimes show secondary
)
FROM
MaterialCompositions mc
INNER JOIN dbo.MaterialPrimaries mp ON mp.Id = mc.MaterialPrimaryId
LEFT JOIN dbo.MaterialSecondaries ms ON ms.Id = mc.MaterialSecondaryId
WHERE mc.Id = #RecordProceed
)
Something like this might be neater.. Note that I'm not clear where MaterialProportion comes from (I suspect MaterialCompositions), so this perhaps isn't a solution, just a note as to how you might use CONCAT/avoid having boatloads of nested selects. The use of INNER/OUTER join links compositions and definitely a primary, possibly a secondary material. If the secondary material is null then the aim is to hide it with a mix and match of CONCAT and +
CONCAT treats nulls as empty strings, where as + causes the whole expression to become null. This can be useful to mix and match e.g. in something like ', ' + ms.MaterialSecondaryEn + CONCAT(100 - MaterialProportion, '%'):
the CONCAT(100 - MaterialProportion, '%') would be 20% (if the primary material was 80%) but
the ', ' + ms.MaterialSecondaryEn + CONCAT(...) as a whole is NULL if MaterialSecondaryEn IS NULL from a left join fail to match, so where there is only a primary material, a the string describing the secondary should disappear entirely as NULL, which the outer CONCAT handles as an empty string

MS SQL Server - replace names while avoiding words containing the names

This is my first time posting on Stack Overflow, so please let me know if I can do anything better or provide more information.
I have been working on this issue for a few days now. I have a table with comments from employees about the company. Some of them could refer to specific employees in the company. For HR reasons, we want to replace any occurrence of an employee name with the word 'employee'. We aren't accounting for typos or misspellings.
An example of my desired outcome would be:
Input: 'I dislike dijon mustard. My boss Jon sucks.'
Name to search for: 'Jon'
Output: 'I dislike dijon mustard. My boss employee sucks.'
Another example:
Input: 'Aggregating data is boring. Greg is the worst person ever.'
Name to search for: 'Greg'
Output: 'Aggregating data is boring. employee is the worst person ever.'
I want to search the comments for occurrences of the employee names, but only if they aren't followed by other letters or numbers on either end. Occurrences with spaces or punctuation on either end of the name should be replaced.
So far I have tried the suggestions in the following threads:
How to replace a specific word in a sentence without replacing in substring in SQL Server
replacing-in-substring-in-s
This yielded the following
update c
set c.Comment = rtrim(ltrim(Replace(replace(' ' + c.Comment + ' ',' ' + en.FirstName + ' ', 'employee'), ' ' + en.FirstName + ' ', 'employee')))
from AnswerComment c
join #EmployeeNames en on en.SurveyId = c.SurveyId
and c.Comment like '%' + en.FirstName + '%'
However, I got results like this:
Input: 'I hate bob.'
Name to search for: 'Bob'
Output: 'I hate bob.'
Input: 'Jon sucks'
Name to search for: 'Jon'
Output: 'employeesucks'
A coworker looked at this thread Replace whole word using ms sql server "replace"
and gave me the following based off of it:
DECLARE #token VARCHAR(10) = 'bob';
DECLARE #replaceToken VARCHAR(10) = 'employee';
DECLARE #paddedToken VARCHAR(10) = ' ' + #token + ' ';
DECLARE #paddedReplaceToken VARCHAR(10) = ' ' + #replaceToken + ' ';
;WITH Step1 AS (
SELECT CommentorId
, QuestionId
, Comment
, REPLACE(Comment, #paddedToken, #paddedReplaceToken) AS [Value]
FROM AnswerComment
WHERE SurveyId = 90492
AND Comment LIKE '%' + #token + '%'
), Step2 AS (
SELECT CommentorId
, QuestionId
, Comment
, REPLACE([Value], #paddedToken, #paddedReplaceToken) AS [Value]
FROM Step1
), Step3 AS (
SELECT CommentorId
, QuestionId
, Comment
, IIF(CHARINDEX(LTRIM(#paddedToken), [Value]) = 1, STUFF([Value], 1, LEN(TRIM(#paddedToken)), TRIM(#paddedReplaceToken)), [Value]) AS [Value]
FROM Step2
)
SELECT CommentorId
, QuestionId
, Comment
, IIF(CHARINDEX(REVERSE(RTRIM(#paddedToken)), REVERSE([Value])) = 1,
REVERSE(STUFF(REVERSE([Value]), CHARINDEX(REVERSE(RTRIM(#paddedToken)), REVERSE([Value])), LEN(RTRIM(#paddedToken)), REVERSE(RTRIM(#paddedReplaceToken)))),
[Value])
FROM Step3;
But I have no idea how I would implement this.
Another thread I can't find anymore suggested using %[^a-z0-9A-Z]% for searching, like this:
update c
set c.Comment = REPLACE(c.Comment, en.FirstName, 'employee')
from AnswerComment c
join #EmployeeNames en on en.SurveyId = c.SurveyId
and c.Comment like '%' + en.FirstName + '%'
and c.Comment not like '%[^a-z0-9A-Z]%' + en.FirstName + '%[^a-z0-9A-Z]%'
select ##ROWCOUNT [first names replaced]
This doesn't work for me. It replaces occurrences of the employee names even if they're part of a larger word, like in this example:
Input: 'I dislike dijon mustard.'
Name to search for: 'Jon'
Output: 'I dislike diemployee mustard.'
At this point it seems to me that it's impossible to accomplish this. Is there anything wrong with how I've implemented these, or anything obvious that I'm missing?
Here is a method that uses a combination of STUFF and PATINDEX.
It'll only replace the first occurence of the name in the comment.
So it might have to be executed more than once till nothing gets updated by it.
UPDATE c
SET c.Comment = STUFF(c.Comment, PATINDEX('%[^a-z0-9]'+en.FirstName+'[^a-z0-9]%', '/'+c.Comment+'/'), len(en.FirstName), 'employee')
FROM AnswerComment c
JOIN #EmployeeNames en ON en.SurveyId = c.SurveyId
WHERE '/'+c.Comment+'/' LIKE '%[^a-z0-9]'+en.FirstName+'[^a-z0-9]%';
Something like this seems to work.
declare #charsTable table (notallowed char(1))
insert into #charsTable (notallowed) values (',')
insert into #charsTable (notallowed) values ('.')
insert into #charsTable (notallowed) values (' ')
declare #input nvarchar(max) = 'Aggregating data is boring. Greg is the worst person ever.'
declare #name nvarchar(50) = 'Greg'
--declare #input nvarchar(max) = 'I dislike dijon mustard. You know who sucks? My boss Jon.'
--declare #name nvarchar(50) = 'Jon'
select case when #name + notallowed = value or notallowed + #name = value or notallowed + #name = value then replace(value, #name, 'employee') else value end 'data()' from string_split(#input, ' ')
left join #charsTable on #name + notallowed = value or notallowed + #name = value or notallowed + #name + notallowed = value
for xml path('')
Results:
Aggregating data is boring. employee is the worst person ever.
I dislike dijon mustard. You know who sucks? My boss employee.

COALESCE Doubles results values

in function
SELECT #ProcedureName = COALESCE(#ProcedureName + ',', '') + ProcedureName
FROM V_Procedures P
inner join MedicalRecords MR on P.Medical_Record=MR.Medical_Record
where ProcedureName IS NOT NULL and MR.Admission_No  = #Admission_No
and Field = 18
getting many doubles seperated by comma, is it possible to avoid it?
For example results values appears more then once as
CONCHOTOMY,FESS-FUNCTIONAL ENDOSCOPIC (NASAL) SINUS SURGERY,CONCHOTOMY,FESS-FUNCTIONAL ENDOSCOPIC (NASAL) SINUS SURGERY,SUBMUCOUS RESECTION OF NASAL SEPTUM
You seems want distinct :
SELECT DISTINCT #ProcedureName = COALESCE(#ProcedureName + ',', '') + ProcedureName
FROM V_Procedures P INNER JOIN
MedicalRecords MR
ON P.Medical_Record=MR.Medical_Record
WHERE ProcedureName IS NOT NULL AND
MR.Admission_No = #Admission_No AND
Field = 18;
Instead COALESCE, try with CONCAT. And also GROUP BY.
DECLARE #ProcedureName VARCHAR(max);
SELECT #ProcedureName = CONCAT(#ProcedureName + ',', ProcedureName)
FROM V_Procedures P
JOIN MedicalRecords MR ON P.Medical_Record = MR.Medical_Record
WHERE ProcedureName IS NOT NULL AND MR.Admission_No = #Admission_No
AND Field = 18
GROUP BY ProcedureName
The trick is that CONCAT won't return NULL when a NULL is added to it. But + does. So because #ProcedureName is NULL at first, the result won't start with a comma.

Return comma-separated list from SQL Server

I have a stored procedure as below. Now I want to modify it so that it returns the value as a comma separated list.
CREATE PROCEDURE [dbo].[CUST_Notification_GetCompaniesFromEmails]
#EmailValue AS NTEXT
AS
SELECT DISTINCT
ISNULL(CompanyAddressesContacts.FirstName, '') + ' ' +
ISNULL(CompanyAddressesContacts.LastName, '') AS ContactName
,ISNULL(dbo.Companies.CompanyName,'') AS CompanyName,
CASE
WHEN CompanyName = 'Meraas Development' THEN '1'
WHEN CompanyName = 'Samsung C&T' THEN '2'
ELSE '3'
END AS id
FROM
dbo.CompanyAddressesContacts
INNER JOIN
dbo.Companies ON dbo.CompanyAddressesContacts.CompanyId = Companies.Id
WHERE
dbo.CompanyAddressesContacts.Email IN
(SELECT [value]
FROM dbo.SplitWords(#EmailValue,';'))
The above code returns values as a normal select statement would do . Now I want a modification in the code so that it returns a value as comma-separated list.
Thanks!
Try like this
DECLARE #List VARCHAR(8000)
SELECT #List = COALESCE(#List + ',', '') + CAST(OfferID AS VARCHAR)
FROM Emp
WHERE EmpID = 23
SELECT #List
Try to use SplitWords method as
dbo.SplitWords(#EmailValue +',','')
Have a visit
http://msmvps.com/blogs/robfarley/archive/2007/04/08/coalesce-is-not-the-answer-to-string-concatentation-in-t-sql.aspx
http://oops-solution.blogspot.in/2011/11/sql-server-convert-table-column-data.html

Convert SQL Server result set into string

I am getting the result in SQL Server as
SELECT StudentId FROM Student WHERE condition = xyz
I am getting the output like
StudentId
1236
7656
8990
........
The output parameter of the stored procedure is #studentId string and I want the return statement as
1236, 7656, 8990.
How can I convert the output in the single string?
I am returning single column [ie. StudentId]
Test this:
DECLARE #result NVARCHAR(MAX)
SELECT #result = STUFF(
( SELECT ',' + CONVERT(NVARCHAR(20), StudentId)
FROM Student
WHERE condition = abc
FOR xml path('')
)
, 1
, 1
, '')
DECLARE #result varchar(1000)
SELECT #result = ISNULL(#result, '') + StudentId + ',' FROM Student WHERE condition = xyz
select substring(#result, 0, len(#result) - 1) --trim extra "," at end
Use the COALESCE function:
DECLARE #StudentID VARCHAR(1000)
SELECT #StudentID = COALESCE(#StudentID + ',', '') + StudentID
FROM Student
WHERE StudentID IS NOT NULL and Condition='XYZ'
select #StudentID
Both answers are valid, but don't forget to initializate the value of the variable, by default is NULL and with T-SQL:
NULL + "Any text" => NULL
It's a very common mistake, don't forget it!
Also is good idea to use ISNULL function:
SELECT #result = #result + ISNULL(StudentId + ',', '') FROM Student
Use the CONCAT function to avoid conversion errors:
DECLARE #StudentID VARCHAR(1000)
SELECT #StudentID = CONCAT(COALESCE(#StudentID + ',', ''), StudentID)
FROM Student
WHERE StudentID IS NOT NULL and Condition='XYZ'
select #StudentID
The following is a solution for MySQL (not SQL Server), i couldn't easily find a solution to this on stackoverflow for mysql, so i figured maybe this could help someone...
ref: https://forums.mysql.com/read.php?10,285268,285286#msg-285286
original query...
SELECT StudentId FROM Student WHERE condition = xyz
original result set...
StudentId
1236
7656
8990
new query w/ concat...
SELECT group_concat(concat_ws(',', StudentId) separator '; ')
FROM Student
WHERE condition = xyz
concat string result set...
StudentId
1236; 7656; 8990
note: change the 'separator' to whatever you would like
GLHF!
This one works with NULL Values in Table and doesn't require substring operation at the end. COALESCE is not really well working with NULL values in table (if they will be there).
DECLARE #results VARCHAR(1000) = ''
SELECT #results = #results +
ISNULL(CASE WHEN LEN(#results) = 0 THEN '' ELSE ',' END + [StudentId], '')
FROM Student WHERE condition = xyz
select #results
The answer from brad.v is incorrect! It won't give you a concatenated string.
Here's the correct code, almost like brad.v's but with one important change:
DECLARE #results VarChar(1000)
SELECT #results = CASE
WHEN #results IS NULL THEN CONVERT( VarChar(20), [StudentId])
ELSE #results + ', ' + CONVERT( VarChar(20), [StudentId])
END
FROM Student WHERE condition = abc;
See the difference? :) brad.v please fix your answer, I can't do anything to correct it or comment on it 'cause my reputation here is zero. I guess I can remove mine after you fix yours. Thanks!
Use STRING_AGG:
SELECT STRING_AGG(sub.StudentId, ',') FROM
(select * from dbo.Students where Name = 'Test3') as sub
If you want to use e.g ORDER BY:
SELECT STRING_AGG(sub.StudentId, ',') WITHIN GROUP(Order by StudentId) FROM
(select * from dbo.Students where Name = 'Test3') as sub
or a single select statement...
DECLARE #results VarChar(1000)
SELECT #results = CASE
WHEN #results IS NULL THEN CONVERT( VarChar(20), [StudentId])
ELSE ', ' + CONVERT( VarChar(20), [StudentId])
END
FROM Student WHERE condition = abc;
Assign a value when declaring the variable.
DECLARE #result VARCHAR(1000) ='';
SELECT #result = CAST(StudentId AS VARCHAR) + ',' FROM Student WHERE condition = xyz