I just started working on one existing project and see the query which looks something like this -
select 100. * somecolumn1 / NULLIF(somecolumn2, 0.) AS ColumnValue,
from dbo.SomeTable
I am not sure what is '.' operator in select statement. Could anyone please help me understand?
Also this is just a portion of massive SQL Server query. And if I comment this particular select statement the query runs in about 7 seconds otherwise it takes about 5 minutes to execute the query. Can this statement be optimized?
SQL Server does integer division. So, 1/2 = 0, not 0.5.
To avoid integer division, you want to use values with decimal places. The simplest way to accomplish that is to use numeric literals. I would always include a 0 after (and before) the decimal place, so the value is easier to see:
select 100.0 * somecolumn1 / NULLIF(somecolumn2, 0.0) AS ColumnValue,
from dbo.SomeTable
I often accomplish this by multiplying by 1.0. Alternative, you can use cast() or convert() on an integer column.
Related
I have a query from core of data which is nvarchar and all values are '00:00:00' format. I want to convert it into long. When I try to convert top 1000 it working fine but problem with all values. Query show in below
SELECT DATEDIFF(second, '00:00', CAST(TimeSpent AS time(7)))* cast(1000 as bigint) + RIGHT(CAST(TimeSpent AS time(7)),7) FROM [mtr].[MatterDocument]
The error statement is
Conversion failed when converting date and/or time from character string
How can I find which value failed to convert?
I suggest that there is some bad data in your MatterDocument table. SQL Server does not support regex searches, but fortunately its LIKE operator does support some primitive regex which we can use:
SELECT *
FROM [mtr].[MatterDocument]
WHERE TimeSpent NOT LIKE '[01][0-9]:[0-5][0-9]:[0-5][0-9]' AND
TimeSpent NOT LIKE '2[0-3]:[0-5][0-9]:[0-5][0-9]';
Demo
You may verify in the demo that bad, non acceptable, time strings are being flushed out. The above query should also work to flush out strings which maybe aren't even time values at all, and somehow made it into your table.
The best long term fix would be to correct your data at its source, and then bring the data into SQL Server as a bona fide date/time type.
Edit: TRY_CAST, as described by #Denis in his answer, might be another approach. But this would require SQL Server 2012 or later. The above query should still work in earlier versions.
Try to use TRY_CAST function to find the wrong rows (it returns NULL if it cannot convert the value)
SELECT c.TimeSpent, /*Any columns to identify rows */
FROM (
SELECT TimeSpent, /*Any columns to identify rows */
DATEDIFF(second, '00:00', TRY_CAST(TimeSpent AS time(7)))* cast(1000 as bigint)
+ RIGHT(TRY_CAST(TimeSpent AS time(7)),7) AS Converted
FROM [mtr].[MatterDocument]
) c
WHERE Converted IS NULL
You should find the bad values:
select timespent
from t
where try_cast(TimeSpent AS time(7)) is null;
This will enable you to find the bad values. They are probably times that exceed 23.
I would suggest doing the conversion more simply:
select (left(TimeSpent, 2) * 60 * 60 +
substring(TimeStpent, 4, 2) * 60 +
right(TimeSpent, 2)
) as seconds
This will do the conversion without the limitations of the SQL Server time data type.
I have 2 columns which I need to divide sum(cola)/sum(ColB), but I am not getting the desired results since SQL server seems to truncate values after decimal
For eg. I have-
select 281370/1035
is giving 271 using simple division, whereas actual result of division is 271.8550724637681 and I want to display 271.8
I tried
SELECT cast(round(281370/1035,1) as numeric(36,1))
but that results 271.0
In SQL Server, you have to cast the integers to decimal and you could use Round to get desired precision.
SELECT cast(Round(CAST(281370 AS decimal) / CAST(1035 AS decimal),1,1) as decimal(10,1))
The problem is that you given the int number and want a decimal result
try this
select convert(decimal(30,10),281370.0/1035.0)
or
select Round(convert(decimal(30,10),281370.0/1035.0),1,1)
#Stormcloak gives the answer to specifically wanting a single position as a mantissa, however to return an exact answer you could "simply" implicitly change the datatype.
select 281370.0/1035
Returns:
271.855072
In Presto DB:
select (CAST(11 as decimal(8,6))/CAST(7 as decimal(8,6))) as result
result:1.571429
decimal(xp,xs)
xp--> total number of digits(before decimal point+ after decimal
point)
xs--> number of digits after the decimal point
reference: https://prestodb.io/docs/current/functions/decimal.html
I need to concatenate between several fields (text and numeric) and It must be accurate. Some of the fields are originally Numeric(19,6) and I need it to be with only 2 digits after the decimal point.
I'm using the following queries and if I run no. 1 I get in the CONCAT_AMOUNT a rounded numbers like so: 38156.738156.7 and in no. 2 I get it correct - 476.47476.47.
Why is it happening and how can I solve this with minimum functions?
SELECT
38156.650000 AS AMOUNT,
CAST(38156.650000 as float),
CONCAT(cast(38156.650000 as float),
cast(38156.650000 as float)) AS CONCAT_AMOUNT
SELECT
467.47 AS AMOUNT,
CAST(467.47 as float),
CONCAT(cast(467.47 as float),
cast(467.47 as float)) AS CONCAT_AMOUNT
Okay, so SQL Server makes some assumptions when converting floating point values to strings. That shouldn't be surprising. The database cannot print out an infinite number of places after the decimal point.
So, two easy choices: convert to decimal or use str():
select concat(cast(38156.650000 as decimal(10, 2)) . . .
or
select concat(str(38156.650000, 10, 2) . . .
Note: the first version is SQL standard and should work in any database.
I am using sql server 2000 and facing round function issue like the following statement working fine.
SELECT ROUND(5 * 7.83, 1)
The result will be 39.2
But when I get these values from the table, it gives 39.1, meaning it truncates and does not round up.
SELECT ROUND(rate * qty, 1)
FROM tbl
The result will be 39.1
rate and qty columns data types are float. Insert 5 in qty and 7.83 in rate, then check it. How I can fix it?
Convert the table values to real,
SELECT ROUND(convert(real,rate)*convert(real,qty),1)
Your sample simply query is not reflective of the data types involved.
Try these two instead:
SELECT ROUND(5 * 7.83, 1)
SELECT ROUND(cast(5 as float) * cast(7.83 as float), 1)
The 2nd one matches your table data types. Float datatypes are not meant for precise decimal calculations, use a decimal type for those instead.
What Every Computer Scientist Should Know About Floating-Point Arithmetic
Without losing too much precision for normal numbers, you can just cast to decimal on the fly to force human-comprehensible decimal arithmetics, e.g.
SELECT ROUND(cast(rate as decimal(10,5)) * cast(qty as decimal(10,5), 1)
FROM tbl
I have in my select clause:
AVG (cast(scale as decimal(5,2)))
I keep getting a number like: 0.6523412897, nothing I do seems to get me to my desired: 0.65.
Basically I want to have a scale of 2 (two decimal places).
Thanks
Cast the average, don't average the cast:
cast(AVG(scale) as decimal(5,2))
Update
Using ROUND() changes the value not the type. Eg. select round(0.12345,2) returns 0.12000 as it should becuase it rounds 0.12345 to 0.12 but keeps the original type with 5 decimals after the point, hence 0.12000. To change the type one must use cast, as in my post.
Try
ROUND(AVG(scale), 2)
It depends upon the database you are using, but ROUND is the answer for SQL Server:
ROUND