what is the divisor is equal to zero in plsql? - sql

SELECT pstartdate,
opbal,
joined,
resign,
( opbal + joined - resign ) clbal
,
( Round(( ( resign * 100 ) / ( opbal + joined ) ) / 100, 2) * 100
) attriation
FROM (SELECT pstartdate,
penddate,
Getopempbal(pstartdate) OpBal,
Getempjn(pstartdate, penddate) Joined,
Getempres(pstartdate, penddate) Resign
FROM (SELECT Add_months(:startdate, LEVEL - 1) pstartdate,
Add_months(:startdate, LEVEL) - 1 penddate
FROM dual
CONNECT BY LEVEL <= Months_between( :enddate, :startdate ) + 1))
ORDER BY To_number(1)
When i executed this query Error came
divisor is equal to zero.
i think error this place
(round(((resign*100)/(opbal+joined))/100,2)*100) attriation

I recommend that you use the nullif() function when doing division:
select . . .
( Round(( ( resign * 100 ) / nullif( opbal + joined, 0 ) ) / 100, 2) * 100
) attriation
This returns NULL if the denominator is zero.

SELECT pstartdate,
opbal,
joined,
resign,
(opbal+joined-resign) clbal,
round((**NULLIF**(resign,0) *100)/(opbal + joined)) ab
FROM
(SELECT pstartdate,
penddate,
getopempbal(pstartdate) opbal,
getempjn(pstartdate,penddate) joined,
getempres(pstartdate,penddate) resign
FROM
(SELECT add_months(:startdate, LEVEL-1) pstartdate,
add_months(:startdate, LEVEL)-1 penddate
FROM dual CONNECT BY LEVEL <= months_between(:enddate, :startdate) + 1))
ORDER BY to_number(1)

Related

getting duplicate rows

If I run the below query I am getting duplicate rows. Could anyone please help .
using distinct making query running long. never ending
adate -> 5-may-2022 rdate -> 28th -may-2022
query output getting as
7-may-2022
14-may-2022
21-may-2022
21-may-2022
21-may-2022
code is as below
select * from (
with qry as (
SELECT /* + parallel(12) */ adate AS DATE1,
MIN(rdate) AS DATE2,
a.id
FROM
t1 a,
t2 b,
t3 c
WHERE
a.id = b.id
GROUP BY
a.id,adate
)select * from (
select id,
date1 + level - 1 as CurDate,date1,date2
from qry
connect by level <= (date2 - date1) + 1)
--group by id,date1 + level - 1,date1,date2 having count(date1 + level - 1)>1)
where to_char(curdate,'DY','NLS_DATE_LANGUAGE=ENGLISH') IN('SAT')
and (CurDate) NOT IN(date1,date2)) dual;
Wrong use of generators... Read more:
https://www.orafaq.com/wiki/Oracle_Row_Generator_Techniques
https://blogs.oracle.com/sql/post/row-generators-part-2
https://blogs.oracle.com/sql/post/follow-up-to-row-generators-part-2
Fix with minimal changes:
select * from (
with qry as (
SELECT /* + parallel(12) */ adate AS DATE1,
MIN(rdate) AS DATE2,
a.id
FROM
t1 a,
t2 b,
t3 c
WHERE
a.id = b.id
GROUP BY
a.id,adate
)select * from (
select id,
date1 + lvl - 1 as CurDate,date1,date2
from qry
,lateral(select level lvl from dual connect by level <= (date2 - date1) + 1)
--group by id,date1 + level - 1,date1,date2 having count(date1 + level - 1)>1)
where to_char(curdate,'DY','NLS_DATE_LANGUAGE=ENGLISH') IN('SAT')
and (CurDate) NOT IN(date1,date2)) dual;

Why I get error Invalid number ORA-01722:

