Count of 2 distinct columns - oracle

How can I get the count of 2 columns such that there are distinct combinations of two columns?
Select count(distinct cola, colb)

SELECT COUNT(*)
FROM (
SELECT DISTINCT a, b
FROM mytable
)

SELECT COUNT(1)
FROM (
SELECT DISTINCT COLA, COLB
FROM YOUR_TABLE
)

Another way of doing it
SELECT COUNT(DISTINCT COLA || COLB)
FROM THE_TABLE
http://www.sqlfiddle.com/#!4/c287e/2

SELECT (select count(cola) from ...), (select count(colb) from ...) from ...
You may want to look at this:
http://www.java2s.com/Code/Oracle/Aggregate-Functions/COUNTcolumnandCOUNTcountthenumberofrowspassedintothefunction.htm
You can put Distinct in the subqueries, if you desire.

In Oracle DB, you can concat the columns and then count on that concatenated String like below:
SELECT count(DISTINCT concat(ColumnA, ColumnB)) FROM TableX;
In MySql, you can just add the columns as parameters in count method.
SELECT count(DISTINCT ColumnA, ColumnB) FROM TableX;

SELECT COUNT(*)
FROM (
SELECT DISTINCT a, b
FROM mytable
) As Temp

Related

equivalent of distinct On in Oracle

How to translate the following query to Oracle SQL, as Oracle doesn't support distinct on()?
select distinct on (t.transaction_id) t.transaction_id as transactionId ,
t.transaction_status as transactionStatus ,
c.customer_id as customerId ,
c.customer_name as customerName,
You can use ANY_VALUE with group by for this:
https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/any_value.html
Example: https://dbfiddle.uk/WUxvjv5J
with t (a,b,c) as (
select 1,10,1 from dual union all
select 1,10,2 from dual union all
select 1,10,3 from dual union all
select 1,20,4 from dual union all
select 1,20,5 from dual union all
select 1,30,7 from dual
)
select a,b,any_value(c)
from t
group by a,b;
Yes, Oracle has a full set of windowing functions you can use for this. The simplest is ROW_NUMBER:
SELECT *
FROM (SELECT x.col1,
x.col2,
x.col3,
ROW_NUMBER() OVER (PARTITION BY x.col1 ORDER BY x.col2 DESC) seq
FROM table x)
WHERE seq = 1
for each distinct col1, it will number the highest col2 value as seq=1, the next highest as seq=2, etc... so you can filter on 1 to get the desired row. You can used as complex ORDER BY logic as you need to pick the row you want. The key thing is that the ORDER BY goes inside the ROW_NUMBER OVER clause along with the distinct (PARTITION BY) definition, not outside in the main query block.

Oracle SQL -- Finding count of rows that match date maximum in table

