01476. 00000 - "divisor is equal to zero" Oracle - sql

I have the following code as part of a Script:
ROUND
(
(
(COUNT(DISTINCT CASE WHEN ONLINE_SALES > 0 THEN CONTACT_KEY ELSE NULL END))
/
(COUNT(DISTINCT CASE WHEN ONLINE_SALES > 0 OR OFFLINE_SALES > 0 THEN CONTACT_KEY ELSE NULL END))
),3
) AS UNIQ_ONLINE_SHOP_RATE
when I run the script I get the 'Divizer is equal to zero' erro.
I ran the denominator and numerator separately which both equal zero so I understand the error.
I have tried NULLiF(,0) as so:
ROUND
(
(
(
COUNT(DISTINCT CASE WHEN ONLINE_SALES > 0 THEN CONTACT_KEY ELSE NULL END) /
nullif((COUNT(DISTINCT CASE WHEN ONLINE_SALES > 0 OR OFFLINE_SALES > 0 THEN CONTACT_KEY ELSE NULL END)),0)
),3
) AS UNIQ_ONLINE_SHOP_RATE
but then get 'FROM keyword not found where expected error.

Is this your real query? I assume ONLINE_SALES > 0 or OFFLINE_SALES > 0 is the default and ONLINE_SALES = 0 or OFFLINE_SALES = 0 is the exception.
Then in most cases your query would result in
COUNT(DISTINCT CONTACT_KEY) / COUNT(DISTINCT CONTACT_KEY)
which is not so "exciting", i.e. always 1
With some best-guess I would do:
NULLIF(
ROUND(
COUNT(DISTINCT CONTACT_KEY)
/
NULLIF(COUNT(DISTINCT ONLINE_SALES), 0)
, 3)
, 0) AS UNIQ_ONLINE_SHOP_RATE

Here are 3 options (CASE, NULLIF and DECODE), visually simple to understand - use a CTE to calculate both values, while the main query divides them, taking care about 0 as the denominator:
with temp as
(select
COUNT(DISTINCT CASE WHEN ONLINE_SALES > 0 THEN CONTACT_KEY ELSE NULL END) val1,
COUNT(DISTINCT CASE WHEN ONLINE_SALES > 0 OR OFFLINE_SALES > 0 THEN CONTACT_KEY ELSE NULL END) val2
from your_table
)
select
-- using CASE
val1 / case when val2 = 0 then null else val2 end as result_1,
-- using NULLIF
val1 / nullif(val2, 0) as result_2
-- using DECODE
val1 / decode(val2, 0, null, val2) as result_3
from temp;
Shouldn't be difficult to round the result at the end.

Related

Validation for columns work very slow (SQL Server)

I want to perform data profiling on the columns of a table. In this particular case - what percentage of data is date/integer/numeric/bit. The query that I am using:
SELECT
CAST(SUM(CASE WHEN TRY_CAST([column1] AS date) IS NOT NULL AND TRY_CAST(TRY_CAST([column1] AS VARCHAR(8000)) AS date) between '1950-01-01' AND '2049-12-31' AND LEN(RTRIM(CAST([column1] AS VARCHAR(MAX)))) > 0 THEN 1 ELSE 0 END) AS NUMERIC(25,2))/(CAST(SUM(CASE WHEN [column1] IS NOT NULL AND LOWER(LTRIM(RTRIM(CAST([column1] AS VARCHAR(MAX))))) not IN ('null', 'n/a') AND LEN(LTRIM(RTRIM(CAST([column1] AS VARCHAR(MAX))))) > 0 THEN 1 ELSE 0 END) AS NUMERIC(25,2))+0.00000001) AS PercentDate,
CAST(SUM(CASE WHEN TRY_CAST([column1] AS FLOAT) IS NOT NULL AND LEN(RTRIM(CAST([column1] AS VARCHAR(MAX)))) > 0 THEN 1 ELSE 0 END) AS NUMERIC(25,2))/(CAST(SUM(CASE WHEN [column1] IS NOT NULL AND LOWER(LTRIM(RTRIM(CAST([column1] AS VARCHAR(MAX))))) not IN ('null', 'n/a') AND LEN(LTRIM(RTRIM(CAST([column1] AS VARCHAR(MAX))))) > 0 THEN 1 ELSE 0 END) AS NUMERIC(25,2))+0.00000001) AS PercentNumeric,
CAST(SUM(CASE WHEN TRY_CAST([column1] AS BIGINT) IS NOT NULL AND LEN(RTRIM(CAST([column1] AS VARCHAR(MAX)))) > 0 THEN 1 ELSE 0 END) AS NUMERIC(25,2))/(CAST(SUM(CASE WHEN [column1] IS NOT NULL AND LOWER(LTRIM(RTRIM(CAST([column1] AS VARCHAR(MAX))))) not IN ('null', 'n/a') AND LEN(LTRIM(RTRIM(CAST([column1] AS VARCHAR(MAX))))) > 0 THEN 1 ELSE 0 END) AS NUMERIC(25,2))+0.00000001) AS PercentInteger,
CAST(SUM(CASE WHEN LOWER(TRY_CAST([column1] AS VARCHAR(MAX))) IN ('1', '0', 't', 'f', 'y', 'n', 'true', 'false', 'yes', 'no') THEN 1 ELSE 0 END) AS NUMERIC(25,2))/(CAST(SUM(CASE WHEN [column1] IS NOT NULL AND LOWER(LTRIM(RTRIM(CAST([column1] AS VARCHAR(MAX))))) not IN ('null', 'n/a') AND LEN(LTRIM(RTRIM(CAST([column1] AS VARCHAR(MAX))))) > 0 THEN 1 ELSE 0 END) AS NUMERIC(25,2))+0.00000001) AS PercentBit
FROM tbl
This query works really slow even if I choose only top 1 row. Actually I am not able to get any result, or at least I cannot wait such a long time.
The column that I am checking is of type decimal if this is of any importance.
The number of records in the table is: 37,431,866. This is why I choose only top 1000 for example, but still does not load any result for more than 40 minutes
If you want this to run faster, then you don't want to limit the rows in the query you are using. After all, an aggregation query with no GROUP BY only returns one row.
Instead use a subquery:
SELECT . . .
FROM (SELECT TOP (1000) t.*
FROM tbl t
) t
Note that this is not a random sample. And if you attempt ORDER BY newid() you will kill performance. One alternative to get an approximate n% sample is to use logic like this:
SELECT . . .
FROM (SELECT TOP (1000) t.*
FROM tbl t
WHERE RAND(CHECKSUM(NEWID())) < 0.001
) t
The 0.001 would be about a 0.1% sample.
Your question can be simpliefied. The part:
CAST(SUM(CASE WHEN TRY_CAST([column1] AS date) IS NOT NULL AND TRY_CAST(TRY_CAST([column1] AS VARCHAR(8000)) AS date) between '1950-01-01' AND '2049-12-31' AND LEN(RTRIM(CAST([column1] AS VARCHAR(MAX)))) > 0 THEN 1 ELSE 0 END) AS NUMERIC(25,2))
can alo be written as:
CAST(SUM(CASE WHEN TRY_CAST(TRY_CAST([column1] AS VARCHAR(8000)) AS date) between '1950-01-01' AND '2049-12-31' THEN 1 ELSE 0 END) AS NUMERIC(25,2))
The second one is quicker then the first one, with the same result. (AFAIK)
This probably can also be applied to the other parts in the query.

CAST string to BIGINT in hive not giving expected result

I am not able to understand output of query run on hive
select count(*),
count(col1) as count,
count( distinct col1) as distinct,
SUM (case when (cast(col1 as BIGINT) is null or cast(col1 as BIGINT) is not null )then 1 else 0 end) as total_count,
SUM (case when cast(col1 as BIGINT) is null then 1 else 0 end) as non_int_count,
SUM (case when cast(col1 as BIGINT) is not null then 1 else 0 end) as int_count,
SUM (case when cast(col1 as BIGINT) is null then 0 else 1 end) as int_count2,
FROM TABLE
where conditions
Result for this query in Hive is
count(*) count distinct total_count non_int_count int_count int_count2
23030525 23030525 1631400 23030525 2 258898 258898
Shouldn't total_count=count(*)=(non_int_count+ int_count). ?

count categories of values

I have int values v >= 0 in nullable column and I would like to count number of occurrences of Null, 0, 1 and 2+ in column how to do it efficiently?
One method is group by:
select (case when col in (0, 1) then cast(col as varchar(255))
else '2+'
end) as grp, count(*)
from t
group by (case when col in (0, 1) then cast(col as varchar(255))
else '2+'
end)
order by min(col);
The exact syntax for the cast() might depend on the database. This also assumes all values are non-negative.
You can put the counts in different columns as well:
select sum(case when val = 0 then 1 else 0 end) as cnt_0,
sum(case when val = 1 then 1 else 0 end) as cnt_1,
sum(case when val >= 2 then 1 else 0 end) as cnt_2pl
from t;

Not a single-group group function while using case when statements

In a query I am trying to use case when keywords. I have to check for 3 conditions there. But I am getting Not a single-group group function error. Any syntax error in my query? Please guide.
Query is
SELECT
CASE WHEN DIST_TYPE_ID IN (5033,5034,5035,5036)
THEN MIN (b2b_start_dt +NVL(access_lead_Days,0))
ELSE
CASE WHEN MAX(overridden) = 0
THEN NVL (MIN (src_start_dt), MIN (b2b_start_dt))
ELSE MAX(B2B_START_dT) END
END as start_date
FROM prog_access_movie_v
WHERE trunc(SYSDATE) BETWEEN b2b_start_dt AND b2b_end_dt
AND (user_id IS NOT NULL OR GROUP_ID IS NOT NULL)
AND dist_type_id IN (5034) AND prog_id = (432899)
This is the select:
SELECT (CASE WHEN DIST_TYPE_ID IN (5033, 5034, 5035, 5036)
THEN MIN(b2b_start_dt + NVL(access_lead_Days, 0))
ELSE (CASE WHEN MAX(overridden) = 0
THEN NVL(MIN(src_start_dt), MIN(b2b_start_dt))
ELSE MAX(B2B_START_dT)
END)
END) as start_date
In terms of aggregation, everything is fine except for the condition on DIST_TYPE_ID. If you had:
SELECT (CASE WHEN MAX(DIST_TYPE_ID) IN (5033, 5034, 5035, 5036)
THEN MIN(b2b_start_dt + NVL(access_lead_Days, 0))
ELSE (CASE WHEN MAX(overridden) = 0
THEN NVL(MIN(src_start_dt), MIN(b2b_start_dt))
ELSE MAX(B2B_START_dT)
END)
END) as start_date
Or:
SELECT (CASE WHEN SUM(CASE WHEN DIST_TYPE_ID IN (5033, 5034, 5035, 5036) THEN 1 ELSE 0 END) > 0
THEN MIN(b2b_start_dt + NVL(access_lead_Days, 0))
ELSE (CASE WHEN MAX(overridden) = 0
THEN NVL(MIN(src_start_dt), MIN(b2b_start_dt))
ELSE MAX(B2B_START_dT)
END)
END) as start_date
Or a myriad of other possibilities, then the query should parse and execute.
It was a silly mistake from me . Group by dist_type_id worked out.
SELECT CASE WHEN DIST_TYPE_ID IN (5033,5034,5035,5036) THEN MIN (b2b_start_dt +NVL(access_lead_Days,0))
ELSE CASE WHEN MAX(overridden) = 0 THEN NVL (MIN (src_start_dt), MIN (b2b_start_dt)) ELSE MAX(B2B_START_dT) END END as start_date
FROM prog_access_movie_v
WHERE trunc(SYSDATE) BETWEEN b2b_start_dt AND b2b_end_dt
AND (user_id IS NOT NULL OR GROUP_ID IS NOT NULL)
AND dist_type_id IN (5034) AND prog_id = (432899)
group by access_lead_days, dist_type_id

SQL - Sum of positive and negative numbers using subquery

I have a table which contains positive and negative numbers. I have to find out sum of positive and negative numbers using sub query
Your question isn't very clear (no table nor column names given), nor is it clear why you need a subquery (never a good idea if it can be avoided). You can get the values that you want by use of the 'case' statement
The following counts the number of positive and negative values
select sum (case when acolumn >= 0 then 1 else 0 end) as positive,
sum (case when acolumn < 0 then 1 else 0 end) as negative
from table
whereas the following sums the number of positive and negative values
select sum (case when acolumn >= 0 then acolumn else 0 end) as positive,
sum (case when acolumn < 0 then acolumn else 0 end) as negative
from table
For the sum of the negative :
SELECT SUM(numberColumn) FROM tableFoo WHERE numberColumn < 0
For the sum of the positive:
SELECT SUM(numberColumn) FROM tableFoo WHERE numberColumn >= 0
To combine the two (with QUERY1 and QUERY2 being the two previous queries):
SELECT (QUERY1), (QUERY2)
select sum(case when a>=0 then a else 0 end) as positive,
sum(case when a<0 then a else 0 end) as negative
from a
By using CTE(Common table Expression) we can get the output.
;WITH Psum_CTE
AS
( SELECT SUM(num) AS PositiveSum
FROM sample
WHERE num>=0
)
,Nsum_CTE
AS
(
SELECT SUM(num) AS NegativeSum
FROM sample
WHERE num<0
)
SELECT PositiveSum,NegativeSum
FROM Psum_CTE,Nsum_CTE
SELECT (
(SELECT SUM(numberColumn) FROM tableFoo WHERE numberColumn < 0 ) -
(SELECT SUM(numberColumn) FROM tableFoo WHERE numberColumn > 0)
) AS totalCalculation
You can use sign to separate the values:
select Sum( ( Sign( n ) + 1 ) / 2 * n ) as PositiveSum,
Sum( -( Sign( n ) - 1 ) / 2 * n ) as NegativeSum
from YourTableOData;
Sign returns 1, 0 or -1 depending on the sign of the input value. A little arithmetic can convert that into 1 or 0 depending on the sign: ( Sign( n ) + 1 ) / 2 is 1 for all positive values, otherwise 0. Note that the check for negative values (( Sign( n ) - 1 ) / 2) returns -1 or 0, hence the negation (-) to avoid flipping the sign of the value that is being summed.