Setting a maximum value for a variable. Cognos - sql

I started working in BI and I was given a brain teaser since I came from C# and not SQL/cognus.
I get a number. It can be between 0 and a very large number. When I get it and it's below 1,000 everything is dandy. But if it's bigger than or equal to 1,000 , I should use 1,000 instead.
I am not allowed to use conditions, I need it to be pure math, or if I can't then I should use efficient methods.
I thought it would be easy and just use Min() but that works differently in cognus and SQL apparently.

Use the LEAST() function:
Oracle Setup:
CREATE TABLE data ( value ) AS
SELECT 1 FROM DUAL UNION ALL
SELECT 999 FROM DUAL UNION ALL
SELECT 1000 FROM DUAL UNION ALL
SELECT 1001 FROM DUAL;
Query:
SELECT value, LEAST( value, 1000 ) AS output FROM data
Output:
VALUE OUTPUT
----- ------
1 1
999 999
1000 1000
1001 1000

Related

Calculate a field with date from previous rows

I have a table like the one shown in the image below. In this table, I need to calculate two new fields(The Red and Yellow fields), but this fields depends on the previous values. I have to calculate this values in BigQuery/SQL. In Excel, it is very easy, but I don't know how to do it in SQL.
I've tried doing a join with the same table, but previous week, and it works, but for only one "Future Week". (And there are about 100 Future Weeks)
How can I calculate this in BigQuery?
I was thinking in a Cursor.. but as far as I know, there are no cursors in BigQuery
Thanks
This is the example data:
WITH Data as ( Select '2021-01-03' as Week, 1000 as InboundReal, 10000 as StockReal, 1190 as SellReal, 1200 as InboundPpto UNION ALL
Select '2021-01-31',1000, 10000 , 1190 , 1200 UNION ALL Select '2021-02-07',1000, 10000 , 1190 , 1200 UNION ALL
Select '2021-02-14',1000, 10000 , 1200 , 1200 UNION ALL Select '2021-02-21',NULL,NULL,NULL,1200 UNION ALL
Select '2021-02-28',NULL,NULL,NULL,1200 UNION ALL Select '2021-03-07',NULL,NULL,NULL,1200 UNION ALL Select '2021-03-14',NULL,NULL,NULL,1200 )
Select *, NULL as ForecastSell,NULL as StockForecast FROM Data
I don't think this type of problem comes really into the SQL domain.
It is more of an iterative problem, where state of each iteration is maintained and available for the next one immediately (which is not the case in SQL). You can run multiple SQL queries in serial to easily achieve this though. Also, explore scripting options in BigQuery.

Calculate grand total in oracle sql developer

How to calculate grand total in query in SQL developer in oracle.
Break on report
Compute Sum is not working in SQL developer.It works only in SQL plus.
Don't want to use group function also.
Is there any way to run a query in SQL developer and show the total at the end of the results/rows.
Also want to use it in jdbc java the query
For Example , i need to select a table and list all records matching certain criteria and show the sum at the end of the records
Select volume, value , *.t1 from table1 t1 where trunc(create_date) = trunc(sysdate)
This will display say 50 records..i want to display at the end of all records under column volume and value ,the grand total of these 2 columns.
Volume value xxx yy zzzz
25 123.5 aa bb cc
35 10 a c b
50 100 c nn xc
-- --
110 233.5
You can use the below query to achieve the result -
SELECT volume,
value ,
t1.*
FROM table1 t1
WHERE TRUNC(create_date) = TRUNC(SYSDATE)
UNION ALL
SELECT SUM(volume),
SUUM(value),
NULL,
NULL,
... -- Add other NULLS according to your column list in table1.
FROM table1;
"I don't want" is a poor reason.
How come you can & want to use SQL*Plus' commands (which won't work elsewhere), but standard SQL capabilities are out of your sight? I'd suggest you to reconsider what you said & thought.
If you do, rollup might be a nice option for you.
SQL> select deptno,
2 sum(sal) sum_sal,
3 sum(comm) sum_comm
4 from emp
5 group by rollup(deptno);
DEPTNO SUM_SAL SUM_COMM
---------- ---------- ----------
10 8750
20 10875
30 9400 2200
29025 2200
SQL>
You can use ROLLUP FUNCTION here.
SELECT SUM (volume) volume,
SUM (value) value,
xxx
FROM table1 t1
WHERE TRUNC (create_date) = TRUNC (SYSDATE)
GROUP BY ROLLUP (xxx)

Oracle SQL - How to display 2 decimal places

