For the below calculation, the expected result is -0.0000671. But the result of the code is -0.00006800000.
declare
#V_A decimal (38,11) = 99.99329,
#V_B decimal (38,11) = 100,
#V_RESULT decimal (38,11);
print '#V_A = '+cast(#V_A as varchar) --Printed as "99.99329000000"
print '#V_B = '+cast(#V_B as varchar) --Printed as "100.00000000000"
SET #V_RESULT = (#V_A / #V_B) - 1;
print '#V_RESULT = '+cast(#V_RESULT as varchar) --Printed as "-0.00006800000"
Interestingly, the below code returns exact result as expected.
select (99.99329 / 100) - 1 --Returns "-0.000067100".
Could you please help me to get the same output in the above T-SQL code? I don't want to use float as it will increase decimal places. Thanks in advance.
Environment: Azure SQL DB, DTU based.
Casting to float during calculation resolves the issue.
#V_A decimal (38,11) = 99.99329,
#V_B decimal (38,11) = 100,
#V_RESULT decimal (38,11);
print '#V_A = '+cast(#V_A as varchar) --Printed as "99.99329000000"
print '#V_B = '+cast(#V_B as varchar) --Printed as 100.00000000000
SET #V_RESULT = (cast(#V_A as float) / cast(#V_B as float)) - 1; --Printed as -0.00006710000
print '#V_RESULT = '+cast(#V_RESULT as varchar)
Related
I am trying to run these lines:
create type _stats_agg_result_type AS (
count bigint,
min double precision,
max double precision,
mean double precision,
variance double precision,
skewness double precision,
kurtosis double precision
);
create or replace function _stats_agg_finalizer(_stats_agg_accum_type)
returns _stats_agg_result_type AS '
BEGIN
RETURN row(
$1.n,
$1.min,
$1.max,
$1.m1,
$1.m2 / nullif(($1.n - 1.0), 0),
case when $1.m2 = 0 then null else sqrt($1.n) * $1.m3 / nullif(($1.m2 ^ 1.5), 0) end,
case when $1.m2 = 0 then null else $1.n * $1.m4 / nullif(($1.m2 * $1.m2) - 3.0, 0) end
);
END;
'
language plpgsql;
Unfortunately I get following error (w.r.t. the _stats_agg_finalizer function):
RETURN must specify a record or row variable in function returning row
Version I'm running:
PostgreSQL 9.2.24 on x86_64-redhat-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28), 64-bit
I am new to PostgreSQL and I have not been able to fix this error.
Appreciate any help, thanks!
This was enabled in 9.3. I assume it corresponds to this release note:
Allow PL/pgSQL to use RETURN with a composite-type expression (Asif
Rehman)
Previously, in a function returning a composite type, RETURN could
only reference a variable of that type.
So you should be able to rewrite it this way:
create or replace function _stats_agg_finalizer(_stats_agg_result_type)
returns _stats_agg_result_type AS '
declare f _stats_agg_result_type ;
BEGIN
f:=row(
$1.n,
$1.min,
$1.max,
$1.m1,
$1.m2 / nullif(($1.n - 1.0), 0),
case when $1.m2 = 0 then null else sqrt($1.n) * $1.m3 / nullif(($1.m2 ^ 1.5), 0) end,
case when $1.m2 = 0 then null else $1.n * $1.m4 / nullif(($1.m2 * $1.m2) - 3.0, 0) end
);
return f;
END;
'
language plpgsql;
Note that I changed the input type, since you didn't show use the definition of the original type.
I have problem multiplying two host variables in embedded SQL for PostgreSQL.
The SQL-query is big but I have cut out the part that doesn't work.
Declaration:
EXEC SQL BEGIN DECLARE SECTION;
int var1;
int var2;
EXEC SQL END DECLARE SECTION;
Code:
CASE WHEN product_id = :var1 THEN :var1 * :var2
ELSE 0 END
The compilation works but I get the following error message at execution:
Errcode: -400
Errmsg: operator is not unique: unknown * unknown on line 1394
If I change the code to
CASE WHEN product_id = :var1 THEN 1 * :var2
ELSE 0 END
or
CASE WHEN product_id = :var1 THEN product_id * :var2
ELSE 0 END
or
CASE WHEN product_id = :var1 THEN :var1 * (1 * :var2)
ELSE 0 END
it works.
Is it possible to multiply two host variables? If not, is there any workaround? The last code example above works but I would like a solution that is not as ugly.
Try casting to integer:
CASE WHEN product_id = :var1 THEN :var1::integer * :var2::integer
ELSE 0 END
The error
operator is not unique...
can mostly be fixed by casting to the expected type
I have a set of decimal values, but I need to remove the values after the decimal if they are zero.
17.00
23.50
100.00
512.79
become
17
23.50
100
512.79
Currently, I convert to a string and replace out the trailing .00 - Is there a better method?
REPLACE(CAST(amount as varchar(15)), '.00', '')
This sounds like it is purely a data presentation problem. As such you should let the receiving application or reporting software take care of the formatting.
You could try converting the .00s to datatype int. That would truncate the decimals. However, as all the values appear in one column they will have to have the same type. Making everything an int would ruin your rows with actual decimal places.
As a SQL solution to a presentation problem, I think what you have is OK.
I would advice you to compare the raw decimal value with itself floored. Example code:
declare
#Val1 decimal(9,2) = 17.00,
#Val2 decimal(9,2) = 23.50;
select
case when FLOOR ( #Val1 ) = #Val1
then cast( cast(#Val1 as int) as varchar)
else cast(#Val1 as varchar) end,
case when FLOOR ( #Val2 ) = #Val2
then cast( cast(#Val2 as int) as varchar)
else cast(#Val2 as varchar) end
-------------
17 | 23.50
I have this table with 1 records. Im trying to compute something call Puntaje, to get the Puntaje Result I have to follow the following formula:
Puntaje = (Infracciones * 10) / Horas
Horas = Segundos / 60 / 60
I wrote the following script, but I have some doubt and problem.
1) Is there another way to assign the values to #variables or another way to compute the sum?
2) Why the Puntaje result is 0.00, have to be: 0.854
Im using MS SQL Server 2012
Can someone help me to resolve this? Thank you in advance.
/* content of table: #Customer_Drivers
DriverId Segundos KM QtyExcesos QtyFreAce QtyDesc Puntaje IDC
6172 717243 1782 17 0 0 0 0
*/
DECLARE #Customer_Drivers TABLE (
DriverId INT,
Segundos INT,
KM INT,
QtyExcesos INT,
QtyFreAce INT,
QtyDesc INT,
Puntaje INT,
IDC INT
);
SET NOCOUNT ON;
INSERT INTO #Customer_Drivers (DriverId, Segundos, KM, QtyExcesos, QtyFreAce, QtyDesc, Puntaje, IDC)
VALUES (6172, 717243, 1782, 17, 0, 0, 0, 0);
SET NOCOUNT OFF;
DECLARE #DriverId INT = 6172;
DECLARE #Horas INT;
DECLARE #QtyExcesos INT ;
DECLARE #QtyFreAce INT ;
DECLARE #QtyDesc INT ;
DECLARE #Infracciones INT;
DECLARE #Puntaje Decimal(18,2);
SET #Horas = (SELECT Segundos FROM #Customer_Drivers WHERE DriverId = #DriverId) / 60 / 60;
SET #QtyExcesos = (SELECT QtyExcesos FROM #Customer_Drivers WHERE DriverId = #DriverId);
SET #QtyFreAce = (SELECT QtyFreAce FROM #Customer_Drivers WHERE DriverId = #DriverId);
SET #QtyDesc = (SELECT QtyDesc FROM #Customer_Drivers WHERE DriverId = #DriverId);
SET #Infracciones = (#QtyExcesos + #QtyFreAce + #QtyDesc);
SET #Puntaje = ( #Infracciones * 10) /#Horas;
PRINT #Horas
PRINT #QtyExcesos
PRINT #QtyFreAce
PRINT #QtyDesc
PRINT #Puntaje
/* OUTPUT
199 -- #Horas
17 -- #QtyExcesos
0 -- #FreAce
0 -- #QtyDesc
0.00 -- #Puntaje must be = 0.854
*/
Even though #Puntaje is declared as Decimal(18,2), that doesn't mean your calculation will be treated as a decimal. The problem is that ( #Infracciones * 10) / #Horas is using all integers so this expression will result in the integer value 0. Then this integer 0 is converted to a decimal and stored in #Puntaje.
To fix this, you need to convert part of the expression to a decimal first so that the result will be a decimal:
SET #Puntaje = ( CAST(#Infracciones AS Decimal(18,2)) * 10) / #Horas
You are using integers in your calculation, so the result will be rounded off (or truncated) to the nearest integer. Use decimal values, or use 'cast' :
#Puntaje = (cast(#Infracciones as decimal(18,2)) * 10.0) / cast(#Horas as decimal(18,2))
Check my syntax - just typed this on without trying it
1) You can use SELECT #Horas = Segundos/3600, #QtyExcesos = QtyExcesos ... FROM [RS_Reports].[dbo].[Customer_Drivers] WHERE DriverId = #DriverId. This should work providing that there is one line of results.
2) Already answered by others, you have to divide by decimal to get a decimal, i.e. you'll have to convert #Horas to Decimal
From what I've learned. #variable should be some parameters light input parameter and output parameter.... Try to execute your Stored Procedure and see what you got in SQL Server Management Studio.
There should be a return value.
i have latitude and longitude columns in location table in PostgreSQL database,
and I am trying to execute distance query with a PostgreSQL function.
I read this chapter of the manual:
https://www.postgresql.org/docs/current/static/earthdistance.html
but I think I'm missing something there.
How should I do that? Are there more examples available
Here's another example using the point operator:
Initial setup (only need to run once):
create extension cube;
create extension earthdistance;
And then the query:
select (point(-0.1277,51.5073) <#> point(-74.006,40.7144)) as distance;
distance
------------------
3461.10547602474
(1 row)
Note that points are created with LONGITUDE FIRST. Per the documentation:
Points are taken as (longitude, latitude) and not vice versa because longitude is closer to the intuitive idea of x-axis and latitude to y-axis.
Which is terrible design... but that's the way it is.
Your output will be in miles.
Gives the distance in statute miles between two points on the Earth's surface.
This module is optional and is not installed in the default PostgreSQL instalatlion. You must install it from the contrib directory.
You can use the following function to calculate the approximate distance between coordinates (in miles):
CREATE OR REPLACE FUNCTION distance(lat1 FLOAT, lon1 FLOAT, lat2 FLOAT, lon2 FLOAT) RETURNS FLOAT AS $$
DECLARE
x float = 69.1 * (lat2 - lat1);
y float = 69.1 * (lon2 - lon1) * cos(lat1 / 57.3);
BEGIN
RETURN sqrt(x * x + y * y);
END
$$ LANGUAGE plpgsql;
A more accurate version of #strkol's answer, using the Haversine formula
CREATE OR REPLACE FUNCTION distance(
lat1 double precision,
lon1 double precision,
lat2 double precision,
lon2 double precision)
RETURNS double precision AS
$BODY$
DECLARE
R integer = 6371e3; -- Meters
rad double precision = 0.01745329252;
φ1 double precision = lat1 * rad;
φ2 double precision = lat2 * rad;
Δφ double precision = (lat2-lat1) * rad;
Δλ double precision = (lon2-lon1) * rad;
a double precision = sin(Δφ/2) * sin(Δφ/2) + cos(φ1) * cos(φ2) * sin(Δλ/2) * sin(Δλ/2);
c double precision = 2 * atan2(sqrt(a), sqrt(1-a));
BEGIN
RETURN R * c;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Input is in degrees (e.g. 52.34273489, 6.23847) and output is in meters.
Assuming you've installed the earthdistance module correctly, this will give you the distance in miles between two cities. This method uses the simpler point-based earth distances. Note that the arguments to point() are first longitude, then latitude.
create table lat_lon (
city varchar(50) primary key,
lat float8 not null,
lon float8 not null
);
insert into lat_lon values
('London, GB', 51.67234320, 0.14787970),
('New York, NY', 40.91524130, -73.7002720);
select
(
(select point(lon,lat) from lat_lon where city = 'London, GB') <#>
(select point(lon,lat) from lat_lon where city = 'New York, NY')
) as distance_miles
distance_miles
--
3447.58672105301
An alternate Haversine formula, returning miles. (source)
CREATE OR REPLACE FUNCTION public.geodistance(
latitude1 double precision,
longitude1 double precision,
latitude2 double precision,
longitude2 double precision)
RETURNS double precision AS
$BODY$
SELECT asin(
sqrt(
sin(radians($3-$1)/2)^2 +
sin(radians($4-$2)/2)^2 *
cos(radians($1)) *
cos(radians($3))
)
) * 7926.3352 AS distance;
$BODY$
LANGUAGE sql IMMUTABLE
COST 100;