I am a little bit confusing and have no idea how to solve this problem. I have column in table Quantity which store Time value.
I want to create a following story. If I have for example
Quantity
8:00
8:00
It needs to SUM() this two and in output I need to get 16 HOURS
Second think, it needs to take last two number :00 and add to HOURS.
This is what I do so far
SELECT
(SUM(SUBSTR(A.Quantity, ':', 1)) + TRUNC((SUM(SUBSTR(A.Quantity, ':', -1)) / 60),0)), ':' ,
MOD(SUM(SUBSTR(A.Quantity, ':' , -1)), 60)
AS TOTAL_SUM FROM (
SELECT
ata.ATAID AS AtaId, ata.ProjectID, ata.StartDate, ataAW.Quantity
FROM
ata
INNER JOIN
weekly_report
ON
weekly_report.ataId = ata.ATAID
INNER JOIN
ata_articles ataAW
ON
ataAW.wrId = weekly_report.id
WHERE
ata.ATAID = 10987
AND
ataAW.type = 1
OR
ataAW.type = 2
OR
ataAW.type = 3
AND
(weekly_report.status != 3 AND weekly_report.status != 4)
AND
(
weekly_report.year < (SELECT year FROM weekly_report WHERE id = 89)
OR
(
weekly_report.year <= (SELECT year FROM weekly_report WHERE id = 89)
AND
weekly_report.week <= (SELECT week FROM weekly_report WHERE id = 89)
)
)
) A
group by A.AtaId
So far better explanation, when I run first part of query I need to get something like
SELECT
CONCAT(
-- extract hours froAm time and add minutes converted to hours
(SUM(SUBSTRING_INDEX(aa.Quantity, ':', 1)) + TRUNCATE((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) / 60),0))
-- , ':',
-- extract minutes from time and find reminder (modulo)*/
-- LPAD((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) % 60), 2, 0)
) AS W_TOTAL_SUM
FROM
ata_articles aa
INNER JOIN
weekly_report wr
ON
aa.wrId = wr.id
WHERE
aa.wrId = 69
AND
aa.type = 1
TOTAL_SUM
16
And when I run second part
SELECT
CONCAT(
-- extract hours froAm time and add minutes converted to hours
-- (SUM(SUBSTRING_INDEX(aa.Quantity, ':', 1)) + TRUNCATE((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) / 60),0))
-- , ':',
-- extract minutes from time and find reminder (modulo)*/
LPAD((SUM(SUBSTRING_INDEX(aa.Quantity, ':', -1)) % 60), 2, 0)
) AS W_TOTAL_SUM
FROM
ata_articles aa
INNER JOIN
weekly_report wr
ON
aa.wrId = wr.id
WHERE
aa.wrId = 69
AND
aa.type = 1
I get output
TOTAL_SUM
00
Can someone guide me and tell me how to solve this issue since I try every solution but unfortunetlly doesn't work. And here is what I try so far, but I always get message
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number
SELECT
(SUM(SUBSTR(A.Quantity, ':', 1)) + TRUNC((SUM(SUBSTR(A.Quantity, ':', -1)) / 60),0)), ':' ,
MOD(SUM(SUBSTR(A.Quantity, ':' , -1)), 60)
AS TOTAL_SUM FROM (
SELECT
ata.ATAID AS AtaId, ata.ProjectID, ata.StartDate, ataAW.Quantity
FROM
ata
INNER JOIN
weekly_report
ON
weekly_report.ataId = ata.ATAID
INNER JOIN
ata_articles ataAW
ON
ataAW.wrId = weekly_report.id
WHERE
ata.ATAID = 10987
AND
ataAW.type = 1
OR
ataAW.type = 2
OR
ataAW.type = 3
AND
(weekly_report.status != 3 AND weekly_report.status != 4)
AND
(
weekly_report.year < (SELECT year FROM weekly_report WHERE id = 89)
OR
(
weekly_report.year <= (SELECT year FROM weekly_report WHERE id = 89)
AND
weekly_report.week <= (SELECT week FROM weekly_report WHERE id = 89)
)
)
) A
group by A.AtaId
UPDATE
I get output error message
ORA-00907: missing right parenthesis
00907. 00000 - "missing right parenthesis"
*Cause:
*Action:
Error at Line: 267 Column: 19
SELECT ( EXTRACT( DAY FROM duration ) * 24 + EXTRACT( HOUR FROM duration ) )
|| ':'
|| TO_CHAR( EXTRACT( MINUTE FROM DURATION ), 'FM00' )
|| ' HOURS' AS duration
FROM (
SELECT NUMTODSINTERVAL(SUM( SUBSTR( quantity, 1, INSTR( quantity, ':' ) - 1 ) ),'HOUR')
+ NUMTODSINTERVAL(SUM( SUBSTR( quantity, INSTR( quantity, ':' ) + 1 ) ), 'MINUTE' )
AS duration
FROM (
SELECT ata.ATAID AS AtaId, ata.ProjectID, ata.StartDate, ataAW.Quantity
FROM ata
INNER JOIN weekly_report
ON weekly_report.ataId = ata.ATAID
INNER JOIN ata_articles ataAW
ON ataAW.wrId = weekly_report.id
INNER JOIN (SELECT week, year FROM weekly_report WHERE id = 89 ) b
ON ( weekly_report.year < b.year OR ( weekly_report.year = b.year AND weekly_report.week <= b.week ))
WHERE ata.ATAID = 10987
AND ataAW.type IN ( 1, 2, 3 )
AND weekly_report.status NOT IN ( 3, 4 )
))
group by A.AtaId
Here is what I get as output when I execute following code
DURATION
:HOURS
If you have the (slightly more complicated) sample data:
CREATE TABLE table_name ( Quantity ) AS
SELECT '8:00' FROM DUAL UNION ALL
SELECT '7:30' FROM DUAL UNION ALL
SELECT '0:30' FROM DUAL;
Then you can use string functions to get the hour and minute parts and sum those and then convert the totals to an interval (so you don't end up with 15:60 HOURS) and then format the output:
SELECT ( EXTRACT( DAY FROM duration ) * 24
+ EXTRACT( HOUR FROM duration )
)
|| ':'
|| TO_CHAR( EXTRACT( MINUTE FROM DURATION ), 'FM00' )
|| ' HOURS' AS duration
FROM (
SELECT NUMTODSINTERVAL(
SUM( SUBSTR( quantity, 1, INSTR( quantity, ':' ) - 1 ) ),
'HOUR'
)
+
NUMTODSINTERVAL(
SUM( SUBSTR( quantity, INSTR( quantity, ':' ) + 1 ) ),
'MINUTE'
) AS duration
FROM table_name
);
Which outputs:
| DURATION |
| :---------- |
| 16:00 HOURS |
db<>fiddle here

How can I count rows in this sql statement?

Could you help me by answering the following question?
How can I count rows in this sql statement?
SELECT `u`.*,
( 6371 * Acos(Cos(Radians(51.6992)) * Cos(Radians(localization_lat)) *
Cos(Radians(localization_lng) - Radians(
5.3042)) +
Sin
(
Radians(51.6992)) * Sin(Radians(localization_lat))
) ) AS
`distance`
FROM `ads` AS `u`
WHERE ( localization_zip_code LIKE '%5200%' )
AND ( date_end > '2016-03-19 19:34:43'
AND date_start < '2016-03-19 19:34:43' )
AND ( is_show = 1 )
AND ( is_accept_admin = 1 )
AND ( is_in_category_page = 1 )
HAVING ( `distance` < '70' )
ORDER BY `distance` ASC
select count(*) from table or select count(column name) from table method returns the number of records
try
SELECT Count(*),
`u`.*,
( 6371 * Acos(Cos(Radians(51.6992)) * Cos(Radians(localization_lat)) *
Cos(Radians(localization_lng) - Radians(
5.3042)) +
Sin
(
Radians(51.6992)) * Sin(Radians(localization_lat))
) ) AS
`distance`
FROM `ads` AS `u`
WHERE ( localization_zip_code LIKE '%5200%' )
AND ( date_end > '2016-03-19 19:34:43'
AND date_start < '2016-03-19 19:34:43' )
AND ( is_show = 1 )
AND ( is_accept_admin = 1 )
AND ( is_in_category_page = 1 )
HAVING ( `distance` < '70' )
ORDER BY `distance` ASC
Yes I know, but when I put count() in the statement I get 0 resulsts whilst without count() I get two in this case...
Can I use count() and HAVING in one sql statement?
You should be able to do it as a subquery SELECT COUNT(*) FROM (...) AS mysubquery. So maybe something like:
SELECT COUNT(*) FROM (
SELECT `u`.*,
( 6371 * Acos(Cos(Radians(51.6992)) * Cos(Radians(localization_lat)) *
Cos(Radians(localization_lng) - Radians(
5.3042)) +
Sin
(
Radians(51.6992)) * Sin(Radians(localization_lat))
) ) AS
`distance`
FROM `ads` AS `u`
WHERE ( localization_zip_code LIKE '%5200%' )
AND ( date_end > '2016-03-19 19:34:43'
AND date_start < '2016-03-19 19:34:43' )
AND ( is_show = 1 )
AND ( is_accept_admin = 1 )
AND ( is_in_category_page = 1 )
HAVING ( `distance` < '70' )
ORDER BY `distance` ASC
) AS mysubquery

postgresql return 0 if returned value is null

I have a query that returns avg(price)
select avg(price)
from(
select *, cume_dist() OVER (ORDER BY price desc) from web_price_scan
where listing_Type='AARM'
and u_kbalikepartnumbers_id = 1000307
and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
and price>( select avg(price)* 0.50
from(select *, cume_dist() OVER (ORDER BY price desc)
from web_price_scan
where listing_Type='AARM'
and u_kbalikepartnumbers_id = 1000307
and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
)g
where cume_dist < 0.50
)
and price<( select avg(price)*2
from( select *, cume_dist() OVER (ORDER BY price desc)
from web_price_scan
where listing_Type='AARM'
and u_kbalikepartnumbers_id = 1000307
and (EXTRACT(Day FROM (Now()-dateEnded)))*24 < 48
)d
where cume_dist < 0.50)
)s
having count(*) > 5
how to make it return 0 if no value is available?
use coalesce
COALESCE(value [, ...])
The COALESCE function returns the first of its arguments that is not null.
Null is returned only if all arguments are null. It is often
used to substitute a default value for null values when data is
retrieved for display.
Edit
Here's an example of COALESCE with your query:
SELECT AVG( price )
FROM(
SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
WHERE listing_Type = 'AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
AND COALESCE( price, 0 ) > ( SELECT AVG( COALESCE( price, 0 ) )* 0.50
FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
FROM web_price_scan
WHERE listing_Type='AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
) g
WHERE cume_dist < 0.50
)
AND COALESCE( price, 0 ) < ( SELECT AVG( COALESCE( price, 0 ) ) *2
FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
FROM web_price_scan
WHERE listing_Type='AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
) d
WHERE cume_dist < 0.50)
)s
HAVING COUNT(*) > 5
IMHO COALESCE should not be use with AVG because it modifies the value. NULL means unknown and nothing else. It's not like using it in SUM. In this example, if we replace AVG by SUM, the result is not distorted. Adding 0 to a sum doesn't hurt anyone but calculating an average with 0 for the unknown values, you don't get the real average.
In that case, I would add price IS NOT NULL in WHERE clause to avoid these unknown values.
(this answer was added to provide shorter and more generic examples to the question - without including all the case-specific details in the original question).
There are two distinct "problems" here, the first is if a table or subquery has no rows, the second is if there are NULL values in the query.
For all versions I've tested, postgres and mysql will ignore all NULL values when averaging, and it will return NULL if there is nothing to average over. This generally makes sense, as NULL is to be considered "unknown". If you want to override this you can use coalesce (as suggested by Luc M).
$ create table foo (bar int);
CREATE TABLE
$ select avg(bar) from foo;
avg
-----
(1 row)
$ select coalesce(avg(bar), 0) from foo;
coalesce
----------
0
(1 row)
$ insert into foo values (3);
INSERT 0 1
$ insert into foo values (9);
INSERT 0 1
$ insert into foo values (NULL);
INSERT 0 1
$ select coalesce(avg(bar), 0) from foo;
coalesce
--------------------
6.0000000000000000
(1 row)
of course, "from foo" can be replaced by "from (... any complicated logic here ...) as foo"
Now, should the NULL row in the table be counted as 0? Then coalesce has to be used inside the avg call.
$ select coalesce(avg(coalesce(bar, 0)), 0) from foo;
coalesce
--------------------
4.0000000000000000
(1 row)
I can think of 2 ways to achieve this:
IFNULL():
The IFNULL() function returns a specified value if the expression is NULL.If the expression is NOT NULL, this function returns the expression.
Syntax:
IFNULL(expression, alt_value)
Example of IFNULL() with your query:
SELECT AVG( price )
FROM(
SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
WHERE listing_Type = 'AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
AND IFNULL( price, 0 ) > ( SELECT AVG( IFNULL( price, 0 ) )* 0.50
FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
FROM web_price_scan
WHERE listing_Type='AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
) g
WHERE cume_dist < 0.50
)
AND IFNULL( price, 0 ) < ( SELECT AVG( IFNULL( price, 0 ) ) *2
FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
FROM web_price_scan
WHERE listing_Type='AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
) d
WHERE cume_dist < 0.50)
)s
HAVING COUNT(*) > 5
COALESCE()
The COALESCE() function returns the first non-null value in a list.
Syntax:
COALESCE(val1, val2, ...., val_n)
Example of COALESCE() with your query:
SELECT AVG( price )
FROM(
SELECT *, cume_dist() OVER ( ORDER BY price DESC ) FROM web_price_scan
WHERE listing_Type = 'AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
AND COALESCE( price, 0 ) > ( SELECT AVG( COALESCE( price, 0 ) )* 0.50
FROM ( SELECT *, cume_dist() OVER ( ORDER BY price DESC )
FROM web_price_scan
WHERE listing_Type='AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
) g
WHERE cume_dist < 0.50
)
AND COALESCE( price, 0 ) < ( SELECT AVG( COALESCE( price, 0 ) ) *2
FROM( SELECT *, cume_dist() OVER ( ORDER BY price desc )
FROM web_price_scan
WHERE listing_Type='AARM'
AND u_kbalikepartnumbers_id = 1000307
AND ( EXTRACT( DAY FROM ( NOW() - dateEnded ) ) ) * 24 < 48
) d
WHERE cume_dist < 0.50)
)s
HAVING COUNT(*) > 5

