Select numbers with more than 4 decimal places - sql

I have a SQL table with one float column populated with values like these:
1.4313
3.35
2.55467
6.22456
3.325
I need to select rows containing only values with more than 4 decimals. In this case, the select must return:
2.55467
6.22456
Ideas? Thanks!
This is what I have tried so far
select *
from table
where CAST(LATITUDE AS DECIMAL(10,5)) - LATITUDE = 0

DECLARE #tbl TABLE (val float)
INSERT INTO #tbl SELECT 1234.567
INSERT INTO #tbl SELECT 1234.5678
INSERT INTO #tbl SELECT -1234.5678
INSERT INTO #tbl SELECT 1234.56789
SELECT *
from #tbl
where (((val*10000) - CONVERT(INT,(val*10000))) <> 0)

Why cant we make it simple by this query:-
SELECT * FROM table WHERE val LIKE '%.____%'
This selects what we want

Another solution also:
SELECT * from table
where (round(value,2) - round(value,4) <> 0)

Given answers did not work for me with MaxDb, but this did:
where FLOOR(value * 10000) != value * 10000
Source
Reduce/Increase 0`s for less/more precision.

This works on Postgres 11:
SELECT * FROM mytable WHERE mycolumn != ROUND(mycolumn::numeric,2)

http://sqlfiddle.com/#!3/abadc/3/0
Seems like something like this should work...
all it does is convert the number to an integer to drop off decimals after multiplying it * 10 to power of decimals you need then it compares that int version of the number to the base number after it too was multiplied by 10 to the power of # of decimals.
If the numbers don't match, then you have decimals beyond 4. If they do match, then it was 4 or fewer.
Select *
from foo
where cast(myNum*power(10,4) as int) <> myNum*power(10,4)

Please try something like:
select * from table
where RIGHT(CAST(value as DECIMAL(10,5)), value), 1) != 0

SELECT *
FROM table WHERE
(abs(val)*100000)%10 <> 0

It's an older question but it checks out.
select val
from table
where ((val * 100) % 1) > 0
Change 100 to your precision.

You can multiply it with 10000 and subtract it from the original number replacing . with ''.
Fiddle
select * from tablename
where replace(numcolumn,'.','') - numcolumn * 10000 > 0

Below is the Code that will check the precision for 4 decimal places:
Replace MyNum, with column you are checking for precision
Replace MyTbl, with the table you are using
Replace 4, with whatever precision you are checking for
Sql:
SELECT MyNum
, LEN(CAST (MyNum AS CHAR))
, -------1. length of decimal number, after conversion to CHAR
CHARINDEX('.', CAST (MyNum AS CHAR))
, ---2.length of numbers after the '.'
LEN(CAST (MyNum AS CHAR)) - CHARINDEX('.', CAST (MyNum AS CHAR)) -----subtracting 1-2, to get the length of numbers after decimal point '.'
FROM MyTbl
WHERE LEN(CAST(MyNum AS CHAR)) - CHARINDEX('.', CAST(MyNum AS CHAR)) > 4; --checking if there are more than 4 numbers after the decimal point '.'

Cast the number as text
Split the text using '.' as separator
Use the 2nd index and apply a length
Filter
--i.e. with postgreSQL.
--1)
select data_numeric, length(arr[2]) as str_length
from (
select data_numeric, regexp_split_to_array(data_numeric::text, '\.') as arr from TABLE
) temp;
--2)
with t1 as (
select data_numeric, regexp_split_to_array(data_numeric::text, '\.') as arr from TABLE
), t2 as (
select data_numeric, arr[2] as decimals, length(arr[2]) as length from t1
)
select * from t2;

Select numbers with more than 2 decimal places:
I had an example, where ((abs(val)*100) and CONVERT(INT,(abs(val)*100)) for value "2.32" in float type column returned two different values.
(abs(2.32)*100) = 232
CONVERT(INT,(abs(2.32)*100)) = 231
That caused wrong select query answers in case for comparing to 0.
I suppose that MSSQL CONVERT() function round numbers in such way that for some float number cases, posted solution would not work.
Here is how I did it for more than 2 decimal places:
DECLARE #tbl TABLE (val float)
INSERT INTO #tbl SELECT 2.32
INSERT INTO #tbl SELECT 1234.54
INSERT INTO #tbl SELECT 1234.545
INSERT INTO #tbl SELECT 1234.5456
INSERT INTO #tbl SELECT 1234.54567
select * from #tbl where abs(val-round((val),2)) > 0.001

You can use the scale function, since postgresql 9.6.
select LATITUDE FROM TABLE where scale(LATITUDE) > 4;
If your data type is float you will get SQL Error [42883]: ERROR: function scale(double precision) does not exist. Below would fix it.
select LATITUDE FROM TABLE where scale(cast(LATITUDE as numeric)) > 4;

This is the simplest solution, Use WITH (NOLOCK) if it's necessary in your case otherwise you can remove it. This will return the records having at least 4 decimal points in ColumnName table.
SELECT * FROM TableName WITH (NOLOCK) WHERE ColumnName LIKE '%.____'

Related

If values in column are less than ten characters, add a 0 to the start

I'm trying to add logic to one of my stored procedures to update an entire column on a table. If the value in the column is less than ten characters long, prepend a 0 to the start.
E.g. if the value is 123456789, update the field to be 0123456789. However, if the value is 1234567890, ignore this record.
What you can do is:
concatenate a static 10 character length text composed of only 0 values.
use the RIGHT() function to substract only the last 10 characters of your new string, which should contain the original "non-zero" characters, and the additional "0" characters, up to the 10 character limit.
The code would look like:
create table #temp (val varchar(30), val_new varchar(10));
insert into #temp (val) values (1234567890), (123456), (123)
update #temp
set val_new = right('0000000000' + val, 10)
select * from #temp
TRy this:
declare #t table (num varchar(50))
insert into #t values ('123456789')
insert into #t values ('1234567890')
Update #t set num =case when len(num) < 10 then '0'+ num
else num end
select * from #t
SQL Server has a built-in function to do this, format():
You can be explicit about the format:
select format(123456789, '0000000000')
Or construct it:
select format(123456789, replicate('0', 10))
Before this function was available, the trick was to use right and prepend the value. You could express this as:
select right(concat(replicate('0', 10), 123456789), 10)
The use of concat() is preferable to + because it works as expected for numbers -- which is presumably what you are starting with.
declare #t table (num varchar(50))
insert into #t values ('12345678')
insert into #t values ('1234')
insert into #t values ('123456')
insert into #t values ('1234567890')
Update #t set num =case when len(num) < 10 then REPLICATE('0',10-len(num))+ num
else num end
select * from #t
UPDATE TABLE
SET COLUMNNAME ='0'+COLUMNNAME
WHERE LEN(COLUMNNAME) < 10
If its SQL Server ther are multiple solutions to this
1:
SELECT RIGHT('0000000000' + '123456789', 10);
2:
SELECT RIGHT(REPLICATE('0', 10) + '123456789', 10);
3:
SELECT REPLACE(STR('1234567', 10),' ','0');
https://database.guide/left-padding-in-sql-server-3-lpad-equivalents/

how to check and change custom string in sql server

i have problem in my sql query code
i have one column for my codes and structure of code like this
3digit-1to3digit-5to7digit-1to2digit
xxx-xxx-xxxxxx-xx
in code column user add code like
1-1486414-305-115 --mistake
116-500-325663-1 --ok
116-2-2244880-1 --ok
121-512-2623075-1 --ok
122-500-1944261-3 --ok
2-2651274-500-147 --mistake
1-2551671-305-147 --mistake
124-500-329130-1 --ok
how to check and fix the mistake codes.
thanks for read my problem
Alternatively, instead of a load of LIKE expressions, you could split the parts and inspect their lengths, and follow up by checking the string only contains digits and hyphens with a LIKE. As your string specifically has 4 parts, I've used PARSENAME here, rather than a "splitter" function.
SELECT *
FROM (VALUES ('1-1486414-305-115'),
('116-500-325663-1'),
('116-2-2244880-1'),
('121-512-2623075-1'),
('122-500-1944261-3'),
('2-2651274-500-147'),
('1-2551671-305-147'),
('116-ba-2244880-1'),
('124-500-329130-1'))V(Code)
CROSS APPLY (VALUES(PARSENAME(REPLACE(V.code,'-','.'),4),
PARSENAME(REPLACE(V.code,'-','.'),3),
PARSENAME(REPLACE(V.code,'-','.'),2),
PARSENAME(REPLACE(V.code,'-','.'),1))) PN(P1, P2, P3, P4)
WHERE LEN(P1) != 3
OR NOT(LEN(P2) BETWEEN 1 AND 3)
OR NOT(LEN(P3) BETWEEN 5 AND 7)
OR NOT(LEN(P4) BETWEEN 1 AND 2)
OR V.Code LIKE '%[^0-9\-]%' ESCAPE '\';
What a pain, because SQL Server does not support regular expressions.
One method is 6 like comparisons:
where col like '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9]-[0-9]' or
col like '[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9]-[0-9][0-9]' or
col like '[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9]-[0-9]' or
col like '[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9]-[0-9][0-9]' or
col like '[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9]-[0-9]' or
col like '[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9]-[0-9][0-9]' or
col like '[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9]-[0-9]' or
col like '[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9]-[0-9][0-9]'
Otherwise, you could count the -s, check the positions, and characters. So:
where col not like '[^-0-9]' and -- only has digits and -
col not like '%-%-%-%-%' and -- does not have 4 hyphens
col like '___-___-%-%[0-9]' and -- first two hyphens in the right place and ends in digit
'-' in (substring(col, 14, 1), substring(col, 15, 1), substring(col, 16, 1)) -- last hyphen in the right place
Here is the complete code which can achieve the required result
1) store the splitted string into a table #myvalues (I have written a solution to split a string into many rows using Recusrsivity in this Link )
2) Store the conditions in Table #tabcheck (length of each string)
3) Make a jointure between #myvalues and #tabcheck to get the result
declare #str as nvarchar(max)
set #str='116-500-325663-1';
declare #separator as char(1)
set #separator='-';
declare #tabcheck as table(id int,fromval int ,toval int)
insert into #tabcheck values(1,3,3),(2,1,3),(3,5,7),(4,1,2);
declare #myvalues as table(id int identity(1,1),myval varchar(100));
with cte as(
select #str [mystr],
cast(1 as int) [Start],
charindex(#separator,#str)as Nd
union all
select substring(#str,nd+1,len(#str)),cast(Nd+1 as int),charindex(#separator,#str,Nd+1) from cte
where nd>0
)
insert into #myvalues(myval)
select case when nd>0 then substring(#str,start,Nd-start)
else substring(#str,start,len(#str)) end [splitted]
from cte OPTION (MAXRECURSION 1000);
declare #result as int;
with mytab as(
select t1.id,t1.myval,len(t1.myval) L,t2.fromval,t2.toval,
case when len(t1.myval)>=t2.fromval and len(t1.myval)<=t2.toval then 1 else 0 end [result]
from #myvalues t1 inner join #tabcheck t2 on t1.id=t2.id)
select #result=count(1) from mytab where result=0 ;
select case #result when 0 then 'OK' else 'Mistake' end [result]

SQL - Divide a value and make sure it re-sums to original

I need to split an invoice line into (in this instance) 3 parts (each with 2 decimal places), but I have ensure that the sum of the splits adds up to the original value.
For example: if I split 5.13 by 3%, 42% and 55% (each rounded to 2DP) I end up with:
0.15
2.82
2.15
Sum = 5.12.
The only way I can figure out how to do it is to use a case statement and split to 2DP on all but the last row.
For the last row, sum all the previous values and subtract this from the original value. This approach requires a few sub-selects. I'm sure there's a better way to do it, but drawing a blank.
(FYI, it's a 3rd party vendor product, so I have to start with a MONEY and return a insert into a MONEY type column and all values must be 2DP
Here's my example:
DECLARE
#CurrExtPrice money = 5.13
DECLARE #tGLSplit AS TABLE
(
ID INT IDENTITY(1,1)
,GLCode NVARCHAR(50)
,PercentSplit DECIMAL(18, 2)
)
INSERT INTO #tGLSplit
([GLCode], [PercentSplit])
Select
'Split1', 0.03
UNION ALL
Select
'Split2', 0.55
UNION ALL
Select
'Split3', 0.42
-- Source Date
SELECT * FROM #tGLSplit [tgs]
SELECT
#CurrExtPrice AS OriginalValue
,tg.[PercentSplit]
,CAST(#CurrExtPrice * tg.[PercentSplit] AS DECIMAL(18,2)) AS Split2DP
,CASE
WHEN tg.ID < (SELECT MAX(ID) FROM #tGLSplit)
THEN
CAST(#CurrExtPrice * tg.[PercentSplit] AS DECIMAL(18,2))
ELSE
(SELECT #CurrExtPrice - SUM(CAST(#CurrExtPrice * [PercentSplit] AS decimal(18,2))) FROM #tGLSplit WHERE ID < (SELECT MAX(ID) FROM #tGLSplit) )
END AS NewSplitValue
FROM #tGLSplit tg
Anyone have a magic algorithm?
TIA
Mark
This was successful for me. Rounding to the 1000's at a line level seemed to produce a sum that worked when rounded to the 100's. Cleanup and modify to your specific needs.
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL DROP TABLE #Temp
GO
DECLARE #Total MONEY = 5.13;
;WITH
SplitData AS
(
SELECT .03 AS SplitPercent
UNION
SELECT .42
UNION
SELECT .55 AS SplitPercent
),
Percents AS
(
SELECT S.SplitPercent,
#Total AS FullMoneyValue,
#Total * S.SplitPercent AS Total,
ROUND(#Total * S.SplitPercent,3,0) AS RoundedTotal
FROM SplitData AS S
)
SELECT P.*
INTO #Temp
FROM Percents AS P
SELECT SUM(P.Total), ROUND(SUM(P.RoundedTotal),2,0)
FROM #Temp AS P

parsing an integer field in sql

I want to split every digit in an integer field in an sql table . example of that would be:
financialNb = 7869
i need the 7 as first digit, 8 as second, 6 as third and 9 as fourth. this is needed because I want every digit to be used as 1 data field in a crystal report?
First you have to convert or cast numbers into text before you can manipulate them in this way. The functions you are looking for are CAST() and SUBSTRING(). To get the numbers to start from the right, you can use REVERSE().
Try this example:
SELECT 7869 AS field1
INTO #tmp
SELECT SUBSTRING(REVERSE(CAST(field1 AS VARCHAR(255))),8,1) AS [Column8]
,SUBSTRING(REVERSE(CAST(field1 AS VARCHAR(255))),7,1) AS [Column7]
,SUBSTRING(REVERSE(CAST(field1 AS VARCHAR(255))),6,1) AS [Column6]
,SUBSTRING(REVERSE(CAST(field1 AS VARCHAR(255))),5,1) AS [Column5]
,SUBSTRING(REVERSE(CAST(field1 AS VARCHAR(255))),4,1) AS [Column4]
,SUBSTRING(REVERSE(CAST(field1 AS VARCHAR(255))),3,1) AS [Column3]
,SUBSTRING(REVERSE(CAST(field1 AS VARCHAR(255))),2,1) AS [Column2]
,SUBSTRING(REVERSE(CAST(field1 AS VARCHAR(255))),1,1) AS [Column1]
FROM #tmp
DROP TABLE #tmp
Presumably your question is about parsing 7869. Using the substring function for this:
select substring(cast(<col> as char(4)), 1, 1) as FirstChar,
substring(cast(<col> as char(4)), 2, 1) as SecondChar,
substring(cast(<col> as char(4)), 3, 1) as ThirdChar,
substring(cast(<col> as char(4)), 4, 1) as FourthChar
from YourTable
I might be interpreting the ordering of the digits incorrectly, and this assumes the strings are always 4 digits and that you want characters. An alternative way is just to look at this as numbers:
select <col%10 as FirstNum,
(col/10) %10 as SecondNum,
(col/100)%10 as ThirdNum,
(col/1000)%10 as FourthNum
You can use the modulo operator (%) to get the digits of an integer, without using the slower string manipulation functions, like this
select
value % 100000000 / 10000000,
value % 10000000 / 1000000,
value % 1000000 / 100000,
value % 100000 / 10000,
value % 10000 / 1000,
value % 1000 / 100,
value % 100 / 10,
value % 10
from testData
Here is a SQL Fiddle to play with.
If the field is always 4 numbers long, you can get away with:
select
value / 1000 as Thousands,
value % 1000 / 100 as Hundreds,
value % 100 / 10 as Tens,
value % 10 as Units
from testData
If, however, you need to use it on arbitrary numbers, you could create a user-defined table valued function, that will return the digits in a table, like this:
create function dbo.getDigits(#Input int)
returns #Digits table
(
Digit int,
Position int
)
as begin
declare #pos int
declare #digit int
set #pos = 0
if #input = 0
begin
-- zero is just a single zero digit at position 1
insert into #digits values (0,1)
return
end
while #input<>0 begin
set #pos=#pos+1
set #digit = #input % 10
set #input = #input / 10
insert into #digits values (#digit, #pos)
end
return
end
and use it like this:
SELECT td.ID, td.Value, d.Digit, d.Position
FROM testData td
CROSS APPLY dbo.getDigits(td.Value) AS d
order by td.ID, d.Position Desc
(Here's another SQL Fiddle, based on the previous one)

sql like operator to get the numbers only

This is I think a simple problem but not getting the solution yet. I would like to get the valid numbers only from a column as explained here.
Lets say we have a varchar column with following values
ABC
Italy
Apple
234.62
2:234:43:22
France
6435.23
2
Lions
Here the problem is to select numbers only
select * from tbl where answer like '%[0-9]%' would have done it but it returns
234.62
2:234:43:22
6435.23
2
Here, obviously, 2:234:43:22 is not desired as it is not valid number.
The desired result is
234.62
6435.23
2
Is there a way to do this?
You can use the following to only include valid characters:
SQL
SELECT * FROM #Table
WHERE Col NOT LIKE '%[^0-9.]%'
Results
Col
---------
234.62
6435.23
2
You can try this
ISNUMERIC (Transact-SQL)
ISNUMERIC returns 1 when the input
expression evaluates to a valid
numeric data type; otherwise it
returns 0.
DECLARE #Table TABLE(
Col VARCHAR(50)
)
INSERT INTO #Table SELECT 'ABC'
INSERT INTO #Table SELECT 'Italy'
INSERT INTO #Table SELECT 'Apple'
INSERT INTO #Table SELECT '234.62'
INSERT INTO #Table SELECT '2:234:43:22'
INSERT INTO #Table SELECT 'France'
INSERT INTO #Table SELECT '6435.23'
INSERT INTO #Table SELECT '2'
INSERT INTO #Table SELECT 'Lions'
SELECT *
FROM #Table
WHERE ISNUMERIC(Col) = 1
Try something like this - it works for the cases you have mentioned.
select * from tbl
where answer like '%[0-9]%'
and answer not like '%[:]%'
and answer not like '%[A-Z]%'
With SQL 2012 and later, you could use TRY_CAST/TRY_CONVERT to try converting to a numeric type, e.g. TRY_CAST(answer AS float) IS NOT NULL -- note though that this will match scientific notation too (1+E34). (If you use decimal, then scientific notation won't match)
what might get you where you want in plain SQL92:
select * from tbl where lower(answer) = upper(answer)
or, if you also want to be robust for leading/trailing spaces:
select * from tbl where lower(answer) = trim(upper(answer))