Calculate string from field in temporary table select using sp_executesql - sql

I've got a temporary table which I can select out of as follows:
select
testId
,testoutput
from
#testResults
This yields results such as the following:
ID Result
1 4303
2 -150000*200*3= -90000000
3 4.2016
4 3205000
The second value is due to some of our tests outputting the calculation rather than value for readability in later reports.
I'd like to turn that calculation back into a number, which I believe is doable via sp_executesql...
I've changed my select to:
select
testId
,case
WHEN isnumeric(trim(testoutput)) = 1 THEN pr.expectedOutput
WHEN CHARINDEX('=', testoutput) != 0 then
exec sp_executesql N'rtrim(left(testoutput, CHARINDEX(''='', testoutput) - 1))'
END
from
#testOuput
i.e. when there's an "=" sign, then split off what's the left of the sign and try to exec sp_executesql on it.
This throws all sorts of syntax errors, which I can't get my head around.
I'd really appreciate any help with the syntax of the sp_executesql

You can also extract the result of the calculation:
SQL Server without TRIM or TRY_PARSE
SELECT testId, CASE
WHEN ISNUMERIC(LTRIM(RTRIM(testoutput))) = 1 THEN pr.expectedOutput
WHEN CHARINDEX('=', testoutput) > 0 THEN
LTRIM(RTRIM(RIGHT(testoutput, CHARINDEX('=', REVERSE(testoutput))-1)))
END
FROM #testOuput
SQL Server with TRIM and TRY_PARSE
SELECT testId, CASE
WHEN TRY_PARSE(TRIM(testoutput) AS NUMERIC) IS NOT NULL THEN pr.expectedOutput
WHEN CHARINDEX('=', testoutput) > 0 THEN
TRIM(RIGHT(testoutput, CHARINDEX('=', REVERSE(testoutput))-1))
END
FROM #testOuput
demo on dbfiddle.uk

Related

SQL Sum of numbers from a string

