SQL MAX expression Function - sql

In a SQL statement I need to select the expression as
SELECT maxValues AS MAX(MIN(100,x),50)
Where x is a result of another complex SQL query. Basically in the place of x I have another SQl select statement.
If I execute the above expression using select statement, I get the following error.
ERROR [42000] ERROR: 'maxValues as max(min(100,x),50)'
nullerror 'EXCEPT' or 'FOR' or 'INTERSECT' or 'ORDER' or 'UNION'
Any help is appreciated.

Use GREATEST and LEAST rather than MAX and MIN
GREATEST and LEAST give you the greatest and least values from a list of values whereas MAX and MIN give you the maximum and minimum values in a column.

You can use a transaction that declares a variable to transfer your value from one query to the next
DECLARE
V_X NUMBER;
V_RESULT NUMBER;
V_SQL_1 CLOB := "_QUERY 1_";
BEGIN
EXECUTE IMMEDIATE V_SQL_1 INTO V_X;
SELECT MAX(MIN(100,V_X),50) INTO V_RESULT FROM DUAL;
END
(This assumes oracle-SQL.)

I'd go with a CASE:
SELECT maxValues AS CASE when x > 100 then 100
when x < 50 then 50
else x end
(If supported... I don't know IBM Neteeza.)

Related

PL/SQL Function returns to many values

I cant understand why my sql function returns the whole table with the same value.
The task is the following:
Create a PL / SQL CalculationAge (Person) function that returns the difference between the year of death and the year of birth, if the person is already deceased, and the difference between the current year and the year of birth if the person is still alive. The current year should be determined using the DBMS system time.
Example: CalculateAlter ('Andrea') should return 24 as the result, and CalculateAlter ('Albert') should return 49."
Im working with the table below.
Geboren=birth year
Gestorben=year of dead
Geschlecht=gender
gelebt=lived
I´m working with this table.
The Code of the function is the following:
create or replace FUNCTION BerechneAlter(n_Name varchar)
RETURN Integer
is
age_result integer;
v_gestorben integer;
v_geboren integer;
Begin
select gestorben, geboren into v_gestorben, v_geboren
from Family
where Family.name = n_Name;
if v_gestorben is Null
then age_result := (2018 - v_geboren);
else
age_result := v_gestorben - v_geboren;
end if;
return age_result;
end;
At the moment the function returns the right value but it shouldn´t do it for every single line of the table.
result picture
That`s because you are running it in a context of a query, it is running for every row and calculating just Andrea. In order to return just one result you need to run it just once:
select BerechneAlter('Andrea') from dual;
And if you want it to calculate for every row in the table you use:
select BerechneAlter(name) from family;
dual is a system table in Oracle to be used to return just one result/value in a query
#JorgeCampos already explained why you are getting duplicated output rows.
Let me also suggest that the code of your procedure can be greatly simplified, so the whole logic is executed in the query :
use NVL to default the date of decease
use EXTRACT to dynamically compute the current year (instead of hardcoding the value)
Code :
create or replace FUNCTION BerechneAlter(n_Name varchar)
RETURN Integer
IS
age_result integer;
BEGIN
SELECT
NVL(gestorben, EXTRACT(year from sysdate)) - geboren into age_result
FROM Family
WHERE Family.name = n_Name;
RETURN age_result;
end;

How to have the variable be assigned 'null' if no results are being returned?

Currently have a variable called VALUE that needs to be assigned a numeric value so that the stored proc doesn't error out . Currently there is no data in the database for every hour so when it reaches a point where there is no data for the prior hour, the whole procedure errors out (since nothing is being returned). Is there a way I can have null assigned to VALUE if no results are returned? Below is my 'SELECT INTO' code:
SELECT VALUE
INTO v_PRIOR__VALUE
FROM VALUE V
WHERE CODE = rCode
AND TIME = rTIME - 1/24;
Or, you could actually handle such a situation:
declare
v_prior__value value.value%type;
begin
SELECT VALUE
INTO v_PRIOR__VALUE
FROM VALUE V
WHERE CODE = rCode
AND TIME = rTIME - 1/24;
exception
when no_data_found then
null; -- v_prior_Value will remain NULL, as declared in the DECLARE section
when too_many_rows then
v_prior_Value := -1; -- this is just an example; you'd handle it the way you want
end;
If you are expecting 0 or one rows, then I think the simplest method is aggregation:
SELECT MAX(VALUE)
INTO v_PRIOR__VALUE
FROM VALUE V
WHERE CODE = rCode AND TIME = rTIME - 1/24;
An aggregation query with no GROUP BY (or HAVING) always returns exactly one row.

selecting the name of the column as values from different column

I have a table that has following columns
End_date.
count_all_transactions.
count_timeouts.
request_key.
Now I need to calculate percentagetimeout for two different dates and display them simultaneously. I have built my query.
My query is as follows:
Select PercentageTimeout ,
PerTimeout,
Transaction
From
(
select
T.COUNT_ALL_TRANSACTIONS as Total,
T.END_DATE as DT1,
T.COUNT_TIMEOUTS as Timeouts,
round (((T.COUNT_TIMEOUTS / T.COUNT_ALL_TRANSACTIONS) * 100)
,2) as PercentageTimeout,
R.INTERFACE_NAME as Transaction
from rpt_timeout T, dim_request R
where
T.REQUEST_KEY = R.REQUEST_KEY
AND
T.END_DATE='27 AUG 2012'
)
left outer join
(
select T1.COUNT_ALL_TRANSACTIONS as Total1,
T1.END_DATE as DT2,
T1.COUNT_TIMEOUTS as Timeouts1,
round (((T1.COUNT_TIMEOUTS / T1.COUNT_ALL_TRANSACTIONS) * 100)
,2) as PerTimeout,
R1.INTERFACE_NAME as Transaction1
from rpt_timeout T1, dim_request R1
where T1.REQUEST_KEY = R1.REQUEST_KEY
AND T1.END_DATE='20 AUG 2012'
) on Transaction = Transaction1;
This query is giving me correct result but what I am struggling with is that I need the name of the column as the corresponding END_DATE in that table i.e:
my output should be like
27-AUG-2012 20-AUG-2012 Transaction
0.28 0.1 Qpay
0.09 0.06 Payment
You need to use dynamic SQL for this. Since this is specific to Oracle, that means using PL/SQL to construct a query, and then execute it with the EXECUTE IMMEDIATE statement.
See the link below...
http://docs.oracle.com/cd/B10500_01/appdev.920/a96590/adg09dyn.htm
Here's some example code; it's not complete and may even be syntactically incorrect (I don't have an Oracle server handy, and haven't worked with Oracle in a little while), just a fragment to give you an idea of what I'm talking about.
DECLARE
query VARCHAR2(4000);
date1 VARCHAR2(25);
date2 VARCHAR2(25);
BEGIN
date1 := '27-AUG-2012';
date2 := '20-AUG-2012';
query := 'Select PercentageTimeout as ' || date1 ||
', PerTimeout as ' || date2 ||
', Transaction From <the rest of your query goes here>';
EXECUTE IMMEDIATE query;
END;
Now you might want to create a cursor instead out of your dynamically constructed query string and iterate through the records; whatever you need to do. The main point is, if you want to dynamically specify column aliases in a query, you need to dynamically construct that query.

Round to the nearest odd integer in SQL

I've found myself somewhat improbably* needing to round to the nearest ODD integer in SQL. There's a nice solution for how to round to the nearest N (2,5,10,etc) here, but nothing explicitly on odd numbers. Using Oracle 11gR2, if there are solutions particular to Oracle out there.
*Need to join my data to tables stripped from this study. The authors used a consistent bin width of 2...but sometimes it's even, and others it's odd.
You could do something like this:
DECLARE
n FLOAT;
BEGIN
n := 195.8;
SELECT
CASE
WHEN mod(FLOOR(n),2) = 0 THEN FLOOR(n)+1
ELSE FLOOR(n)
END NUM
INTO n
FROM DUAL;
dbms_output.put_line(to_char(n));
END;
/
Sometimes straightfoward is best, as people who come along after you will understand what's going on.
I don't think you need a case statement, this should do it:
SELECT
ROUND((11.9-1)/2,0)*2+1
FROM DUAL
Here is an oracle PL/SQL Function that would do that:
CREATE OR REPLACE FUNCTION ROUNDODD
(
IMPNUM IN NUMBER
) RETURN NUMBER AS
roundnum number;
oddnum number;
BEGIN
roundnum := round (IMPNUM,0);
IF mod(roundnum,2) = 1
THEN RETURN roundnum;
ELSE
IF roundnum > IMPNUM
THEN RETURN roundnum-1;
ELSE RETURN roundnum+1;
end if;
end if;
END ROUNDODD;
Arithmetic OR?
ROUND(3.14,0)|1
EDIT
Andriy correctly corrects this to FLOOR(3.64)::int|1. (which works correctly).
using modulus can help you find even/odd numbers. add 1 to the even numbers
select
case when (value % 2) <> 0 then value
else value + 1 end
from table

Oracle: SQL query that returns rows with only numeric values

I have a field (column in Oracle) called X that has values like "a1b2c3", "abc", "1ab", "123", "156"
how do I write an sql query that returns me only the X that hold pure numerical values = no letters? from the example above would be „123“ and „156“
select X
from myTable
where ...??
You can use the REGEXP_LIKE function as:
SELECT X
FROM myTable
WHERE REGEXP_LIKE(X, '^[[:digit:]]+$');
Sample run:
SQL> SELECT X FROM SO;
X
--------------------
12c
123
abc
a12
SQL> SELECT X FROM SO WHERE REGEXP_LIKE(X, '^[[:digit:]]+$');
X
--------------------
123
SQL>
If the only characters to consider are letters then you can do:
select X from myTable where upper(X) = lower(X)
But of course that won't filter out other characters, just letters.
Since Oracle 12c (at least) there has been a built-in function to check whether a character value is numeric: VALIDATE_CONVERSION
select X from myTable where validate_conversion(X as number) = 1
If you use Oracle 10 or higher you can use regexp functions as codaddict suggested. In earlier versions translate function will help you:
select * from tablename where translate(x, '.1234567890', '.') is null;
More info about Oracle translate function can be found here or in official documentation "SQL Reference"
UPD: If you have signs or spaces in your numbers you can add "+-" characters to the second parameter of translate function.
What about 1.1E10, +1, -0, etc? Parsing all possible numbers is trickier than many people think. If you want to include as many numbers are possible you should use the to_number function in a PL/SQL function. From http://www.oracle-developer.net/content/utilities/is_number.sql:
CREATE OR REPLACE FUNCTION is_number (str_in IN VARCHAR2) RETURN NUMBER IS
n NUMBER;
BEGIN
n := TO_NUMBER(str_in);
RETURN 1;
EXCEPTION
WHEN VALUE_ERROR THEN
RETURN 0;
END;
/
The complete list of the regexp_like and other regexp functions in Oracle 11.1:
http://66.221.222.85/reference/regexp.html
In your example:
SELECT X
FROM test
WHERE REGEXP_LIKE(X, '^[[:digit:]]$');
You can use following command -
LENGTH(TRIM(TRANSLATE(string1, '+-.0123456789', '')))
This will return NULL if your string1 is Numeric
your query would be -
select * from tablename
where LENGTH(TRIM(TRANSLATE(X, '+-.0123456789', ''))) is null