How to separate date from a string? - sql

Hi i have the string llike,
"on 01-15-09 witha factor of 0.8"
i wanted to seperate this string in the follwing way,
1] date as 01-15-09
2] Factor of 0.8
NOTE : String length is not fixed.
so how can we seperate the data in the form of #1 & #2 ?

To get the date you can use PATINDEX().
declare #yourString varchar(100)
set #yourString = 'on 01-15-09 with a factor of 0.8'
select substring(#yourString,
patindex('%[0-9][0-9]-[0-9][0-9]-[0-9][0-9]%', #yourString),
8)
To get "factor of xx" you can do:
select substring(#yourString,
patindex('%with a%', #yourString) + 7,
20)

declare #txt varchar(max)
set #txt = 'on 01-15-09 witha factor of 0.8'
select cast(substring(#txt, patindex('% [0-9][1-9]-%', #txt), 9) as date) [date],
cast(right(#txt, patindex('%_ %', reverse(#txt))) as decimal(9,1)) Factor
Result:
date Factor
---------- ------
2009-01-15 0.8

Related

Error Handling for numbers of delimiters when extracting substrings

Situation: I have a column where each cell can have up to 5 delimiters. However, it's possible that there are none.
Objective: How do i handle errors such as :
Invalid length parameter passed to the LEFT or SUBSTRING function.
in the case that it cannot find the specified delimiter.
Query:
declare #text VARCHAR(111) = 'abc-def-geeee-ifjf-zzz'
declare #start1 as int
declare #start2 as int
declare #start3 as int
declare #start4 as int
declare #start_index_reverse as int
set #start1 = CHARINDEX('-',#text,1)
set #start2 = CHARINDEX('-',#text,charindex('-',#text,1)+1)
set #start3 = CHARINDEX('-',#text,charindex('-',#text,CHARINDEX('-',#text,1)+1)+1)
set #start4 = CHARINDEX('-',#text,charindex('-',#text,CHARINDEX('-',#text,CHARINDEX('-',#text,1)+1)+1)+1)
set #start_index_reverse = CHARINDEX('-',REVERSE(#text),1)
select
LEFT(#text,#start1-1) AS Frst,
SUBSTRING(#text,#start1+1,#start2-#start1-1) AS Scnd,
SUBSTRING(#text,#start2+1,#start3-#start2-1) AS Third,
SUBSTRING(#text,#start3+1,#start4-#start3-1)AS Third,
RIGHT(#text,#start_index_reverse-1) AS Lst
In this case my variable includes 5 delimiters and so my query works but if i removed one '-' it would break.
XML support in SQL Server brings about some unintentional but useful tricks. Converting this string to XML allows for some parsing that is far less messy than native string handling, which is very far from awesome.
DECLARE #test varchar(111) = 'abc-def-ghi-jkl-mnop'; -- try also with 'abc-def'
;WITH n(x) AS
(
SELECT CONVERT(xml, '<x>' + REPLACE(#test, '-', '</x><x>') + '</x>')
)
SELECT
Frst = x.value('/x[1]','varchar(111)'),
Scnd = x.value('/x[2]','varchar(111)'),
Thrd = x.value('/x[3]','varchar(111)'),
Frth = x.value('/x[4]','varchar(111)'),
Ffth = x.value('/x[5]','varchar(111)')
FROM n;
For a table it's almost identical:
DECLARE #foo TABLE ( col varchar(111) );
INSERT #foo(col) VALUES('abc-def-ghi-jkl-mnop'),('abc'),('def-ghi');
;WITH n(x) AS
(
SELECT CONVERT(xml, '<x>' + REPLACE(col, '-', '</x><x>') + '</x>')
FROM #foo
)
SELECT
Frst = x.value('/x[1]','varchar(111)'),
Scnd = x.value('/x[2]','varchar(111)'),
Thrd = x.value('/x[3]','varchar(111)'),
Frth = x.value('/x[4]','varchar(111)'),
Ffth = x.value('/x[5]','varchar(111)')
FROM n;
Results (sorry about the massive size, seems this doesn't handle 144dpi well):
add a test before your last select
then you should decide how to handle the other case (when one of start is 0)
You can also refer to this link about splitting a string in sql server
which is uses a loop and can handle any number of delimiters
if #start1>0 and #start2>0 and #start3>0 and #start4>0
select LEFT(#text,#start1-1) AS Frst,
SUBSTRING(#text,#start1+1,#start2-#start1-1) AS Scnd,
SUBSTRING(#text,#start2+1,#start3-#start2-1) AS Third,
SUBSTRING(#text,#start3+1,#start4-#start3-1)AS Third,
RIGHT(#text,#start_index_reverse-1) AS Lst

Text string split\cut

|
I have many strings that need to be cut\split according to one basic rule - split\ cut between the 1st ";" to the 2nd ";" and than paste it under new column.
for examples one of my rows data is:
Y 4+2 A SAMPLES; Res 50Xp3 TP; HRI ; Bin n/a; Skew: RS; Source: Y805 [100] (Qty 100);
from this row I should retrieve: "Res 50Xp3 TP"
I think I tried all split option without success I also tried to use PATINDEX\CHARINDEX and it didn't help.
Thanks,
One options is using a little XML
Example
Declare #YourTable table (ID int,SomeCol varchar(max))
Insert Into #YourTable values
(1,'Y 4+2 A SAMPLES; Res 50Xp3 TP; HRI ; Bin n/a; Skew: RS; Source: Y805 [100] (Qty 100);')
Select ID
,NewValue = ltrim(rtrim(convert(xml,'<x>'+replace(SomeCol,';','</x><x>')+'</x>').value('/x[2]','varchar(100)')))
From #YourTable
Returns
ID NewValue
1 Res 50Xp3 TP
i've done things like this in my scripts using combination of CHARINDEX and SUBSTRINGs
DECLARE #str VARCHAR(200) = 'Y 4+2 A SAMPLES; Res 50Xp3 TP; HRI ; Bin n/a; Skew: RS; Source: Y805 [100] (Qty 100)'
DECLARE #char VARCHAR(1) = ';'
SELECT
SUBSTRING(
LTRIM(SUBSTRING(#str,CHARINDEX(#char, #str)+1, LEN(#str)-CHARINDEX(#char, #str))),
0,
CHARINDEX(#char, LTRIM(SUBSTRING(#str,CHARINDEX(#char, #str)+1, LEN(#str)-CHARINDEX(#char, #str))))
)
output
Res 50Xp3 TP
in reference to the comments
SELECT
SUBSTRING(
LTRIM(SUBSTRING(v.description,CHARINDEX(';', v.description)+1, LEN(v.description)-CHARINDEX(';', v.description))),
0,
CHARINDEX(';', LTRIM(SUBSTRING(v.description,CHARINDEX(';', v.description)+1, LEN(v.description)-CHARINDEX(';', v.description))))
) AS 'YourText'
FROM vw_public_vpo AS v

Creating Dynamic Dates as Variable (Column Names) in SQL

First, I have read about similar posts and have read the comments that this isn't an ideal solution and I get it but the boss (ie client) wants it this way. The parameters are as follows (for various reasons too bizarre to go into but trust me):
1. SQL Server Mgmt Studio 2016
2. NO parameters or pass throughs or temp tables. All has to be within contained code.
So here we go:
I need to create column headings that reflect dates:
1. Current date
2. Most recent quarter end prior to current date
3. Most recent quarter end prior to #2
4. Most recent quarter end prior to #3
5. Most recent quarter end prior to #4
6. Most recent quarter end prior to #5
So if using today's date, my column names would be as follows
12/18/2016 9/30/2016 6/30/2016 3/31/2016 12/31/2016 9/30/2015
I can easily do it in SAS but can't in SQL given the requirements stated above.
Help please with same code.
Thank you
Paula
Seems like a long way to go for something which really belongs in the presentation layer. That said, consider the following:
Let's assume you maintain a naming convention for your calculated fields, for example [CurrentDay], [QtrMinus1], [QtrMinus2], [QtrMinus3], [QtrMinus4],[QtrMinus5]. Then we can wrap your complicated query in some dynamic SQL.
Just as an illustration, let's assume your current query results looks like this
After the "wrap", the results will then look like so:
The code - Since you did NOT exclude Dynamic SQL.
Declare #S varchar(max)='
Select [CustName]
,['+convert(varchar(10),GetDate(),101)+'] = [CurrentDay]
,['+Convert(varchar(10),EOMonth(DateFromParts(Year(DateAdd(QQ,-1,GetDate())),DatePart(QQ,DateAdd(QQ,-1,GetDate()))*3,1)),101)+'] = [QtrMinus1]
,['+Convert(varchar(10),EOMonth(DateFromParts(Year(DateAdd(QQ,-2,GetDate())),DatePart(QQ,DateAdd(QQ,-2,GetDate()))*3,1)),101)+'] = [QtrMinus2]
,['+Convert(varchar(10),EOMonth(DateFromParts(Year(DateAdd(QQ,-3,GetDate())),DatePart(QQ,DateAdd(QQ,-3,GetDate()))*3,1)),101)+'] = [QtrMinus3]
,['+Convert(varchar(10),EOMonth(DateFromParts(Year(DateAdd(QQ,-4,GetDate())),DatePart(QQ,DateAdd(QQ,-4,GetDate()))*3,1)),101)+'] = [QtrMinus4]
,['+Convert(varchar(10),EOMonth(DateFromParts(Year(DateAdd(QQ,-5,GetDate())),DatePart(QQ,DateAdd(QQ,-5,GetDate()))*3,1)),101)+'] = [QtrMinus5]
From (
-- Your Complicated Query --
Select * from YourTable
) A
'
Exec(#S)
If it helps the visualization, the generated SQL is as follows:
Select [CustName]
,[12/18/2016] = [CurrentDay]
,[09/30/2016] = [QtrMinus1]
,[06/30/2016] = [QtrMinus2]
,[03/31/2016] = [QtrMinus3]
,[12/31/2015] = [QtrMinus4]
,[09/30/2015] = [QtrMinus5]
From (
-- Your Complicated Query --
Select * from YourTable
) A
Here is one way using dynamic query
DECLARE #prior_quarters INT = 4,
#int INT =1,
#col_list VARCHAR(max)=Quotename(CONVERT(VARCHAR(20), Getdate(), 101))
WHILE #int <= #prior_quarters
BEGIN
SELECT #col_list += Concat(',', Quotename(CONVERT(VARCHAR(20), Eomonth(Getdate(), ( ( ( ( Month(Getdate()) - 1 ) % 3 ) + 1 ) * -1 ) * #int), 101)))
SET #int+=1
END
--SELECT #col_list -- for debugging
EXEC ('select '+#col_list+' from yourtable')

MS-SQL - Extracting numerical portion of a string

I have an MS-SQL table, with a column titled 'ImportCount'.
Data in this column follows the below format:
ImportCount
[Schedules] 1376 schedule items imported from location H:\FOLDERA\AA\XX...
[Schedules] 10201 schedule items imported from location H:\FOLDERZZ\PERS\YY...
[Schedules] 999 schedule items imported from location R:\PERS\FOLDERA\AA\XX...
[Schedules] 21 schedule items imported from location H:\FOLDERA\MM\2014ZZ...
What I would like to do is extract that numerical portion of the data (which varies in length), but am struggling to get the right result. Would appreciate any help on this!
Thanks.
Try
select left(ImportCount, patindex('%[^0-9]%', ImportCount+'.') - 1)
select SUBSTRING(ImportCount,13,patindex('% schedule items%',ImportCount)-13) from table name
Try this..You can declare it as a SQL function also.
DECLARE #intText INT
DECLARE #textAplhaNumeric varchar(100)
set #textAplhaNumeric = '1376 schedule items imported from location'
SET #intText = PATINDEX('%[^0-9]%', #textAplhaNumeric)
BEGIN
WHILE #intText > 0
BEGIN
SET #textAplhaNumeric = STUFF(#textAplhaNumeric, #intText, 1, '' )
SET #intText = PATINDEX('%[^0-9]%', #textAplhaNumeric)
END
END
Select #textAplhaNumeric //output is 1376
It will work in case of NULL or empty values.
Please try:
SELECT LEFT(Val,PATINDEX('%[^0-9]%', Val+'a')-1) from(
SELECT
STUFF(ImportCount, 1, PATINDEX('%[0-9]%', ImportCount)-1, '') Val
FROM YourTable
)x

Dynamic tsql variable data types causing query to return wrong results

I am using Sql Server 2008
Say you have a table named "Weights" and within that table you have a column named "Weight" with its data type defined as "real" with the following data.
Weight(real data type)
2
2.001
2.002
2.003
2.004
2.005
2.006
2.007
2.008
2.009
3
Here is the query I am running in the new query window against the table
declare #sql nvarchar(MAX)
declare #params nvarchar(MAX)
declare #interval float = .001
declare #conversion float = 1/#interval
set #sql =
N'select FLOOR(Weight * #INPUTconversion)*#INPUTinterval as [Weight],
COUNT(1) as ''Count''
FROM dbo.Weights
GROUP BY FLOOR(Weight*#INPUTconversion)*#INPUTinterval
order by FLOOR(Weight*#INPUTconversion)*#INPUTinterval'
set #params =
N'
#INPUTconversion real,
#INPUTinterval float'
exec sp_executesql #sql, #params,
#INPUTconversion = #conversion,
#INPUTinterval = #interval
Here is the result which appears to be wrong.
Weight Count
2 2
2.002 1
2.003 1
2.004 1
2.005 1
2.006 1
2.007 2
2.009 1
3 1
How can I make the return look like this using the same query? Do I need to change my variable data types?
Weight Count
2 1
2.001 1
2.002 1
2.003 1
2.004 1
2.005 1
2.006 1
2.007 1
2.008 1
2.009 1
3 1
This is clearly a problem of numeric representation in the data. What you are seeing as 2.001 must really be stored as 2.00099999999999 . . . for some number of "9"s.
I think your best solution is to change the data type to something like DECIMAL(12, 6), where what you see is what you get.
Alternatively, you could do some fuzzy math, by adding a very small increment to the value:
select FLOOR(Weight * #INPUTconversion + 0.0000001)*#INPUTinterval as [Weight]
This will treat a weight really close to 2.001 as 2.001 rather than just a smidgen less.