I have a string like this:)
"<"FOSTIMON 75 M.J.>|4|4|4|3|3|3|3|3|3|3|3|3||||||||||||||||||||||||||||"
I need the sum of the numbers (4+4+4+3+...+3), expected result = 39
Thank you for the help!
THIS ANSWERS THE ORIGINAL QUESTION BEFORE EDITING.
Most databases support executing some form of prepared statement. In your case, probably the simplest method is to construct a SQL statement and then execute it dynamically.
The syntax for this varies dramatically from database to database. Out of randomness, I'm choosing SQL Server, but the functionality (although not the syntax) is available in almost any database:
declare #str nvarchar(max) = '|4|4|4|3|3|3|3|3|3|3|3|3||||||||||||||||||||||||||||';
set #str = 'select ' + replace(#str, '|', '+') + ' + 0';
exec sp_executesql #str;
Here is a rextester for this particular version.
Note that this works because + is a unary (numeric) operator, analogous to - but it does not change the sign.
Try this
Assuming the first part of the string upto the first "|" can be ignored
Not sure what version of SQL you're using but if its less than SQL2016 then use this string splitter
DECLARE #s NVARCHAR(50) = '<"FOSTIMON 75 M.J.>|4|4|4|3|3|3|3|3|3|3|3|3||||||||||||||||||||||||||||'
SELECT
SUM(CONVERT(INT, S.[Value]))
FROM dbo.DelimitedSplit8K(#s, '|') S
WHERE S.RN >= 2 AND S.RN <= 13
If you're on SQL2012 + then you can utilise TRY_PARSE and get rid of the WHERE clause altogether
SELECT
SUM(
CASE
WHEN TRY_PARSE(S.[Value] AS INT) IS NOT NULL
THEN CONVERT(INT, S.[Value])
ELSE 0
END
--CONVERT(INT, S.[Value])
)
FROM dbo.DelimitedSplit8K(#s, '|') S
If you're using SQL2016 + then use the inbuilt function, String_Split
SELECT
SUM(
CASE
WHEN TRY_PARSE(S.[Value] AS INT) IS NOT NULL
THEN CONVERT(INT, S.[Value])
ELSE 0
END
)
FROM STRING_SPLIT(#s, '|') S

How to convert Varchar column to Numeric

I have a requirement to move varchar column data to Numeric but with two conditions.
All the alphanumeric value should migrate as null
All the decimal values should go as it is.
I wrote the condition as WHERE data like '%[^0-9]%', it is working fine for all the records except for decimal.
Also I have values like .001 abcd, this has to be pass as null.
To summarize I need :
1) 1234 as 1234
2) 1.23 as 1.23
3) ABC as null
4) .ABC as null
There is by default function in SQL Server ISNUMERIC() so, first of all Check your data value by that function,
Select ISNUMERIC(DATA)
Whole query is written as below,
SELECT CASE WHEN ISNUMERIC(data)=1 THEN CAST(data as decimal(18,2))
ELSE NULL END as tData FROM DataTable
As per your question,first we have to convert with numeric with using case,which satisfies your first condition,another thing if the value is String than convert as NULL. In Above query both the condition has been taken care.
EDIT : If you are using SQL SERVER 2012 or higher version then use
TRY_PARSE(), then there will be no need to worry about using CASE too...
I have tried this,
SELECT TRY_PARSE('63.36' as decimal(18,2)) got result 63.36
and
SELECT TRY_PARSE('.' as decimal(18,2)) got result NULL
I think that this fits your spec. It is quite verbose, but hopefully it breaks down the conditions sufficiently that it's clearly doing the correct thing or, if it isn't, that it's easy enough to modify:
declare #t table (data varchar(30))
insert into #t(data) values
('1234'),
('1.23'),
('abc'),
('.abc'),
('+6000'),
('1.2.3')
select
CASE WHEN
Possible = 1 AND
(DecCheck = 0 OR
SingleDec = 1
) THEN
CONVERT(decimal(12,3),data)
END
from
#t t
cross apply
(select
--Only contains the correct characters
CASE WHEN not t.data like '%[^0-9.]%' THEN 1 ELSE 0 END as Possible,
--Contains a decimal point? (Needs more checks)
CASE WHEN CHARINDEX('.',t.data) > 0 THEN 1 ELSE 0 END as DecCheck,
CHARINDEX('.',t.data) as FirstDec --Where the first decimal point is
) p
cross apply
(select
CASE WHEN DecCheck = 1 THEN
--Only contains one decimal point
CASE WHEN LEN(data) = FirstDec + CHARINDEX('.',REVERSE(data)) - 1
THEN 1
ELSE 0 END
ELSE 0 END as SingleDec
) d
Results:
data
------------------------------ ---------------------------------------
1234 1234.000
1.23 1.230
abc NULL
.abc NULL
+6000 NULL
1.2.3 NULL
I.e. one additional check you may want to use is that a decimal cannot be the first or last character in the string. That is easy enough to do by adding those additional checks into the first CASE for the SingleDec column.
try ISNUMERIC function,
SELECT ISNUMERIC('abc')
SELECT ISNUMERIC('1.23')
On SQL Server (Version 2012, 11.0.5343)
SELECT
CASE WHEN ISNUMERIC('.') = 1 THEN <Field> ELSE 0 END
FROM
<Table>
works fine ...
Thre is A blog post.
Try following
SELECT
CASE
WHEN
ISNUMERIC(data + 'e0') = 1 THEN CAST(data AS decimal(18,2))
ELSE NULL END AS tData
FROM
DataTable
try ISNUMERIC function
DECLARE #MyTable TABLE(Val VARCHAR(100))
INSERT INTO #MyTable
VALUES
('1234')
,('1.23')
,('ABC')
,('.ABC')
,('MJA')
Select Val as OldValue,
Case
When ISNUMERIC(Val) = 1
then Cast(Val as numeric(18,2))
else null
end NewValue
From #MyTable
Output
OldValue NewValue
-----------------------------------------------------
1234 1234.00
1.23 1.23
ABC NULL
.ABC NULL
MJA NULL
(5 row(s) affected)

