Split alpha and numeric using sql -followup Q - sql

This is actually a follow-up question to a topic mentioned here:
split alpha and numeric using sql
Facing similar problems, I adjusted #knkarthick24 (a chance to say tnx!) query to my needs almost perfectly (I have “2,500” not “2 500”) as follow:
SELECT [Quantity]
,substring(replace(subsrtunit, ',', ''), PATINDEX('%[0-9.]%', replace(subsrtunit, ',', '')) + 1, len(subsrtunit)) AS unit
,LEFT(replace(subsrtnumeric, ',', ''), PATINDEX('%[^0-9.]%', replace(subsrtnumeric, ',', '') + 't') - 1) AS num
FROM (
SELECT [Quantity]
,subsrtunit = SUBSTRING([Quantity], posofchar, LEN([Quantity]))
,subsrtnumeric = SUBSTRING([Quantity], posofnumber, LEN([Quantity]))
FROM (
SELECT [Quantity]
,posofchar = PATINDEX('%[^0-9.]%', replace([Quantity], ',', ''))
,posofnumber = PATINDEX('%[0-9.]%', replace([Quantity], ',', ''))
FROM [OPI].[dbo].[MRRInvoices]
WHERE DocumentNum IS NOT NULL
) d
) t
the only thing left is handling negative values.
Right now the results I'm getting for a negative value in Quantity field (-1.00 GB) is (.00 GB) in the unit field and (1.00) for num field.
Also, does anyone know how to "translate" it to derived column in SSIS?
Can "Findstring" in SSIS replace PATINDEX?
Thank you all in advance.
!1[img]

Related

SQL - Remove Duplicate value between two columns

I'm looking a simple way to remove an unwanted Duplicate value.
The Dupe is part of a reference to another column, and not within the column itself, but the column I want to remove the dupe value from is multi-delimited with other values.
Here is an example table:
ID,Thing
Dog,Cat;Dog;Bird
Snake,Horse;Fish;Snake
Car,Car;Bus;Bike
As you can see Dog,Snake,Car are the values I need to remove from the Thing column.
Output:
ID,Thing
Dog,Cat;Bird
Snake,Horse;Fish
Car,Bus;Bike
Is there a way to match within a multidelimited field and pull out the exact match?
I'm using SQL Server MGMT studio. Thanks.
WITH CTE AS
(
SELECT ID, Thing, ROW_NUMBER() OVER (PARTITION BY Thing) AS rn
)
DELETE
FROM CTE
WHERE rn > 1
I believe this will do it. Test first by running just the CTE part of the query so you can see what rn is.
Your question and sample data is not very clear. I think what you want is to remove anything from the second column that is in the first column, in which case you can try using replace
select Id,
replace(replace(thing,id,''),';;',';')
from table
Storing multi-value elements in a column is never a good idea and is a conflict of interest with the relational data model; it pretty much always causes problems at some point.
What you can do is concatenate a leading and a trailing ; to the value of Thing and then replace the value of ID with an empty string.
Then remove the leading and trailing ;.
If your version of SQL Server is 2017+, you can use the function TRIM():
SELECT Id,
TRIM(';' FROM REPLACE(';' + Thing + ';', ';' + ID + ';', ';')) Thing
from tablename;
For previous versions use SUBSTRING():
SELECT Id,
SUBSTRING(
REPLACE(';' + Thing + ';', ';' + ID + ';', ';'),
2,
LEN(REPLACE(';' + Thing + ';', ';' + ID + ';', ';')) - 2
) Thing
from tablename;
If you want to update the table:
UPDATE tablename
SET Thing = TRIM(';' FROM REPLACE(';' + Thing + ';', ';' + ID + ';', ';'));
or:
UPDATE tablename
SET Thing = SUBSTRING(
REPLACE(';' + Thing + ';', ';' + ID + ';', ';'),
2,
LEN(REPLACE(';' + Thing + ';', ';' + ID + ';', ';')) - 2
);
See the demo.
I don't really understand what "multi-delimited" means with respect to a string. In your context it seems to suggest that you might have different types of delimiters. It definitely does mean that you have a really poor data model. If you want to remove the id from the things column, then my first suggestion is to fix the delimiters.
In SQL Server, you could use:
select t.*,
(select string_agg(s.value, ';')
from string_split(replace(t.things, ',', ';'), ';') s
where s.value <> t.id
) as new_things
from t;
If the delimited have some intrinsic meaning (did I mentioned that you should fix the data model?), then you can use a more brute force approach. Here is one method:
select t.*,
(case when things = id then ''
when things like concat(id, '[,;]%')
then stuff(things, 1, len(id) + 1, '')
when things like concat('%[,;]', id)
then left(things, len(things) - len(id) - 1)
when things like concat('%[,;]', id, '[,;]%')
then stuff(things, patindex(concat('%[,;]', id, '[,;]%'), things), len(id) + 1, '')
else things
end)
from t;
Here is a db<>fiddle.
Your Question is a good one. I used simple case statement to get the answer. It is CHARINDEX that helped to find the location of the value in Id column and then identified the position of the value in id and according to the position, string was replaced by required values.
--Preparing the table
SELECT *
INTO t
FROM (VALUES
('Dog', 'Cat;Dog;Bird'),
('Snake', 'Horse;Fish;Snake'),
('Car', 'Car;Bus;Bike')
) v(id, things)
--Query
SELECT id
,CASE WHEN CHARINDEX(reverse(id), reverse(things), 1) = 1 THEN REPLACE(things,';'+id ,'')
WHEN CHARINDEX(id, things, 1) < LEN(things) AND CHARINDEX(id, things, 1) > 1 THEN REPLACE(things, id +';' ,'')
WHEN CHARINDEX(id, things, 1) = 1 THEN REPLACE(things, id +';' ,'')
ELSE 'End'
END as [things]
FROM t

