How to substring non constant strings? - sql

I have the following query:
UPDATE AmmUser.ORDINI_SCANSIONATI
SET NUMERO_ORDINE=replace((substring([Text],PATINDEX('%NR. [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%',[Text]),13)),'NR. ',''),
STATO=1
from AmmUser.ORDINI_SCANSIONATIIndexes
inner join AmmUser.ORDINI_SCANSIONATIDocs
on ORDINI_SCANSIONATIIndexes.DocumentID=ORDINI_SCANSIONATIDocs.DocumentID
inner join AmmUser.ORDINI_SCANSIONATI
on ORDINI_SCANSIONATIDocs.RecordID =ORDINI_SCANSIONATI.DsRecordID
where PageNumber IS NULL AND STATO IS NULL
With this query I try to associate the value of substring to my variable NUMERO_ORDINE when I find the "NR." string in the Text column.
Sometimes I don't have the "NR." string, so this query doesn't work and I get wrong values from substring function.
How can I create the same substring when I don't have the "NR." string into Text? I always need to isolate nine numbers.

One method is to use a CASE expression:
(case when [Text] like '%NR. [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%'
then replace(substring([Text],
PATINDEX('%NR. [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%', [Text]),
13
), 'NR. ', ''
)
end),
STATO = 1
You can also add the pattern to the end of the string when it is being searched:
replace(substring([Text],
PATINDEX('%NR. [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%',
[Text] + 'NR. 000000000'),
13
), 'NR. ', ''
),
STATO = 1
This is a little tricky in this case because the pattern is a little complicated.

I noticed that my code sometime has prefix "NR." and sometime suffix "DEL" (in many cases I have both at the same time). So I used the first solution provided by Gordon with a little customization:
UPDATE AmmUser.ORDINI_SCANSIONATI
SET NUMERO_ORDINE = CASE
WHEN [Text] like '%NR. [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%'
THEN REPLACE(SUBSTRING([Text],PATINDEX('%NR. [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%',[Text]),13),'NR.','')
WHEN [Text] like '%[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] DEL%'
THEN REPLACE(SUBSTRING([Text],PATINDEX('%[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] DEL%',[Text]),9),'DEL','')
ELSE 'ERRATA LETTURA'
END,
STATO=1
FROM AmmUser.ORDINI_SCANSIONATIIndexes
INNER JOIN AmmUser.ORDINI_SCANSIONATIDocs ON ORDINI_SCANSIONATIIndexes.DocumentID=ORDINI_SCANSIONATIDocs.DocumentID
INNER JOIN AmmUser.ORDINI_SCANSIONATI ON ORDINI_SCANSIONATIDocs.RecordID =ORDINI_SCANSIONATI.DsRecordID
WHERE PageNumber IS NULL AND STATO IS NULL

Related

Set prefix in SQL CASE expression

I have problem setting a prefix in a case statement.
Data set:
missionid:
5505
5506
select
CASE
WHEN m.EXTLOCATIONID is not null THEN '01' + convert(nvarchar(50),m.missionid)
ELSE tg.ID_ACTIVITY
END as Barcode2
from MISSION m
left join TASKGROUP tg with(nolock) on m.MMPICKLISTID = tg.ID
When I run this query my result is this:
Barcode2:
15505
15506
Desired result is this:
015505
015506
As one can see, the first zero is not shown in the result. How can I achieve this?
CASE expression would always return one type so, you need to do conversion:
CASE WHEN m.EXTLOCATIONID is not null
THEN '01' + convert(nvarchar(50), m.missionid)
ELSE CONVERT(VARCHAR(255), tg.ID_ACTIVITY)
END as Barcode2
A case expression returns a single type. And, if different paths return different types -- say a string and a number -- then the result is a number. Those are the rules of SQL.
You are also mixing national character sets with "regular" characters. That seems unnecessary. I would recommend:
(CASE WHEN m.EXTLOCATIONID is not null
THEN CONCAT('01', m.missionid)
ELSE CONVERT(VARCHAR(255), tg.ID_ACTIVITY)
END) as Barcode2

SQL COALESCE and IS NULL are not returning a space when when the query returns NULL