Convert exponential to number in sql

I have a large amount of card tokens (16 digits) uploaded from xml file to sql-server. The problem is I see them as expression, sample below:
3.3733E+15
3.3737E+15
3.3737E+15
3.3737E+15
3.37391E+15
3.37391E+15
3.37398E+15
3.37453E+15
3.37468E+15
3.37468E+15
3.3747E+15
3.37486E+15
3.37486E+15
3.37567E+15
3.3759E+15
3.3759E+15
Any suggestion to change them to a 16 digit number? I have tried to change the data type, but got error"Conversion failed when converting the varchar value '3.37201E+15' to data type int"
Thanks for help!
Edit:
#X.L.Ant see my code below. I create this table from another one, which is just purely inserted from xml file. Is this may cause an error because some rows are empty in column TOKEN?
CREATE TABLE MULTICURRENCY_CHECK
(
TOKEN varchar(255)
)
/*Merges all card tokens into 1 column, as in xml they are spread across different columns*/
INSERT INTO MULTICURRENCY_CHECK
(
TOKEN
)
SELECT no FROM gpstransactionsnew2
UNION ALL
SELECT no19 FROM gpstransactionsnew2
UNION ALL
SELECT no68 FROM gpstransactionsnew2
UNION ALL
SELECT no93 FROM gpstransactionsnew2
UNION ALL
SELECT no107 FROM gpstransactionsnew2
UNION ALL
SELECT no121 FROM gpstransactionsnew2
SELECT REPLACE(TOKEN, 'OW1', ' ')
FROM MULTICURRENCY_CHECK
/*Converts exponential expression to number*/
SELECT CONVERT(numeric(16,0), CAST(TOKEN AS FLOAT))
FROM MULTICURRENCY_CHECK
Try to cast your string to float before converting it :
SELECT CONVERT(numeric(16,0), CAST(TOKEN AS FLOAT))
FROM MULTICURRENCY_CHECK
See this fiddle.
I don't know what's the format of those numbers in your XML source, but with the data you provide, you'll end up with 33733 for instance followed by a bunch of zeroes. If you have a bigger precision in your XML, maybe you should tweak your importing settings to keep this precision instead of trying to deal with that in the DB.
EDIT:
Try testing your strings with ISNUMERIC to avoid the casting errors you're getting. Adding a raw output of your column will allow you to check which value fails to convert (i.e. converts to 0).
SELECT TOKEN,
CONVERT(NUMERIC(16, 0), CAST(CASE
WHEN ISNUMERIC(TOKEN) = 1
THEN TOKEN
ELSE 0
END AS FLOAT))
FROM MULTICURRENCY_CHECK
For SQL Server 2012+, use TRY_CONVERT().
The use of ISNUMERIC() in xlecoustillier's edited answer does not protect against conversion failures.
Given the following scenario:
CREATE TABLE test(a varchar(100));
insert into test values ('3.3733E+15'),
('3.3737E+15'),
('3.37391E+30'), --fails conversion. included to demonstrate the nature of TRY_CONVERT().
('3.37398E+15'),
('3.37453E+15'),
('3.37468E+15'),
('3.3747E+15'),
('3.37486E+15'),
('3.37567E+15'),
('3.3759E+15');
SELECT TRY_CONVERT(numeric(16,0), CAST(a AS FLOAT))
FROM test
Results in only valid converted values:
---------------------------------------
3373300000000000
NULL
3373910000000000
3373980000000000
3374530000000000
3374680000000000
3374700000000000
3374860000000000
3375670000000000
3375900000000000
However:
SELECT a,
CONVERT(NUMERIC(16, 0), CAST(CASE
WHEN ISNUMERIC(a) = 1
THEN a
ELSE 0
END AS FLOAT))
FROM test
Fails with:
Conversion failed when converting the varchar value '3.3733E+15' to
data type int.
The issue is that all values in the 'a' column return 1 when passed to the ISNUMERIC() function.
SELECT CASE WHEN ISNUMERIC(a) = 1 THEN 'Yes' ELSE 'No' END as IsValueNumeric
FROM test
Try it on SQLFiddle and/or compare with xlecoustillier's sqlfiddle
SELECT colmn_name || '' FROM table_name
This should work.