Just help me out to display a number whose length is unknown with 2 decimal places.
Example:
If the number is 230000 then i need it to be printed as 230000.00
I tried
Select to_char(amount, 'FM99999999.90') as amt from customer;
Formatting is usually front-end "problem"; every decent tool (be it Oracle Apex, Reports, Forms, Jasper Reports, ...) has an option to format a number as you want it. Why? So that those values remain numbers, to be able to apply e.g. SUM function to them or whatever you may need.
In SQL*Plus (or similar, even GUI tools), formatting is done by the TO_CHAR function and desired format mask. If you want two decimals and (just for example) thousands separator, you might do something like this:
SQL> with customer (amount) as
2 (select 230000 from dual union all
3 select 3.14 from dual union all
4 select 0.0002 from dual union all
5 select 25.123 from dual
6 )
7 select amount,
8 to_char(amount, 'fm999g999g990d00') new_amount,
9 lpad(to_char(amount, 'fm999g999g990d00'), 10, ' ') new_amount2
10 from customer;
AMOUNT NEW_AMOUNT NEW_AMOUNT2
---------- --------------- ----------------------------------------
230000 230.000,00 230.000,00
3,14 3,14 3,14
,0002 0,00 0,00
25,123 25,12 25,12
SQL>
note that new values have ...0d00 format mask which makes sure you'll actually see zeroes around the decimal point.
use G and D for thousand groups and decimals, rather than commas and dots
new_amount2, aditionaly, has lpad applied so that values are right-aligned. I presumed that max length of those values is 10 (you'd know better)
If you do use SQL*Plus (which is quite rare nowadays), you could even use its set numformat command so - no additional modifications are necessary; you just select what you have:
SQL> set numformat 999g990d00
SQL>
SQL> with customer (amount) as
2 (select 230000 from dual union all
3 select 3.14 from dual union all
4 select 0.0002 from dual union all
5 select 25.123 from dual
6 )
7 select amount
8 from customer;
AMOUNT
-----------
230.000,00
3,14
0,00
25,12
SQL>
Use concat as follows:
select concat(amount, '.00') from customer

add two zero with decimal if number is complete integer in Oracle SQL column

Column amount contains data like - 200.203, 200, 5.10, 45.20, 10 and 5000213.012
Now I want to select if the number does not include any decimal digit then we add .00 in the returning result.
Expected result - 200.203, 200.00 ,5.10, 45.20 , 10.00 and 5000213.012
You can use TO_CHAR to format the value so that it has at least 2 decimal places:
SELECT value,
TO_CHAR( value, 'FM9999999990.009' ) AS formatted_value
FROM table_name
Which, for the sample data:
CREATE TABLE table_name ( value ) AS
SELECT 200.203 FROM DUAL UNION ALL
SELECT 200 FROM DUAL UNION ALL
SELECT 5.10 FROM DUAL UNION ALL
SELECT 45.20 FROM DUAL UNION ALL
SELECT 10 FROM DUAL UNION ALL
SELECT 5000213.012 FROM DUAL;
Outputs:
VALUE | FORMATTED_VALUE
----------: | :--------------
200.203 | 200.203
200 | 200.00
5.1 | 5.10
45.2 | 45.20
10 | 10.00
5000213.012 | 5000213.012
db<>fiddle here
Following some comments, the OP's question is effectively:
How can I change this number to have a given format?
When you consider that a NUMBER data type has no format and 5, 5.0 and 5.00000 are exactly the same value and the database does not store how many trailing zeroes a decimal value has then this question does not entirely make sense as there is no way to give a number a format.
Instead the question can be formulated as either:
How can I get <insert name of client program> to display numbers so that they always have at least 2 decimal places?
We can't answer this question without knowing the client program so I'll skip it.
Or:
How can I display a number from an Oracle query so that it is formatted with at least 2 decimal places?
Since NUMBERs never have any formatting of their own then this must involve a conversion to another data-type which can represent the number with a format (i.e. a string). So the result is that if you want a NUMBER data type then Oracle will not give it a format (but the client program might) but if you want to change the NUMBER to a string data type then you can give it a format (but it won't be a NUMBER as its now a string that just happens to contain digits) and, as described above, TO_CHAR does that.
This will do:
select to_number(to_char(value, '9999999.99')) from dual;

Why is there no "product()" aggregate function in SQL? [duplicate]

This question already has answers here:
is there a PRODUCT function like there is a SUM function in Oracle SQL?
(7 answers)
Closed 7 years ago.
When there are Sum(), min(), max(), avg(), count() functions, can someone help understand why there is no product() built-in function. And what will be the most efficient user-implementation of this aggregate function ?
Thanks,
Trinity
If you have exponential and log functions available, then:
PRODUCT(TheColumn) = EXP(SUM(LN(TheColumn)))
One can make a user-defined aggregate in SQL 2005 and up by using CLR. In Postgresql, you can do it in Postgres itself, likewise with Oracle
I'll focus on the question why it's not a standard function.
Aggregate function are basic statistical functions and product is not
Applied to common numerical data, the result will be in most cases out of range (overflow) so it is of little general use
It's probably left out because most people don't need it and it can be defined easily in most databases.
Solution for PostgreSQL:
CREATE OR REPLACE FUNCTION product_sfunc(state numeric, factor numeric)
RETURNS numeric AS $$
SELECT $1 * $2
$$ LANGUAGE sql;
CREATE AGGREGATE product (
sfunc = product_sfunc,
basetype = numeric,
stype = numeric,
initcond = '1'
);
You can simulate product() using cursors. If you let us know which database platform you're using, then we might be able to give you some sample code.
I can confirm that it is indeed rare to use a product() aggregate function, but I have a quite valid example, especially working with highly aggregated data that must be presented to users in a report.
It utilizes the exp(sum(ln( multiplyTheseColumnValues ))) "trick" as mentioned in another post and other internet sources.
The report (which should care about the display, and contain as least data calculation logic as possible, to provide better maintainability and flexibility) is basically displaying this data along with some graphics:
DESCR SUM
---------------------------------- ----------
money available in 2013 33233235.3
money spent in 2013 4253235.3
money bound to contracts in 2013 34333500
money spent 2013 in % of available 12
money bound 2013 in % of available 103
(In real life its a bit more complex and used in state budget scenarios.)
It aggregates quite some complex data found in the first 3 rows.
I do not want to calculate the percentage values of the following rows (4th and 5th) by:
doing it in the quite dumb (as it should be) report (which just takes any number of such rows with a descripiton descr and a number sum) with some fancy logic (using JasperReports, BIRT Reports or alike)
neither do I want to calculate the underlying data (money available, money spent, money bound) multiple times (since these are quite expensive operations) just to calculate the percentage values
So I used another trick involving the use of the product()-functionality.
(If somebody does know of a better way to achive this considering the above mentioned restrictions, I would be happy to know :-) )
The whole simplified example is available as one executable SQL below.
Maybe it could help convice some Oracle guys that this functionality is not as rare, or not worth providing, as it may seem at first thoughts.
with
-- we have some 10g database without pivot/unpivot functionality
-- what is interesting for various summary reports
sum_data_meta as (
select 'MA' as sum_id, 'money available in 2013' as descr, 1 as agg_lvl from dual
union all select 'MS', 'money spent in 2013', 1 from dual
union all select 'MB', 'money bound to contracts in 2013', 1 from dual
union all select 'MSP', 'money spent 2013 in % of available', 2 from dual
union all select 'MBP', 'money bound 2013 in % of available', 2 from dual
)
/* select * from sum_data_meta
SUM_ID DESCR AGG_LVL
------ ---------------------------------- -------
MA money available in 2013 1
MS money spent in 2013 1
MB money bound to contracts in 2013 1
MSP money spent 2013 in % of available 2
MBP money bound 2013 in % of available 2
*/
-- 1st level of aggregation with the base data (the data actually comes from complex (sub)SQLs)
,sum_data_lvl1_base as (
select 'MA' as sum_id, 33233235.3 as sum from dual
union all select 'MS', 4253235.3 from dual
union all select 'MB', 34333500 from dual
)
/* select * from sum_data_lvl1_base
SUM_ID SUM
------ ----------
MA 33233235.3
MS 4253235.3
MB 34333500.0
*/
-- 1st level of aggregation with enhanced meta data infos
,sum_data_lvl1 as (
select
m.descr,
b.sum,
m.agg_lvl,
m.sum_id
from sum_data_meta m
left outer join sum_data_lvl1_base b on (b.sum_id=m.sum_id)
)
/* select * from sum_data_lvl1
DESCR SUM AGG_LVL SUM_ID
---------------------------------- ---------- ------- ------
money available in 2013 33233235.3 1 MA
money spent in 2013 4253235.3 1 MS
money bound to contracts in 2013 34333500.0 1 MB
money spent 2013 in % of available - 2 MSP
money bound 2013 in % of available - 2 MBP
*/
select
descr,
case
when agg_lvl < 2 then sum
when agg_lvl = 2 then -- our level where we have to calculate some things based on the previous level calculations < 2
case
when sum_id = 'MSP' then
-- we want to calculate MS/MA by tricky aggregating the product of
-- (MA row:) 1/33233235.3 * (MS:) 4253235.3/1 * (MB:) 1/1 * (MSP:) 1/1 * (MBP:) * 1/1
trunc( -- cut of fractions, e.g. 12.7981 => 12
exp(sum(ln( -- trick simulating product(...) as mentioned here: http://stackoverflow.com/a/404761/1915920
case when sum_id = 'MS' then sum else 1 end
/ case when sum_id = 'MA' then sum else 1 end
)) over ()) -- "over()" => look at all resulting rows like an aggregate function
* 100 -- % display style
)
when sum_id = 'MBP' then
-- we want to calculate MB/MA by tricky aggregating the product as shown above with MSP
trunc(
exp(sum(ln(
case when sum_id = 'MB' then sum else 1 end
/ case when sum_id = 'MA' then sum else 1 end
)) over ())
* 100
)
else -1 -- indicates problem
end
else null -- will be calculated in a further step later on
end as sum,
agg_lvl,
sum_id
from sum_data_lvl1
/*
DESCR SUM AGG_LVL SUM_ID
---------------------------------- ---------- ------- ------
money available in 2013 33233235.3 1 MA
money spent in 2013 4253235.3 1 MS
money bound to contracts in 2013 34333500 1 MB
money spent 2013 in % of available 12 2 MSP
money bound 2013 in % of available 103 2 MBP
*/
Since the Product is noting but the multiple of SUM, so in SQL they didnot introduce the Product aggregate function
For example: 6 * 4 can be acheived by
either adding 6, 4 times to itself like 6+6+6+6
or
adding 4, 6 times to itself like 4+4+4+4+4+4
thus giving the same result