T-SQL get substring - sql

I am looking to get an order number from a column named KEY_Ref, this ref column have various contents, but some rows look like this
LINE_NO=15^ORDER_NO=176572^RELEASE_NO=1^
Now I am interested in getting the value for ORDER_NO (176572 in this case)
How would I (In SQL Server) go about getting this (Or other) value from the main string
The logic is always
key1=value1^key2=value2^key3=value3^

You can use string_split():
select t.*, s.orderno
from t outer apply
(select stuff(s.value, 1, 9, '') as orderno
from string_split(t.key_ref, '^') s
where s.value like 'ORDER_NO=%'
) s;
Here is a db<>fiddle.

this is going to be a bit lengthy answer however if your SQL server version doesn't support string_split function you may use this.
declare #str varchar(100) = 'LINE_NO=15^ORDER_NO=176572^RELEASE_NO=1^'
declare #substr1 varchar(50) = substring(#str,charindex('^',#str)+1,len(#str))
declare #substr2 varchar(50) = substring(#substr1,charindex('=',#substr1)+1,charindex('^',#substr1)-charindex('=',#substr1)-1)
select #substr2 as 'order number'
the final variable will produce the desired value and you must merge the above queries to a single query that can fetch the value from the table in a single select statement.
this will work only if the pattern doesn't deviate from the one you've mentioned.

Related

Anything like template literals while writing a search query in SQL?

I am writing a stored procedure to get a particular value.
declare #num int
set #num = (SELECT Id
FROM [sometable]
WHERE Name like '%today%')
-- returns #num = 1
Select Value
FROM [anothertable]
where name like 'days1'
In the last line of the query I want to add "1" or any other number after 'days', depending on the variable #num.
How can I do it, sort of like how we use template literals in Javascript, using the ${} syntax but in SQL?
You can just use the first query as a sub-query of the second:
select [Value]
from anothertable
where [name] = Concat('days', (select Id from sometable where [Name] like '%today%'));

Can you concatenate a string value multiple times in a PostgreSql SELECT statement?

In Sql Server you can run the following query to combine values from multiple rows into a single string variable.
DECLARE #x NVARCHAR(MAX) = N'';
SELECT TOP 5 #x = #x + name + ', '
FROM sys.objects
SELECT #x
Which results in
"sysrscols, sysrowsets, sysclones, sysallocunits, sysfiles1,"
Is there a way to do something similar in PostgreSql? I've tried creating a PostgreSql function that does a SELECT INTO stringVariable but that is only resulting in a single row's worth of values.
Not exactly. The code you have in SQL Server is not actually guaranteed to work. In Postgres, you would use:
select string_agg(name, ', ')
from sys.objects;
If you have a sys.objects table.
Note that in SQL Server, you should do the same thing:
select string_agg(name, ', ')
from sys.objects;
as demonstrated in this SQL Fiddle.
As a note: Your use of the variable is directly contradicted by the documentation:
If a SELECT statement returns more than one row and the variable references a non-scalar expression, the variable is set to the value returned for the expression in the last row of the result set.
That said, I know what you are doing actually works in practice. But I would recommend using string_agg() or in earlier versions using XML for string concatenation.

How to put result of one column inside a string variable?