I am trying to use a query to return the count from rows such that the date of the rows matches the maximum date for that column in the table.
Oracle SQL: version 11.2:
The following syntax would seem to be correct (to me), and it compiles and runs. However, instead of returning JUST the count for the maximum, it returns several counts more or less like the "HAIVNG" clause wasn't there.
Select ourDate, Count(1) as OUR_COUNT
from schema1.table1
group by ourDate
HAVING ourDate = max(ourDate) ;
How can this be fixed, please?
You can use:
SELECT MAX(ourDate) AS ourDate,
COUNT(*) KEEP (DENSE_RANK LAST ORDER BY ourDate) AS ourCount
FROM schema1.table1
or:
SELECT ourDate,
COUNT(*) AS our_count
FROM (
SELECT ourDate,
RANK() OVER (ORDER BY ourDate DESC) AS rnk
FROM schema1.table1
)
WHERE rnk = 1
GROUP BY ourDate
Which, for the sample data:
CREATE TABLE table1 (ourDate) AS
SELECT SYSDATE FROM DUAL CONNECT BY LEVEL <= 5 UNION ALL
SELECT SYSDATE - 1 FROM DUAL;
Both output:
OURDATE
OUR_COUNT
2022-06-28 13:35:01
5
db<>fiddle here
I don't know if I understand what you want. Try this:
Select x.ourDate, Count(1) as OUR_COUNT
from schema1.table1 x
where x.ourDate = (select max(y.ourDate) from schema1.table1 y)
group by x.ourDate
One option is to use a subquery which fetches maximum date:
select ourdate, count(*)
from table1
where ourdate = (select max(ourdate)
from table1)
group by ourdate;
Or, a more modern approach (if your database version supports it; 11g doesn't, though):
select ourdate, count(*)
from table1
group by ourdate
order by ourdate desc
fetch first 1 rows only;
You can use this SQL query:
select MAX(ourDate),COUNT(1) as OUR_COUNT
from schema1.table1
where ourDate = (select MAX(ourDate) from schema1.table1)
group by ourDate;

Query taking long when i use user defined function with order by in oracle select

I have a function, which will get greatest of three dates from the table.
create or replace FUNCTION fn_max_date_val(
pi_user_id IN number)
RETURN DATE
IS
l_modified_dt DATE;
l_mod1_dt DATE;
l_mod2_dt DATE;
ret_user_id DATE;
BEGIN
SELECT MAX(last_modified_dt)
INTO l_modified_dt
FROM table1
WHERE id = pi_user_id;
-- this table contains a million records
SELECT nvl(MAX(last_modified_ts),sysdate-90)
INTO l_mod1_dt
FROM table2
WHERE table2_id=pi_user_id;
-- this table contains clob data, 800 000 records, the table 3 does not have user_id and has to fetched from table 2, as shown below
SELECT nvl(MAX(last_modified_dt),sysdate-90)
INTO l_mod2_dt
FROM table3
WHERE table2_id IN
(SELECT id FROM table2 WHERE table2_id=pi_user_id
);
execute immediate 'select greatest('''||l_modified_dt||''','''||l_mod1_dt||''','''||l_mod2_dt||''') from dual' into ret_user_id;
RETURN ret_user_id;
EXCEPTION
WHEN OTHERS THEN
return SYSDATE;
END;
this function works perfectly fine and executes within a second.
-- random user_id , just to test the functionality
SELECT fn_max_date_val(100) as max_date FROM DUAL
MAX_DATE
--------
27-02-14
For reference purpose i have used the table name as table1,table2 and table3 but my business case is similar to what i stated below.
I need to get the details of the table1 along with the highest modified date among the three tables.
I did something like this.
SELECT a.id,a.name,a.value,fn_max_date_val(id) as max_date
FROM table1 a where status_id ='Active';
The above query execute perfectly fine and got result in millisecods. But the problem came when i tried to use order by.
SELECT a.id,a.name,a.value,a.status_id,last_modified_dt,fn_max_date_val(id) as max_date
FROM table1 where status_id ='Active' a
order by status_id desc,last_modified_dt desc ;
-- It took almost 300 seconds to complete
I tried using index also all the values of the status_id and last_modified, but no luck. Can this be done in a right way?
How about if your query is like this?
select a.*, fn_max_date_val(id) as max_date
from
(SELECT a.id,a.name,a.value,a.status_id,last_modified_dt
FROM table1 where status_id ='Active' a
order by status_id desc,last_modified_dt desc) a;
What if you don't use the function and do something like this:
SELECT a.id,a.name,a.value,a.status_id,last_modified_dt x.max_date
FROM table1 a
(
select max(max_date) as max_date
from (
SELECT MAX(last_modified_dt) as max_date
FROM table1 t1
WHERE t1.id = a.id
union
SELECT nvl(MAX(last_modified_ts),sysdate-90) as max_date
FROM table2 t2
WHERE t2.table2_id=a.id
...
) y
) x
where a.status_id ='Active'
order by status_id desc,last_modified_dt desc;
Syntax might contain errors, but something like that + the third table in the derived table too.

With clause not working with union

My query result is a union of several queries. I am facing the below error when I use WITH clause within a union. Any ideas why?
select column1 from TABLE_A
union
with abcd as (select * from TABLE_B)
select column2 from TABLE_A A, abcd
where abcd.m_reference = A.m_reference
ORA-32034: unsupported use of WITH clause
32034. 00000 - "unsupported use of WITH clause"
*Cause: Inproper use of WITH clause because one of the following two reasons
1. nesting of WITH clause within WITH clause not supported yet
2. For a set query, WITH clause can't be specified for a branch.
3. WITH clause can't sepecified within parentheses.
*Action: correct query and retry
Encapsulate your WITH statement in a dummy select.
select column1 from TABLE_A
union
select * from (
with abcd as (select * from TABLE_B)
select column2 from TABLE_A A, abcd
where abcd.m_reference = A.m_reference
)
Just define the CTE first, before the actual UNION query. Then use it as you would a regular table:
with abcd as (select * from TABLE_B)
select column1 from TABLE_A
union
select column2
from TABLE_A A
inner join abcd
on abcd.m_reference = A.m_reference
You can use multiple CTE as follows:
with cte1 AS (...),
cte2 AS (...)
select * from ...
Encapsulating it is the way to go if you have multiple WITHs; for example I just had to do this monstrosity to quickly pull in data from ID numbers from an Excel sheet
select * from (
with childvendor as (
select vendornumber, name From vendor where vendornumber = '0000800727'
)
select
v.vendornumber as parentvendor,
v.name as parentname,
cv.vendornumber as childvendor,
cv.name as childname
From
vendor v, childvendor cv
where
v.vendornumber = '0000800004'
)
UNION ALL
select * from (
with childvendor as (
select vendornumber, name From vendor where vendornumber = '0000800042'
)
select
v.vendornumber as parentvendor,
v.name as parentname,
cv.vendornumber as childvendor,
cv.name as childname
From
vendor v, childvendor cv
where
v.vendornumber = '0000800035'
)
And so on

Taking the record with the max date

Let's assume I extract some set of data.
i.e.
SELECT A, date
FROM table
I want just the record with the max date (for each value of A). I could write
SELECT A, col_date
FROM TABLENAME t_ext
WHERE col_date = (SELECT MAX (col_date)
FROM TABLENAME t_in
WHERE t_in.A = t_ext.A)
But my query is really long... is there a more compact way using ANALYTIC FUNCTION to do the same?
The analytic function approach would look something like
SELECT a, some_date_column
FROM (SELECT a,
some_date_column,
rank() over (partition by a order by some_date_column desc) rnk
FROM tablename)
WHERE rnk = 1
Note that depending on how you want to handle ties (or whether ties are possible in your data model), you may want to use either the ROW_NUMBER or the DENSE_RANK analytic function rather than RANK.
If date and col_date are the same columns you should simply do:
SELECT A, MAX(date) FROM t GROUP BY A
Why not use:
WITH x AS ( SELECT A, MAX(col_date) m FROM TABLENAME GROUP BY A )
SELECT t.A, t.date FROM TABLENAME t JOIN x ON x.A = t.A AND x.m = t.col_date
Otherwise:
SELECT A, FIRST_VALUE(date) KEEP(dense_rank FIRST ORDER BY col_date DESC)
FROM TABLENAME
GROUP BY A
You could also use:
SELECT t.*
FROM
TABLENAME t
JOIN
( SELECT A, MAX(col_date) AS col_date
FROM TABLENAME
GROUP BY A
) m
ON m.A = t.A
AND m.col_date = t.col_date
A is the key, max(date) is the value, we might simplify the query as below:
SELECT distinct A, max(date) over (partition by A)
FROM TABLENAME
Justin Cave answer is the best, but if you want antoher option, try this:
select A,col_date
from (select A,col_date
from tablename
order by col_date desc)
where rownum<2
Since Oracle 12C, you can fetch a specific number of rows with FETCH FIRST ROW ONLY.
In your case this implies an ORDER BY, so the performance should be considered.
SELECT A, col_date
FROM TABLENAME t_ext
ORDER BY col_date DESC NULLS LAST
FETCH FIRST 1 ROW ONLY;
The NULLS LAST is just in case you may have null values in your field.
SELECT mu_file, mudate
FROM flightdata t_ext
WHERE mudate = (SELECT MAX (mudate)
FROM flightdata where mudate < sysdate)

Resources