SQL Server - Extract text from a given string field

What is the best method to extract the text from the string field below?
I am trying to extract the ProjectID numbers (91, 108, 250) below but am struggling because the ProjectIDs are either 2 or 3 integers long and are within different parts of the string.
Row Parameter
1 ProjectID=91&GroupID=250&ParentID=1
2 ProjectID=108&GroupID=250&ParentID=35
3 GroupID=1080&ProjectID=250&ParentID=43
4 ProjectID=250
Any help would be much appreciated.
SQL Server is kind of lousy on string functionality. Here is one method:
select left(v1.p, patindex('%[^0-9]%', v1.p + ' ') - 1)
from (values ('ProjectID=91&GroupID=250&ParentID=1'),
('ProjectID=108&GroupID=250&ParentID=35'),
('GroupID=1080&ProjectID=250&ParentID=43'),
('ProjectID=250')
) v(parameter) cross apply
(values (stuff(v.parameter, 1, charindex('ProjectID=', v.parameter) + 9, ''))
) v1(p);
Or split the string and look for a match:
select stuff(s.value, 1, 10, '')
from (values ('ProjectID=91&GroupID=250&ParentID=1'),
('ProjectID=108&GroupID=250&ParentID=35'),
('GroupID=1080&ProjectID=250&ParentID=43'),
('ProjectID=250')
) t(parameter) cross apply
string_split(t.parameter, '&') s
where s.value like 'ProjectId=%';
Here is a db<>fiddle.
SELECT
substring ( #Parameter,
CHARINDEX('ProjectID', #Parameter) + 10,
CHARINDEX('&', #parameter, CHARINDEX('ProjectID', #Parameter)) -
(CHARINDEX('ProjectID', #Parameter) + 10))
from table

T-SQLpad leading zeros in string for values between "." character

I want to convert numbers to 3 decimal places for each number between the character ".". For example:
1.1.5.2 -> 001.001.005.002
1.2 -> 001.002
4.0 -> 004.000
4.3 ->004.003
4.10 -> 004.010
This is my query:
SELECT ItemNo
FROM EstAsmTemp
This is fairly easy once you understand all the steps:
Split the string into the individual data points.
Convert the parsed values into the format you want.
Shove the new values back into a delimited list.
Ideally you shouldn't store data with multiple datapoints in a single intersection like this but sometimes you just have no choice.
I am using the string splitter from Jeff Moden and the community at Sql Server Central which can be found here. http://www.sqlservercentral.com/articles/Tally+Table/72993/. There are plenty of other decent string splitters out there. Here are some excellent examples of other options. http://sqlperformance.com/2012/07/t-sql-queries/split-strings.
Make sure you understand this code before you use it in your production system because it will be you that gets the phone call at 3am asking for it to be fixed.
with something(SomeValue) as
(
select '1.1.5.2' union all
select '1.2' union all
select '4.0' union all
select '4.3' union all
select '4.10'
)
, parsedValues as
(
select SomeValue
, right('000' + CAST(x.Item as varchar(3)), 3) as NewValue
, x.ItemNumber as SortOrder
from something s
cross apply dbo.DelimitedSplit8K(SomeValue, '.') x
)
select SomeValue
, STUFF((Select '.' + NewValue
from parsedValues pv2
where pv2.SomeValue = pv.SomeValue
order by pv2.SortOrder
FOR XML PATH('')), 1, 1, '') as Details
from parsedValues pv
group by pv.SomeValue
I decided to change it in the presentation layer, per Zohar Peled's comment.
You did not mention the number of '.' separator a column can have. I assume, the max is 4 and the solution is below.
SELECT STUFF(ISNULL('.' + RIGHT('000' + PARSENAME(STRVALUE,4),4),'') + ISNULL('.' + RIGHT('000' + PARSENAME(STRVALUE,3),4) ,'') + ISNULL('.' + RIGHT('000' + PARSENAME(STRVALUE,2),4) ,'') + ISNULL('.' + RIGHT('000' + PARSENAME(STRVALUE,1),4),''),1,1,'')
FROM (VALUES('1.1.5.2'), ('1.2'), ('4.0'),('4.3'), ('4.10')) A (STRVALUE)

SQL Select, how to display numeric as money and reverse - numbers to positive

I have a numeric column formatted that contains data like:
8547.22
-1254.22
For reasons beyond my control I need to present the results of a select in this format (this is one field of a much larger select statement) I can't add any new functions either.
-$8,547.22
$1,254.22
So to be clear I need to add money formatting ('$' and ',') and also reverse positive numbers to negative and vice versa.
I've tried the following which obviously doesn't work:
case
when a.principal_outstanding like '-%'
then '$' + (SELECT RIGHT(REPLACE(CONVERT(varchar(20), (CAST(SUM(a.principal_outstanding) AS money)), 1), '.00', ''), LEN((REPLACE(CONVERT(varchar(20), (CAST(SUM(a.principal_outstanding) AS money)), 1), '.00', '')))) - 1)
when a.principal_outstanding not like '-%'
then '-' + '$' + (REPLACE(CONVERT(varchar(20), (CAST(SUM(a.principal_outstanding) AS money)), 1), '.00', ''))
else 'ERROR2'
end as '<currentBalance>'
Any suggestions?
If you must do this in your SQL query (and not the client):
SELECT '$' + CONVERT(VARCHAR, CAST(TheValue * -1 AS MONEY), 1)
FROM TheTable
Edit: Since you're using negative numbers, it gets even more ugly, but does the job.
SELECT CASE WHEN TheValue <= 0
THEN '$' + CONVERT(VARCHAR, CAST(TheValue * -1 AS MONEY), 1)
ELSE '-$' + CONVERT(VARCHAR, CAST(TheValue AS MONEY), 1)
END
FROM TheTable

Extract multiple decimal numbers from string in T-SQL

I have a table in SQL Server Management Studio with columns containing ranges of numbers as strings. I am trying to find a way to extract the numeric values from the string and insert them into a new table.
For example, in the table I have the value 12.45% - 42.32% as a string. I'd like to be able to get 12.45 and 42.32 and insert them into a new table with columns min_percent and max_percent.
I found several ways to extract a single numeric value from a string using SQL, and also tried modifying the function from Extract numbers from a text in SQL Server (which returns multiple integers, but not decimals), but so far I haven't been able to get it working. Thanks in advance for any suggestions
Assuming your data is consistent, this should work fine, and has the added advantage of being easier on the eyes. Also consider decimal if you're going for precision.
select
cast(left(r, charindex('%', r) - 1) AS float) as minVal,
cast(replace(right(r, charindex('-', r) - 1), '%', '') as float) AS maxVal
from ( select '22.45% - 42.32%' as r ) as tableStub
The function is quite close. You just use numeric and add the point:
with C as
(
select cast(substring(S.Value, S1.Pos, S2.L) as decimal(16,2)) as Number,
stuff(s.Value, 1, S1.Pos + S2.L, '') as Value
from (select #String+' ') as S(Value)
cross apply (select patindex('%[0-9,.]%', S.Value)) as S1(Pos)
cross apply (select patindex('%[^0-9,.]%', stuff(S.Value, 1, S1.Pos, ''))) as S2(L)
union all
select cast(substring(S.Value, S1.Pos, S2.L) as decimal(16,2)),
stuff(S.Value, 1, S1.Pos + S2.L, '')
from C as S
cross apply (select patindex('%[0-9,.]%', S.Value)) as S1(Pos)
cross apply (select patindex('%[^0-9,.]%', stuff(S.Value, 1, S1.Pos, ''))) as S2(L)
where patindex('%[0-9,.]%', S.Value) > 0
)
select Number
from C
Here is a brute force approach using the string operations available in SQL Server:
with t as (
select '12.45% - 42.32%' as val
)
select cast(SUBSTRING(val, 1, charindex('%', val) - 1) as float) as minval,
cast(replace(substring(val, len(val) - charindex(' ', reverse(val))+2, 100), '%', '') as float) as maxval
from t