Select x times for each row without union

Is it possible to write union select queries like the following more succintly?
select
id,
1,
(1 + #defCapUp) * (p.Value + p.Premium),
getdate()
from Products p
union
select
id,
1,
(1 - #defCapDown) * (p.Value - p.Premium),
getdate()
from Products p
union
select
id,
case when p.Paydate > getdate() then 1 else 0 end,
(1 - #defCapUp) * (p.Value - p.Premium),
#nextYear
from Products p
union
select
id,
case when p.Paydate > getdate() then 1 else 0 end,
(1 + #defCapDown) * (p.Value + p.Premium),
#nextYear
from Products p
The statement selects four rows for each row in the Products table. The only thing varying is the formula used to calculate the values for column two and tree. I think there should be a way in sql to write the above without so much ugly code duplication. If only functions were first class objects and sql allowed lambda expressions...
Richard's solution down below is perfect, works very well for the example provided. But I had two typos in the orignal example which makes the problem somewhat tougher:
select
id,
1,
(1 + #defCapUp) * (p.Value + p.Premium),
getdate()
from Products p
union
select
id,
1,
(1 - #defCapDown) * (p.Value - p.Payout),
getdate()
from Products p
union
select
id,
case when p.Paydate > getdate() then 1 else 0 end,
(1 - #defCapUp) * (p.Value - p.Premium),
#nextYear
from Products p
union
select
id,
case when p.Paydate <= getdate() then 1 else 0 end,
(1 + #defCapDown) * (p.Value + p.Payout),
#nextYear
from Products p
The big problem is the case expression in which the comparison operator differs. My problem is that it is very hard to "neatly" handle those cases. What if there were a third case where the comparison was p.Paydate = getdate() for example?
(Not sure how lambda expressions would have helped you)
select
id,
case when p.Paydate > X.CompareDate then 1 else 0 end,
(1 + Cap) * (p.Value + ModF * p.Premium),
#nextYear
from Products p
cross join (
select #defCapUp Cap, Cast(0 as datetime) CompareDate, 1 Modf union all
select -#defCapDown, 0, -1 union all
select -#defCapUp, GETDATE(), -1 union all
select #defCapDown, GETDATE(), 1
) X
BTW, you should have been using UNION ALL, not UNION.
If the order doesn't matter, you could use WHERE.
SELECT id, field2, field3, field4
FROM Products p
WHERE (
field4 = getdate() AND field2=1 AND
(
field3=(1 + #defCapUp) * (p.Value + p.Premium) OR
field3=(1 - #defCapDown) * (p.Value - p.Premium)
)
)
OR
(
field4=#nextYear AND field2=(case when p.Paydate > getdate() then 1 else 0 end) AND
(
field3=(1 - #defCapUp) * (p.Value - p.Premium) OR
field3=(1 + #defCapDown) * (p.Value + p.Premium)
)
)