I am trying to optimize a humongous SQL query that was written by a self taught developer that used a ton of functions instead of JOINS. Anyway, I am having trouble displaying a space or a empty string('') when there is no value in the field selected. I've included only the SELECT in question. I am having the weirdest problem or just overlooking the correct answer in troubleshooting. Whenever I use COALESCE, when the field is supposed to be a blank string, it displays a zero. And when I use IS NULL, I get back NULL. All info online seems to point toward using COALESCE(value, '') as depicted in the code. But I am getting a 0 instead of ''. Does anyone see what I'm doing wrong? I'm using SSMS.
SELECT
pss8.dbo.xml_StripIllegalChars(dbo.rpt_get_series_volume(b.bookkey)) AS p_seriesvol --SELECT to be replaced that works but is slow due to function use I am told
,COALESCE(bd.seriesvolume, '') AS p_seriesvol --my SELECT that won't work!
FROM
bookdetail bd
WHERE
--bd.bookkey='303177'
bd.bookkey='6002'
The bookkeys at the bottom are for testing as I know the top one returns a 1 and the bottom one returns a '' previously when it worked. The SELECT above my commented SELECT is the code that works but is slow... According to what I read online, I am saying 'if there isn't a series volume number, then it equals an empty string.' Does COALESCE not work like this? Can it only return a 0 if the field has no value, or in this case, has no volume number? All help much appreciated. I'm very curious to hear a solution!
Here's more intel. This is how the this SELECT works:
pss8.dbo.xml_StripIllegalChars(dbo.rpt_get_series_volume(b.bookkey)) AS p_seriesvol
The
.rpt_get_series_vol
function manages to create an empty string with this code... Does this reveal anything?
DECLARE #RETURN
VARCHAR(5)
DECLARE #v_desc
VARCHAR(5)
DECLARE #i_volumenumber INT
SELECT #i_volumenumber = volumenumber
FROM bookdetail
WHERE bookkey = #i_bookkey and volumenumber <> 0
IF #i_volumenumber > 0
BEGIN
SELECT #RETURN = CAST(#i_volumenumber as varchar(5))
END
ELSE
BEGIN
SELECT #RETURN = ''
END
RETURN #RETURN
END
As you are looking for a '0' not a NULL COALESCE()is not useful, instead use a simple CASE:
select
...,
case bd.seriesvolume when '0' then '' else bd.seriesvolume end as p_seriesvol
from
...
Or if you want '' for 0 or NULL
case when bd.seriesvolume is null or bd.seriesvolume = '0' then '' else bd.seriesvolume end as p_seriesvo
COALESCE() function returns the 1st non null value
SELECT COALESCE(NULL, NULL, 'third_value', 'fourth_value'); returns the third value because the third value is the first value that is not null.
So in your case COALESCE(bd.seriesvolume, '') AS p_seriesvol if seriesvolume colum value is null then it will return blank string

Invalid argument for function integer IBM DB2

I need to filter out rows in table where numer_lini column has number in it and it is between 100 and 999, below code works just fine when i comment out line where i cast marsnr to integer. However when i try to use it i get error: Invalid character found in a character string argument of the function "INTEGER". when looking at the list seems like replace and translate filters only numbers just fine and select only contains legit numbers (list of unique values is not long so its easy to scan by eye). So why does it fail to cast something? I also tried using integer(marsnr), but it produces the same error. I need casting because i need numeric range, otherwise i get results like 7,80 and so on. As I mentioned Im using IBM DB2 database.
select numer_lini, war_trasy, id_prz1, id_prz2
from alaska.trasa
where numer_lini in (
select marsnr
from (
select
distinct numer_lini marsnr
from alaska.trasa
where case
when replace(translate(numer_lini, '0','123456789','0'),'0','') = ''
then numer_lini
else 'no'
end <> 'no'
)
where cast(marsnr as integer) between 100 and 999
)
fetch first 300 rows only
If you look at the optimized SQL from the Db2 explain, you will see that Db2 has collapsed your code into a single select.
SELECT DISTINCT Q2.NUMER_LINI AS "NUMER_LINI",
Q2.WAR_TRASY AS "WAR_TRASY",
Q2.ID_PRZ1 AS "ID_PRZ1",
Q2.ID_PRZ2 AS "ID_PRZ2",
Q1.NUMER_LINI
FROM ALASKA.TRASA AS Q1,
ALASKA.TRASA AS Q2
WHERE (Q2.NUMER_LINI = Q1.NUMER_LINI)
AND (100 <= INTEGER(Q1.NUMER_LINI))
AND (INTEGER(Q1.NUMER_LINI) <= 999)
AND (CASE WHEN (REPLACE(TRANSLATE(Q1.NUMER_LINI,
'0',
'123456789',
'0'),
'0',
'') = '') THEN Q1.NUMER_LINI
ELSE 'no' END <> 'no')
Use a CASE to force Db2 to do the "is integer" check first. Also, you don't check for the empty string.
E.g. with this table and data
‪create‬‎ ‪TABLE‬‎ ‪alaska‬‎.‪trasa‬‎ ‪‬‎(‪numer_lini‬‎ ‪VARCHAR‬‎(‪10‬‎)‪‬‎,‪‬‎ ‪war_trasy‬‎ ‪INT‬‎ ‪‬‎,‪‬‎ ‪id_prz1‬‎ ‪INT‬‎,‪‬‎ ‪id_prz2‬‎ ‪INT‬‎)‪;
insert into alaska.trasa values ('',1,1,1),('99',1,1,1),('500',1,1,1),('3000',1,1,1),('00300',1,1,1),('AXS',1,1,1);
This SQL works
select numer_lini, war_trasy, id_prz1, id_prz2
from alaska.trasa
where case when translate(numer_lini, '','0123456789') = ''
and numer_lini <> ''
then integer(numer_lini) else 0 end
between 100 and 999
Although that does fail if there is an embedded space in the input. E.g. '30 0'. To cater for that, a regular expressing is probably preferred. E.g.
select numer_lini, war_trasy, id_prz1, id_prz2
from alaska.trasa
where case when regexp_like(numer_lini, '^\s*[+-]?\s*((\d+\.?\d*)|(\d*\.?\d+))\s*$'))
then integer(numer_lini) else 0 end
between 100 and 999

