T-SQL Right Function default value - sql-server

I am working towards migrating an access Right() function onto SQL Server.
This is the Access Right() function:
Barcode: "ID" & (Right(String(8,"0") & [Job Number],8) & Right(String(6,"0") &
[PART LIBARY HEADER_1]![PartID],6) & Right(String(6,"0") & [Part Assembly Link
Table]![AssemblyLinkID],6))
What the above expression does, is that it dynamically creates a field to house a barcode that is always 22 characters in length. Now the values of these barcodes are determined by other columns.
I am using the Right() method to gather the Rightmost: 8 chars of Job Number, 6 chars of PartID and 6 chars of AssemblyLinkID.
Now the problem I face is that whilst I can move these values onto T-SQL, I having difficulty setting the default value to be = 0.
For example the following input:
Job Number: 123456
PartID: 9876
AssemblyLinkID: 127
Would need to return… ID00123456009876000127
The String() function in access is handling the null values for me by appending with 0 but this method is not something available in SQL Server.
String(8,"0")
This is my SQL Code so far:
Concat('ID', RIGHT(STR(0, 8) & [Job Number],8)) AS Barcode,
STR() is not the function I am looking to use as it is not giving the same results as MS Access's String().

This does the job you want:
declare #t table ([Job NUmber] int, PartID int, AssemblyLinkID int)
insert into #t ([Job NUmber], PartID, AssemblyLinkID) values(123456,9876,127)
select
'ID' +
RIGHT('00000000' + CONVERT(varchar(8),[Job Number]),8) +
RIGHT('000000' + CONVERT(varchar(6),PartID),6) +
RIGHT('000000' + CONVERT(varchar(6),AssemblyLinkID),6)
from #t
You can use REPLICATE as an exact analogue for your STRING calls but since the string literals are shorter than the method call, I prefer them.
Not sure quite what your point was around nulls, but if any of these columns may be NULL, then you may way to use COALESCE as well:
declare #t table ([Job NUmber] int, PartID int, AssemblyLinkID int)
insert into #t ([Job NUmber], PartID, AssemblyLinkID) values(123456,9876,127)
select
'ID' +
RIGHT('00000000' + COALESCE(CONVERT(varchar(8),[Job Number]),''),8) +
RIGHT('000000' + COALESCE(CONVERT(varchar(6),PartID),''),6) +
RIGHT('000000' + COALESCE(CONVERT(varchar(6),AssemblyLinkID),''),6)
from #t
(Here we'll get all zeros for a NULL value. If you want something different, substitute that into the empty string towards the end of each expression)

Right(String(8,"0") & [Job Number],8) =
RIGHT(REPLICATE('0', 8) + ISNULL([Job Number], ''), 8)

Related

how to get the words after the slash in SQL query

I have a date which look like this "Corporate Services\Corporate Affairs & Communications(DP19)"
I want to the result to be like this:
Column A
Column B
Corporate Service
Corporate Affairs & Communications (DP19)
I already tried using substring but no luck,
I am using Microsoft SQL
DECLARE #AData VARCHAR(1000) = 'Corporate Services\Corporate Affairs & Communications(DP19)';
SELECT
LEFT(#AData, CHARINDEX('\', #AData) - 1) AS [Column A],
SUBSTRING(#AData, CHARINDEX('\', #AData) + 1, LEN(#AData)) AS [Column B];
I kind of cheated with using LEN(#AData) for the Length parameter of the SUBSTRING() function used in Column B, but SUBSTRING() doesn't care, so no harm no foul:
length
...If the sum of start and length is greater than the number of characters in expression, the whole value expression beginning at start is returned.
you can use PARSENAME
declare #t table(ch varchar(max))
insert into #t values
(N'Corporate Services\Corporate Affairs & Communications(DP19)');
SELECT
PARSENAME(REPLACE(ch,'\','.'),2) AS N'Column A' ,
PARSENAME(REPLACE(ch,'\','.'),1) AS N'Column B'
FROM #t

How do I enable ordinals from the STRING_SPLIT function in MSSQL

I'm trying to use the STRING_SPLIT function in Microsoft SQL Server 2019. The function works, if I only put in two arguments, but since I want to extract a specific element from the string, I would like to enable ordinals.
When I add the third argument to the STRING_SPLIT function it returns
Msg 8144, Level 16, State 3, Line 5 Procedure or function STRING_SPLIT
has too many arguments specified.
I don't understand what I'm doing wrong, since hovering over the STRING_SPLIT function clearly states that the function can take a third argument as an int.
My SQL code is as follows
SELECT *
FROM STRING_SPLIT('[Control Structure].Root.NP_02.ABC01_02_03.Applications.Prototype.Control Modules.ABC060V.ABC060VXFR2','.',1)
WHERE ORDINAL = 4
You can't enable it, since it is not available in SQL Server 2019 (and is almost certainly not going to be back-ported there).
The problem is that SSMS has IntelliSense / tooltips coded without conditional logic based on version, and the code is ahead of the engine. Currently the functionality is only available in Azure SQL Database, Managed Instance, and Synapse.
From the documentation:
The enable_ordinal argument and ordinal output column are currently only supported in Azure SQL Database, Azure SQL Managed Instance, and Azure Synapse Analytics (serverless SQL pool only).
Some more background:
Trusting STRING_SPLIT() order in Azure SQL Database
What you can do instead is create your own inline table-valued UDF that provides the same type of ordinal output (and make it return the same output as STRING_SPLIT to make it easy to change later). There are many variations on this; here's one:
CREATE FUNCTION dbo.SplitStrings_Ordered
(
#List nvarchar(max),
#Delimiter nvarchar(255)
)
RETURNS TABLE
AS
RETURN (SELECT value = Item ,
ordinal = ROW_NUMBER() OVER (ORDER BY Number),
FROM (SELECT Number, Item = SUBSTRING(#List, Number,
CHARINDEX(#Delimiter, #List + #Delimiter, Number) - Number)
FROM (SELECT ROW_NUMBER() OVER (ORDER BY s1.[object_id])
FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2) AS n(Number)
WHERE Number <= CONVERT(INT, LEN(#List))
AND SUBSTRING(#Delimiter + #List, Number, LEN(#Delimiter)) = #Delimiter
) AS y);
GO
Another simpler way would be to use JSON, which I forgot I even wrote recently in this tip:
CREATE FUNCTION dbo.SplitStrings_Ordered
(
#List nvarchar(max),
#Delimiter nchar(1)
)
RETURNS table WITH SCHEMABINDING
AS
RETURN
(
SELECT value, ordinal = [key]
FROM OPENJSON(N'["' + REPLACE(#List, #Delimiter, N'","') + N'"]') AS x
);
GO
Also, if you're just trying to get the last ordinal in a (1-)4-part name and each part is <= 128 characters, you can use PARSENAME():
DECLARE #str nvarchar(512) = N'here is one.here is two.and three.and four';
SELECT p1 = PARSENAME(#str, 4),
p2 = PARSENAME(#str, 3),
p3 = PARSENAME(#str, 2),
p4 = PARSENAME(#str, 1);
Output:
p1
p2
p3
p4
here is one
here is two
and three
and four
Example db<>fiddle
We can sort of cheat our way around ordinal as our order by using the current order instead. Keep in mind that the default order for STRING_SPLIT is non-deterministic:
STRING_SPLIT() reference
The output rows might be in any order. The order is not guaranteed to match the order of the substrings in the input string. You can override the final sort order by using an ORDER BY clause on the SELECT statement, for example, ORDER BY value or ORDER BY ordinal.
DECLARE #object as nvarchar(500) = 'test_string_split_order_string'
select
value,
ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS RowNum
from STRING_SPLIT(#object, '_')
SQL Server's XML/XQuery allow to implement very easy tokenization of a string.
XML/XQuery data model is based on ordered sequences.
It allows to retrieve any token based on its position is a string of tokens.
SQL
DECLARE #tokens VARCHAR(256) = '[Control Structure].Root.NP_02.ABC01_02_03.Applications.Prototype.Control Modules.ABC060V.ABC060VXFR2'
, #separator CHAR(1) = '.'
, #pos INT = 4;
SELECT c.value('(/root/r[sql:variable("#pos")]/text())[1]', 'VARCHAR(100)') AS token
FROM (SELECT TRY_CAST('<root><r><![CDATA[' +
REPLACE(#tokens, #separator, ']]></r><r><![CDATA[') +
']]></r></root>' AS XML)) AS t(c);
Output
+-------------+
| token |
+-------------+
| ABC01_02_03 |
+-------------+
yet another way (with ';' as delimiter)
create function dbo.split_string_ord
(
#sentence nvarchar(max)
)
returns table
as
return(
with first_word(ordinal,word,sentence) as (
Select
1 as ordinal,
substring(#sentence+';',1,charindex(';',#sentence+';',1)-1) as word,
substring(#sentence+';',charindex(';',#sentence+';',1)+1,LEN(#sentence+';')-charindex(';',#sentence+';',1)+1) as sentence
union all
Select
ordinal + 1 as ordinal,
substring(sentence,1,charindex(';',sentence,1)-1) as word,
substring(sentence,charindex(';',sentence,1)+1,LEN(sentence)-charindex(';',sentence,1)+1) as sentence
from
first_word
where
sentence != ''
)
Select
ordinal,
word
from
first_word
)
;

Get 3rd part of text field in SQL Server

I have a table in my SQL Server database with a column of type NTEXT. The column holds address information, like this:
"Company name
Street + number
Postalcode + City
Country"
Sometimes the country is not there, but the first 3 lines are always there.
How would I go about selecting only line 3?
Each line is separated with CR + LF (\r\n)
I need this as part of a SQL Server stored procedure and the column I use is called RecipientAddress
The reason why I need this to be done within an SP is that I use the data to create a Crystal Report.
Or is there a way to do this within a formula in Crystal Reports?
EDIT: The datatypes used for the fields cannot be changed at the moment, since fields are part of an ERP system, where we are not able to change the datatypes.
I didn't use patindex because I suppose you are not using SS2014/16
It works on a set of addresses but can be change to work on only 1 value at a time using a variable
I used 2 CTE because it is easier to read and write the query this way. You can use intermediary variables instead if you work on only 1 address in a variable.
Code below can be tested in Management Studio (it creates 1 with country and 1 without country):
declare #delim varchar(10) = char(13)+char(10)
declare #table table(ID int, Address varchar(max))
insert into #table(ID, Address) values(0, 'Company name1
Street 1000
92345 City
Country')
insert into #table(ID, Address) values(1, 'Company name
Street 1000
92345 City')
; With row_start as(
Select ID, Address, pos_start = charindex(#delim, Address, charindex(#delim, Address, 0)+1)+len(#delim)
From #table
)
, row_end as (
Select ID, Address, pos_start, pos_end = charindex(#delim, Address,pos_start+1)
From row_start
)
Select ID, Address
, Zip_City = substring(Address, pos_start, (case when pos_end = 0 then len(Address)+1 else pos_end end) - pos_start)
From row_end

T-SQL function to convert int to varchar with plus/minus sign

While I've been troubled by annoying SQL operations, I've got another T-SQL problem.
I have to convert some Int variables into zero-filled varchar with plus/minus sign.
I have tried RIGHT() and CONVERT() functions so far,
RIGHT('000000' + CONVERT(value1 AS VARCHAR(6)), 6)
but I couldn't figure out what the best way to convert them.
What I would like to see is:
If value1 = 305 then '+000305'
If value1 = -110 then '-000110'
Is there any simple function to achieve this? Or should I have to create my own function for this?
I know it's stupid question, but my current task requires a lot of such non-sense tasks to Stored Procedures (database-side) rather than 'application-side'.
Thanks.
You want to use CAST instead of CONVERT when you structure it that way. There's no standard function that will do what you want, but you could create an expression like this to get what you need:
LEFT(REPLACE(SIGN(value1),'1','+'),1) + RIGHT('000000' + CAST(ABS(value1) AS VARCHAR(6)), 6)
If you want to use CONVERT it would look like:
LEFT(REPLACE(SIGN(value1),'1','+'),1) + RIGHT('000000' + CONVERT(VARCHAR(6),ABS(value1)), 6)
Just for fun, here's another way you could do it:
LEFT(REPLACE(SIGN(value1),'1','+'),1) + REPLACE(STR(ABS(value1),5),' ','0')
For SQL 2012 and above, you can use FORMAT().
DECLARE #yourTable TABLE (nums INT);
INSERT INTO #yourTable VALUES (305),(-110);
SELECT RIGHT('+' + FORMAT(nums,'00000#'),7) AS formatted_nums
FROM #yourTable
Results:
formatted_nums
--------------
+000305
-000110
may be this one can achieved in both ways using REPLACE or Replicate function.
DECLARE #t TABLE (Num INT)
INSERT #t
SELECT 305
UNION SELECT -110
SELECT CASE WHEN Num < 0 THEN '-' ELSE '+' END +
replace(RIGHT('00000'+ CONVERT(VARCHAR,Num),8),'-','0') AS NUM
FROM #t
SELECT CASE WHEN Num < 0 THEN '-' ELSE '+' END +
RIGHT(Replicate('0',6) + CONVERT(VARCHAR,Abs(Num)), 6)
FROM #t

SQL Server converting a variable varchar field to money/decimal/something with decimal places

I'm looking for an elegant way to convert a field of type varchar, with variable data in it, to a data type which can be used for mathematical operations sample data from the field
(excluding quotes)
''
'abc'
'23'
'23.2'
The method should work for all, and for the first & second values should return 0, and not throw an SQL Server error..
Try this:
SELECT CASE WHEN IsNumeric(YourColumn) = 0 THEN
0
ELSE
CAST(YourColumn AS decimal(18, 2))
END
You have to adjust the destination data type, I have chosen decimal(18, 2) for demonstration.
I know this is a long-dead thread, but I recently stumbled upon it from a Google search and had a thought. It is less elegant than a CASE statement, but it is an alternative.
SELECT
COALESCE(CAST(NULLIF(ISNUMERIC(LEFT(MyColumn, PATINDEX('% %', MyColumn + ' ') - 1)), 1) AS MONEY), LEFT(MyColumn, PATINDEX('% %', MyColumn + ' ') - 1))
FROM
myTable
or you could do:
Select COALESCE(CAST(NULLIF(ISNUMERIC(MyColumn), 1) AS MONEY), MyColumn)
FROM
myTable
The top version would see "2 5" as just 2, the bottom one would see it as a text field.
SELECT CASE IsNumeric(mycol) WHEN 1 THEN CAST(mycol AS FLOAT) ELSE 0 END
FROM mytable
If you'd like to convert it, you should use UPDATE instead of SELECT
UPDATE Table
SET Col1 = CAST(Col1 As Decimal(18,2))
COALESCE is a great option for this: Find more information here. It evaluates the arguments in order and returns the current value of the first expression that initially does not evaluate to NULL.
ISNUMERIC returns 0 or 1 depending on if the value being evaluated could be considered one of the SQL 'number' or 'numeric' types. e.g. int, bigint, money..
NULLIF essentially finds the value you specify and if it matches it replaces it with a NULL value.
CAST Simply changes a data type to another in this example to MONEY
As you can see, if you break the below down using this information its quite an elegant solution I think?
COALESCE(CAST(NULLIF(ISNUMERIC(COL1), 1) AS MONEY), COL1)

Resources