I try to select number of rows and then put them into string variable such as 1,2,3,4,5, but get this error :
Subquery returned more than 1 value. This is not permitted when the
subquery follows =, !=, <, <= , >, >= or when the subquery is used as
an expression.
I use MSSQL SERVER
DECLARE #CodeNameString VARCHAR(MAX)
SELECT #CodeNameString = STUFF(
(
SELECT dbo.CharterReference.TicketNo+','
FROM dbo.CharterReference
),
1,
1,
''
)
SELECT #CodeNameString
How can i fix this?
If you want the values in #CharterReference, you can use the following
Declare #CharterReference table (TicketNo int)
Insert Into #CharterReference values
(1),(2),(3),(4),(5),(6),(7),(8)
Declare #CodeNameString varchar(Max) = '>>>'
Select #CodeNameString =replace(concat(#CodeNameString ,',',TicketNo),'>>>,','')
From #CharterReference
Where TicketNo between 1 and 5
Order By TicketNo
Select #CodeNameString
Returns
1,2,3,4,5
Or you can use a little XML
Select #CodeNameString=Stuff((Select ',' +cast(TicketNo as varchar(25))
From #CharterReference
Where TicketNo between 1 and 5
For XML Path ('')
),1,1,'')
The error message is complaining because you have multiple rows returned, and that is not allowed in the way you have done this.
Rearranging to a normal looking select statement, and then lopping off the last comma afterwards would work around this:
DECLARE #CodeNameString VARCHAR(MAX);
set #CodeNameString = '';
SELECT #CodeNameString = TicketNo + ','
FROM dbo.CharterReference;
SELECT left(#CodeNameString, len(#CodeNameString)-1) as CodeNameString;
The SQL-based solution requires you to use recursive SQL for this. The syntax is typically DBMS-specific, and guessing by the syntax you're using in the example, O believe your engine calls this feature "recursive CTE".
The alternative is to cursor over the result set with the individual row and construct the string append in your client program.
Yet another alternative is to use the PL/SQL dialect of your system. You can then write an SQL procedure where you do the cursoring over the result set and the string appending. You can expose this SQL procedure as a callable module to your client programs.

String manipulation SQL

I have a row of strings that are in the following format:
'Order was assigned to lastname,firsname'
I need to cut this string down into just the last and first name but it is always a different name for each record.
The 'Order was assigned to' part is always the same.......
Thanks
I am using SQL Server. It is multiple records with different names in each record.
In your specific case you can use something like:
SELECT SUBSTRING(str, 23) FROM table
However, this is not very scalable, should the format of your strings ever change.
If you are using an Oracle database, you would want to use SUBSTR instead.
Edit:
For databases where the third parameter is not optional, you could use SUBSTRING(str, 23, LEN(str))
Somebody would have to test to see if this is better or worse than subtraction, as in Martin Smith's solution but gives you the same result in the end.
In addition to the SUBSTRING methods, you could also use a REPLACE function. I don't know which would have better performance over millions of rows, although I suspect that it would be the SUBSTRING - especially if you were working with CHAR instead of VARCHAR.
SELECT REPLACE(my_column, 'Order was assigned to ', '')
For SQL Server
WITH testData AS
(
SELECT 'Order was assigned to lastname,firsname' as Col1 UNION ALL
SELECT 'Order was assigned to Bloggs, Jo' as Col1
)
SELECT SUBSTRING(Col1,23,LEN(Col1)-22) AS Name
from testData
Returns
Name
---------------------------------------
lastname,firsname
Bloggs, Jo
on MS SQL Server:
declare #str varchar(100) = 'Order was assigned to lastname,firsname'
declare #strLen1 int = DATALENGTH('Order was assigned to ')
declare #strLen2 int = len(#str)
select #strlen1, #strLen2, substring(#str,#strLen1,#strLen2),
RIGHT(#str, #strlen2-#strlen1)
I would require that a colon or some other delimiter be between the message and the name.
Then you could just search for the index of that character and know that anything after it was the data you need...
Example with format changing over time:
CREATE TABLE #Temp (OrderInfo NVARCHAR(MAX))
INSERT INTO #Temp VALUES ('Order was assigned to :Smith,Mary')
INSERT INTO #Temp VALUES ('Order was assigned to :Holmes,Larry')
INSERT INTO #Temp VALUES ('New Format over time :LootAt,Me')
SELECT SUBSTRING(OrderInfo, CHARINDEX(':',OrderInfo)+1, LEN(OrderInfo))
FROM #Temp
DROP TABLE #Temp

SQL Server - Replacing Single Quotes and Using IN

I am passing a comma-delimited list of values into a stored procedure. I need to execute a query to see if the ID of an entity is in the comma-delimited list. Unfortunately, I think I do not understand something.
When I execute the following stored procedure:
exec dbo.myStoredProcedure #myFilter=N'1, 2, 3, 4'
I receive the following error:
"Conversion failed when converting the varchar value '1, 2, 3, 4' to data type int."
My stored procedure is fairly basic. It looks like this:
CREATE PROCEDURE [dbo].[myStoredProcedure]
#myFilter nvarchar(512) = NULL
AS
SET NOCOUNT ON
BEGIN
-- Remove the quote marks so the filter will work with the "IN" statement
SELECT #myFilter = REPLACE(#myFilter, '''', '')
-- Execute the query
SELECT
t.ID,
t.Name
FROM
MyTable t
WHERE
t.ID IN (#myFilter)
ORDER BY
t.Name
END
How do I use a parameter in a SQL statement as described above? Thank you!
You could make function that takes your parameter, slipts it and returns table with all the numbers in it.
If your are working with lists or arrays in SQL Server, I recommend that you read Erland Sommarskogs wonderful stuff:
Arrays and Lists in SQL Server 2005
You need to split the string and dump it into a temp table. Then you join against the temp table.
There are many examples of this, here is one at random.
http://blogs.microsoft.co.il/blogs/itai/archive/2009/02/01/t-sql-split-function.aspx
Absent a split function, something like this:
CREATE PROCEDURE [dbo].[myStoredProcedure]
#myFilter varchar(512) = NULL -- don't use NVARCHAR for a list of INTs
AS
SET NOCOUNT ON
BEGIN
SELECT
t.ID,
t.Name
FROM
MyTable t
WHERE
CHARINDEX(','+CONVERT(VARCHAR,t.ID)+',',#myFilter) > 0
ORDER BY
t.Name
END
Performance will be poor. A table scan every time. Better to use a split function. See: http://www.sommarskog.se/arrays-in-sql.html
I would create a function that takes your comma delimited string and splits it and returns a single column table variable with each value in its own row. Select that column from the returned table in your IN statement.
I found a cute way of doing this - but it smells a bit.
declare #delimitedlist varchar(8000)
set #delimitedlist = '|1|2|33|11|3134|'
select * from mytable where #delimitedlist like '%|' + cast(id as varchar) + '|%'
So... this will return all records with an id equal to 1, 2, 33, 11, or 3134.
EDIT:
I would also add that this is not vulnerable to SQL injection (whereas dynamic SQL relies on your whitelisting/blacklisting techniques to ensure it isn't vulnerable). It might have a performance hit on large sets of data, but it works and it's secure.
I have a couple of blog posts on this as well, with a lot of interesting followup comments and dialog:
More on splitting lists
Processing list of integers