SQL Doesnt Want to match strings with spaces for some reason

I have this SQL Query that is not comparing properly so I commented it out the WHERE clause. When returning the AF.ActivityNote it always has 2 spaces after it no matter if I do RTRIM on it or not. I think those spaces are the issue that wont let the commented WHERE clause to properly match the string against userfield33.
SELECT CAST(UF.UserField33 AS NVARCHAR) , RTRIM(CAST(AF.ActivityNote AS NVARCHAR))
FROM [BCMTEST01].[dbo].[ActivityContacts] as AC INNER JOIN [BCMTEST01].[dbo].[ActivityFullView] as AF
ON AC.ActivityID = AF.ActivityID INNER JOIN [BCMTEST01].[dbo].[OpportunityExportView] as OP
ON AC.ContactID = OP.ContactServiceID INNER JOIN [BCMTEST01].[dbo].[UserFields] as UF
ON OP.ContactServiceID = UF.ContactServiceID
WHERE ContactID = 8376
--WHERE RTRIM(CAST(UF.UserField33 AS NVARCHAR) = RTRIM(CAST(AF.ActivityNote AS NVARCHAR))
ORDER BY ContactID ASC
First, you should always include the length when converting to nvarchar, varchar, char, and nchar. So use something like:
cast(uf.userfield33 as nvarchar(255)) -- or whatever length you like, so long as you have something
The last two characters are not spaces. Do something like:
select ascii(right( AF.ActivityNote, 1))
To see what the character value is. You can then use replace to get rid of it. Or, you can just chop off the last two characters (if that works for your application).
By the way, I am assuming you are using SQL Server based on the syntax of the query.
Here is an alternative where clause:
where (case when right(AF.ActivityNote, 2) = char(10)+CHar(13)
then LEFT(AF.ActivityNote, LEN(AF.ActivityNote) - 2)
else AF.ActivityNote
end) = CAST(UF.UserField33 AS NVARCHAR(255)
I'm not a big fan of case statements in where clauses. I would actually put the logic in a subquery. Also, I might have the order of the 10/13 backwards.

SQL Query Not making Sense to me

I think my where clause is wrong.
My dilemma is, if user don't have a record in tbl_dentalBuyerInsurance that means they are taking all of it.
So if user don't have a record in tbl_dentalBuyerInsurance I want them to come back as a result.
I also want them to come back if they do have a record in tbl_dentalBuyerInsurance and it matches using LIKE or equal.
SELECT
[dbo].[tbl_users].*, [dbo].[tbl_dentalBuyerInsurance].*
FROM
[dbo].[tbl_users]
LEFT OUTER JOIN [dbo].[tbl_dentalBuyerInsurance] ON [dbo].[tbl_dentalBuyerInsurance].buyerId = [dbo].[tbl_users].id
LEFT OUTER JOIN [dbo].[tbl_dentalInsurance] ON [dbo].[tbl_dentalInsurance].id = [dbo].[tbl_dentalBuyerInsurance].dentalInsuranceId
WHERE
(
(
[dbo].[tbl_dentalInsurance].companyName LIKE '%Cigna%'
OR [dbo].[tbl_dentalInsurance].companyName = ''
)
AND(
[dbo].[tbl_dentalBuyerInsurance].ppo = 1
OR [dbo].[tbl_dentalBuyerInsurance].ppo = ''
)
AND(
[dbo].[tbl_dentalBuyerInsurance].hmo = 0
OR [dbo].[tbl_dentalBuyerInsurance].hmo = ''
)
)
Given you're using LEFT JOINS, if there's no matching records on the "right" side of the join, all of those right-side fields will be NULL, not empty strings. You'd have to explicitly check for that with .... OR whatever IS NULL, as NULL cannot ever be equal to anything, including itself.
[dbo].[tbl_dentalInsurance].companyName LIKE '%Cigna%'
OR [dbo].[tbl_dentalInsurance].companyName = ''
that means that you are allowinf empty strings, that's your first mistake, and how said MarcB if you are looking for null values so the query is :
[dbo].[tbl_dentalInsurance].companyName LIKE '%Cigna%'
OR [dbo].[tbl_dentalInsurance].companyName is null
if you are allowing empty string so you have to use len function for validate values with lenght 0
saludos