Remove only zero after decimal sql server 2012

Consider the following numbers.
7870.2
8220.0
I need to remove decimal points if the value ends with .0. If it ends with .2 then it should keep the value as it is.
I have used ceiling but it removes all the values after decimal.
How can I write a select query in which I can add some condition for this?
Generally speaking you should not do this in your dB. This is an app or reporting side operation. The dB is made to store and query information. It is not made to format/string manipulate information.
use right within a case statement and:
DECLARE #val decimal(5,1)
SET #val = 7870.0
Select
Case
When right(#val,1)<> '0' then
cast(#val as varchar)
else
cast(cast(#val as int) as varchar)
End
output: 7870
EDIT: I could write :
Case
When right(#val,1)<> '0' then
#val
else
cast(#val as int) -- or floor(#val)
End
but because return type of case statement is the highest precedence type from the set of given types, so the output for second version is: 7870.0 not 7870, that's why I convert it to i.e varchar in when clauses, and it can be converted outside of case statement, I mean cast ((case when...then...else... end) as datatype)
Cast the number as a float, using float(24) to increase precision:
DECLARE #t table(number decimal(10,1))
INSERT #t values(7870.2),(8220.0)
SELECT cast(number as float(24))
FROM #t
Result:
7870,2
8220
Here below goes a sample:
declare #1 decimal(4,3)
select #1 = 2.9
select case when SUBSTRING (PARSENAME(#1,1), 1, 1) = 0 then FLOOR(#1) else #1 end
Change the #1 in the select statement with your database field name.
sqlfiddle
The solution seems to be simple:
SELECT CONVERT (FLOAT, PAYLOAD)

A small Help needed in a _Sql Converstion of Decimal_ using **CASE**

I am need to convert a value in to decimal.Before that I am checking a condition.I want to eliminate the decimal values if #tbt=1.
Eg if #tbt=1 then 15
if #tbt=0 then 15.233
declare #tbt int =1
1) select
CASE WHEN #tbt=1 THEN CONVERT(DECIMAL(24,0),15.23335)
ELSE CONVERT(DECIMAL(24,3),15.23335) END
2) select
CASE WHEN #tbt=1 THEN '1'
ELSE '2' END
The first Query will returns 15.000.
1. Is it possible to get 15?
2. If CONVERT(DECIMAL(24,0),15.23335) returns 15.then why it is coming 15.000 in the query.
For checking I used another query and it will prints 2.
Thanks
you could use your current solution and add additional cast to Varchar(30) on both.
You can't force it to return 2 separate datatypes like this depending on the CASE.
If you insert that result into a table using SELECT INTO syntax, you'll actually see the datatype is not DECIMAL(24,0) but DECIMAL(27,3)
i.e.
declare #tbt int =1
select
CASE WHEN #tbt=1 THEN CONVERT(DECIMAL(24,0),15.23335)
ELSE CONVERT(DECIMAL(24,3),15.23335) END AS Col
INTO SomeTestTable
--Now check the SomeTestTable schema
So what SQL Server has done, is rationalised it down to a single datatype definition that can fulfil BOTH cases.
WITH T(tbt, val) AS
(
select 1,15.23335 UNION ALL
select 0,15.23335
)
Select
CASE WHEN tbt=1 THEN cast( CONVERT(DECIMAL(24,0),val) as sql_variant)
ELSE CONVERT(DECIMAL(24,3),val) END
FROM T
returns
15
15.233
Thanks to bw_üezi
I got the answer after considering his advice. thanks for all others .
Here my answer..
declare #tbt int =0
select
CASE WHEN #tbt=1 THEN CAST(CONVERT(DECIMAL(24,0),15.23335)AS NVARCHAR)
ELSE CAST(CONVERT(DECIMAL(24,3),15.23335)AS NVARCHAR) END