How to split a string in sql server using stored procedure and insert the data to table - sql

<pre>update d
set d.Price = null
from dbo.SalDocumentDetail d
left join dbo.StkWarehouse w on w.WarehouseID = d.WarehouseID
where DocumentID=" + 1 + "
and DocumentTypeID=" + 2 + "
and FiscalYear= " + 2016 + "
and isnull(isPrescription,0) <>1
and w.POSType is null
and ProductName BETWEEN ''C' 'AND' 'M''
and Country LIKE ''%land%'''</pre>
Actually this string is only a sample one my original string is very large . i am not getting a point that if i break this string than how many variables i have to make to capture the data also after splitting the string i want that to be inserted into data table containing columns as Felid and Value?
I want my result like :
<pre>
Felid Value
DocumentID= 1
DocumentTypeID= 2
FiscalYear= 2016
isnull(isPrescription,0) <>= 1
w.POSType is= null
ProductName= C
ProductName= M
Country= land
</pre>

<pre>I Use this function but this function split 'and' not split like what i want in my result i want split 'and,or,like,is,between ' if function find any this split it to two columns (Felid and Value)</pre>
<pre>ALTER FUNCTION [dbo].[fnSplitString]
(#List NVARCHAR(MAX),#Delimiter NVARCHAR(255))
RETURNS #Items TABLE(Felid NVARCHAR(Max),Valu nvarchar(MAx))
WITH SCHEMABINDING
AS BEGIN
DECLARE #ll INT=LEN(#List)+1,#ld INT=LEN(#Delimiter);
WITH a AS
(SELECT
[end]=COALESCE(NULLIF(CHARINDEX(#Delimiter,#List,1),0),#ll),
[VlaueFelid]=SUBSTRING(#List,(select
CHARINDEX('where',#List)+5),COALESCE(NULLIF(CHARINDEX('=', #List,0),0),#ll) ) ,
[Value]=SUBSTRING(#List,(select CHARINDEX('="',#List)+2),(select CHARINDEX('and',#List))-(select C`enter code here`HARINDEX('="',#List)+3))
UNION ALL
SELECT
[end]=COALESCE(NULLIF(CHARINDEX(#Delimiter,#List,[end]+#ld), 0),#ll),
[VlaueFelid]=SUBSTRING(#List,[end]+#ld, COALESCE(NULLIF(CHARINDEX('=',#List, [end]+#ld),0),#ll)-[end]-#ld),
[Value]=SUBSTRING(#List,[end]+#ld+16, COALESCE(NULLIF(CHARINDEX('=',#List,[end]+#ld),0),#ll)-[end]-#ld-5)
FROM a WHERE [end]< #ll) INSERT #Items SELECT[VlaueFelid],[Value] FROM a WHERE LEN([VlaueFelid])>0 RETURN;
END</pre>

Related

Handling variables in SQL Server

I have a procedure that needs to handle up to 60 different variables.
The variables have a standardized naming convention.
#TextParameter1 varchar(443) = NULL,
#TextParameter2 varchar(443) = NULL,
#TextParameter3 varchar(443) = NULL
I need to be able to check which variables are NULL and which aren't, and then handle the values of the non-null variables.
I tried using dynamic SQL to iterate over the variables by making the first portion of the variable name a string and iterating through the numbers on the end.
declare #rownum int = 1
while #rownum <= 60
declare #var_sql nvarchar(max) = 'INSERT INTO #slicer
SELECT IDENTITY(Int, 1, 1) AS rowkey, value
FROM STRING_SPLIT(CAST(#DetailQueryTextParameter' + CAST(#rownum AS nvarchar(3)) AS varchar(4000)), '^')'
execute #var_sql
Set #rownum = #rownum + 1
This will return an error claiming that #DetailQueryTextParameter needs to be declared first. What is the best way to handle all of these variables? I could do by writing a line of code for every single variable, but it seems like there is a better way. Can I insert the variable names into a table and iterate from there?
(The below was updated to include the SPLIT_STRING().)
You can use a VALUES subselect (not sure if that is the proper term) to combine all of your parameters into a single collection. You can then filter out the null values and pass the remaining values into STRING_SPLIT() using a CROSS APPLY.
DECLARE
#TextParameter1 varchar(443) = NULL,
#TextParameter2 varchar(443) = 'aaa^bbb',
#TextParameter3 varchar(443) = NULL,
#TextParameter4 varchar(443) = 'xxx^yyy^zzz',
#TextParameter5 varchar(443) = NULL
SELECT A.*, B.Value AS SplitValue
FROM (
VALUES
(1, #TextParameter1),
(2, #TextParameter2),
(3, #TextParameter3),
(4, #TextParameter4),
(5, #TextParameter5)
) A(Parameter, Value)
CROSS APPLY STRING_SPLIT(A.Value, '^') B
WHERE A.Value IS NOT NULL
Which would yield results like:
Parameter
Value
SplitValue
2
aaa^bbb
aaa
2
aaa^bbb
bbb
4
xxx^yyy^zzz
xxx
4
xxx^yyy^zzz
yyy
4
xxx^yyy^zzz
zzz
See this db<>fiddle.

How to calculate superscript values in SQL

I have prices coming in my source file like below -
78-22¼,
78-18⅝
I need to calculate these price. For example for first case result should be 78-22.25. I searched a lot but found that SQL supports few of these characters only. Is there anyway to make sure we are able to calculate for whatever value we are getting. Solution in either SQL or PowerShell could work.
You could write a PowerShell function to convert the fractions to decimals:
PS ~> ConvertTo-Decimal '18⅝'
18.625
To do so, we'll need to write a function that:
Uses regex to identify and extract the integer and fraction parts
Uses [char]::GetNumericValue() to get the decimal representation of the fraction
Outputs the sum of the two
function ConvertTo-Decimal {
param(
[Parameter(Mandatory)]
[string]$InputObject
)
if($InputObject -match '^(-?)(\d+)(\p{No})?$'){
$baseValue = +$Matches[2]
if($Matches[3]){
$baseValue += [char]::GetNumericValue($Matches[3])
}
if($Matches[1] -eq '-'){
$baseValue *= -1
}
return $baseValue
}
return 0
}
Hoo this one was fun.
If you want to do it purley in TSQL give this a tug:
DECLARE #table TABLE (Glyph NVARCHAR(2), Dec DECIMAL(8,6))
INSERT INTO #table (Glyph, Dec) VALUES
(N'¼', 1.0/4),(N'½', 1.0/2),(N'¾', 3.0/4),(N'⅐', 1.0/7),
(N'⅑', 1.0/8),(N'⅒',1.0/10),(N'⅓', 1.0/3),(N'⅔', 2.0/3),
(N'⅕', 1.0/5),(N'⅖', 2.0/5),(N'⅗', 3.0/5),(N'⅘', 4.0/5),
(N'⅙', 1.0/6),(N'⅚', 5.0/6),(N'⅛', 1.0/8),(N'⅜', 3.0/8),
(N'⅝', 5.0/8),(N'⅞', 7.0/8),(N'⅟', 1.0/1)
DECLARE #values TABLE (ID INT IDENTITY, value NVARCHAR(20))
INSERT INTO #values (value) VALUES
(N'78-22¼'),(N'78-18⅝'),(N'10+1')
;WITH sort AS (
SELECT v.*, t.*,
CASE WHEN m.value = v.value THEN
CASE WHEN t.Dec IS NOT NULL THEN REPLACE(p.value,t.Glyph,'')+dec
ELSE p.value
END
ELSE
CASE WHEN t.Dec IS NOT NULL THEN REPLACE(m.value,t.Glyph,'')+dec
ELSE m.value
END
END AS v,
CASE WHEN m.value = v.value THEN '+'
ELSE '-' END AS op,
ROW_NUMBER() OVER (PARTITION BY v.value ORDER BY CASE WHEN m.value = v.value THEN CHARINDEX(m.value,v.value) ELSE CHARINDEX(p.value,v.value) END) AS subID
FROM #values v
OUTER APPLY STRING_SPLIT(v.value,'-') m
OUTER APPLY STRING_SPLIT(v.value,'+') p
LEFT OUTER JOIN #table t
ON RIGHT(CASE WHEN m.value = v.value THEN p.value ELSE m.value END,1) = t.Glyph
)
SELECT ID, value, SUM(v * CASE WHEN subId = 1 THEN 1 WHEN op = '+' THEN 1 ELSE -1 END) AS v
FROM sort
GROUP BY ID, value
ID value v
---------------------
1 78-22¼ 55.750000
2 78-18⅝ 59.375000
3 10+1 11.000000
#values replaces your table.
disclaimer: this works, it'll probably perform like hot garbage, but it works :P
In T-SQL you could write a function like this that takes a vulgar fraction and replaces it with its decimal equivalent (this is not completely exhaustive, but handles the most common fractions, and makes a guess about whether you want .666 or .667 or something else for ⅔):
CREATE FUNCTION dbo.FractionToDecimal(#str nvarchar(255))
RETURNS TABLE
AS
RETURN
(
SELECT str = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
REPLACE(REPLACE(REPLACE(REPLACE(#str, N'¼','.25'),
N'½','.5'), N'¾','.75'), N'⅓','.333'), N'⅔','.666'),
N'⅛','.125'), N'⅜','.375'), N'⅝','.625'), N'⅞','.875')
);
Sample usage:
DECLARE #x table(str nvarchar(255));
INSERT #x VALUES(N'78-22¼'),(N'78-18⅝');
SELECT [input] = i.str, [output] = o.str
FROM #x AS i
CROSS APPLY dbo.FractionToDecimal(str) AS o;
Output:
input
output
78-22¼
78-22.25
78-18⅝
78-18.625
Working example in this fiddle.
Note there are only so many fraction codes available that you could be pulling in ... so you could add any to the above e.g. from this set but it isn't the case that you would have to handle any possible fraction, only the ones that are represented by these specific symbols. If someone passes in plain text 9/10 or 31/33 that is a completely different problem space than what you have outlined in the question.

Get Values between Each Comma in Seperate Row in SQL Server

I need to insert multiple rows in a database table from a single string.
Here is my string it will be comma-seperated values
Current string:
batch 1 45665 987655,1228857 76554738,12390 8885858,301297 38998798
What I want is that batch 1 should be ignored or removed and remaining part should be added into the SQL Server database as a separate row for after each comma like this
Table name dbo.MSISDNData
Data
------------------
45665 987655
1228857 76554738
12390 8885858
301297 38998798
and when I query the table it should return the results like this
Query :
Select data
from dbo.MSISDNData
Results
Data
---------------------
45665 987655
1228857 76554738
12390 8885858
301297 38998798
Try this:
DECLARE #Data NVARCHAR(MAX) = N'batch 1 45665 987655,1228857 76554738,12390 8885858,301297 38998798'
DECLARE #DataXML XML;
SET #Data = '<a>' + REPLACE(REPLACE(#Data, 'batch 1 ', ''), ',', '</a><a>') + '</a>';
SET #DataXML = #Data;
SELECT LTRIM(RTRIM(T.c.value('.', 'VARCHAR(MAX)'))) AS [Data]
FROM #DataXML.nodes('./a') T(c);
It demonstrates how to split the data. You may need to sanitize it, too - remove the batch 1, perform trimming, etc.

Converting ID values in substring of varchar to it's lookup values

I have a SQL column of type varchar that is meant to contain SQL conditions, eg (3 rows below):
WHERE Language = 1 OR Region = 10
WHERE Color= 3 OR Region = 10
WHERE Status = 1 OR Region = 10 AND Language = 1
I need to create a query to get the lookup values of these that can be sent to any non technical person. The output would be:
WHERE Language = English OR Region = Canada
WHERE Color= Red OR Region = Canada
WHERE Status = Active OR Region = Canada AND Language = English
I know I can first put all the lookups in a temp table and then use the REPLACE function, but I was wondering if there's any better (and shorter) way to do this? Any help would be appriciated.
Thanks.
I would create subquery column values ready to replace originals, f.eks for Regions:
SELECT
CONCAT('%Region = ', Region,'%') ConditionToJoin,
CONCAT('Region = ', Region) ConditionToFind,
CONCAT('Region = ', RegionName) ConditionToReplace
FROM Regions
The join this sub query with condition rows using LIKE operator and ConditionToJoin column.
There is also a question if you need to handle situations like:
Region=1
Region =1
etc...
Alternatively you could write user function to wash data and perform all replacements, something like:
CREATE FUNCTION replaceLookups(#condition VARCHAR(MAX))
RETURNS VARCHAR(MAX)
BEGIN
#string_replacement VARCHAR(MAX), #string_pattern VARCHAR(MAX);
SET #string_pattern = SELECT TOP 1 CONCAT('Region = ', Region) FROM Regions WHERE #condition LIKE CONCAT('%Region = ', Region, '%')
SET #string_replacement = SELECT TOP 1 CONCAT('Region = ', RegionName) FROM Regions WHERE #condition LIKE CONCAT('%Region = ', Region, '%')
SET #ret = REPLACE(#condition, #string_pattern, #string_replacement)
... --and so on for each lookup
RETURN #ret
END
Word of warning. Above code was written from top of my head - might need some work. Also I wouldn't expect great performance.

Turning an XML into a select

I'm trying to turn this XML string into a select
I have #Schedule XML = '<days><day enabled="0">0</day><day enabled="1">1</day><day enabled="1">2</day><day enabled="1">3</day><day enabled="1">4</day><day enabled="1">5</day><day enabled="0">6</day></days>'
What I'm trying to see at the end is..
DayNumber DayEnabled
0 0
1 1
2 1
3 1
4 1
5 1
6 0
I've tried a few ways, so far nothing is working right.. I am handling this as an XML data type, I'd prefer not to use a function as this will just be in a stored procedure..
Update: Maybe I didn't explain it correctly..
I have a stored procedure, XML is one of the parameters passed to it, I need to send it to a table to be inserted, so I'm trying to do the following..
INSERT INTO tblDays (DayNumber, DayEnabled)
SELECT #XMLParsedOrTempTableWithResults
I just can't figure out how to parsed the parameter
DECLARE #myXML as XML = '<days><day enabled="0">0</day><day enabled="1">1</day><day enabled="1">2</day><day enabled="1">3</day><day enabled="1">4</day><day enabled="1">5</day><day enabled="0">6</day></days>'
DECLARE #XMLDataTable table
(
DayNumber int
,DayEnabled int
)
INSERT INTO #XMLDataTable
SELECT d.value('text()[1]','int') AS [DayNumber]
,d.value('(#enabled)[1]','int') AS [DayEnabled]
FROM #myXML.nodes('/days/*') ds(d)
SELECT * FROM #XMLDataTable
Refer:
http://beyondrelational.com/modules/2/blogs/28/posts/10279/xquery-labs-a-collection-of-xquery-sample-scripts.aspx
The XMLTABLE function is how most XML-enabled DBMSes shred an XML document into a relational result set.
This example uses DB2's syntax for XMLTABLE and an input parameter passed into a stored procedure:
INSERT INTO tblDays (DayNumber, DayEnabled)
SELECT X.* FROM
XMLTABLE ('$d/days/day' PASSING XMLPARSE( DOCUMENT SPinputParm ) as "d"
COLUMNS
dayNumber INTEGER PATH '.',
dayEnabled SMALLINT PATH '#enabled'
) AS X
;