Oracle co related query? - oracle

How does co-related query works? Does inner query iterate according to outer query rows? Suppose I have student table with only 1 ID columns with vlaues 1, 2, 3. Can any body gives pictorial example?
select count(*)
from student s where s.sid < any (select s1.id from student s1 where s1.id < s.id);

The correlated subquery is (theoretically - without considering possible optimization) performed once for each row of the main table (s).
For the s.ID = 1 the subquery returns no row (s1.ID < 1 return nothing)
for the s.ID = 2 it returns 1 and (predicate s1.id < 2)
for the s.ID = 3 it returns 1,2
Therefore the first row (s.ID=1) is not selected (the subquery return no row),
for the second row (s.ID =2) the predicate is s.id < any ( 1 ) which is rewritten to s.id < 1 see rules for ANY
and the row is not selected as 2 < 1 is FALSE
for the third row (s.ID = 3) the predicate is s.id < any ( 1,2 ) which is rewritten to s.id < 1 OR s.id < 2 which is FLASE as well.
So the query
create table student as
select rownum id from dual connect by level <= 3;
select *
from student s where s.id < any (select s1.id from student s1 where s1.id < s.id);
return empty result (no rows).

Related

calculate percentage of two select counts

I have a query like
select count(1) from table_a where state=1;
it gives 20
select count(1) from table_a where state in (1,2);
it gives 25
I would like to have a query to extract percentage 80% (will be 20*100/25).
Is possible to have these in only one query?
I think without testing that the following SQL command can do that
SELECT SUM(CASE WHEN STATE = 1 THEN 1 ELSE 0 END)
/SUM(CASE WHEN STATE IN (1,2) THEN 1 ELSE 0 END)
as PERCENTAGE
FROM TABLE_A
or the following
SELECT S1 / (S1 + S2) as S1_PERCENTAGE
FROM
(
SELECT SUM(CASE WHEN STATE = 1 THEN 1 ELSE 0 END) as S1
,SUM(CASE WHEN STATE = 2 THEN 1 ELSE 0 END) as S2
FROM TABLE_A
)
or the following
SELECT S1 / T as S1_PERCENTAGE
FROM
(
SELECT SUM(CASE WHEN STATE = 1 THEN 1 ELSE 0 END) as S1
,SUM(CASE WHEN STATE IN (1,2) THEN 1 ELSE 0 END) as T
FROM TABLE_A
)
you have the choice for performance or readability !
Just as a slight variation on #schlebe's first query, you can continue to use count() by making that conditional:
select count(case when state = 1 then state end)
/ count(case when state in (1, 2) then state end) as result
from table_a
or multiplying by 100 to get a percentage instead of a decimal:
select 100 * count(case when state = 1 then state end)
/ count(case when state in (1,2) then state end) as percentage
from table_a
Count ignores nulls, and both of the case expressions default to null if their conditions are not met (you could have else null to make it explicit too).
Quick demo with a CTE for dummy data:
with table_a(state) as (
select 1 from dual connect by level <= 20
union all select 2 from dual connect by level <= 5
union all select 3 from dual connect by level <= 42
)
select 100 * count(case when state = 1 then state end)
/ count(case when state in (1,2) then state end) as percentage
from table_a;
PERCENTAGE
----------
80
Why the plsql tag? Regardless, i think what you need is:
(select count(1) from table_a where state=1) * 100 / (select count(1) from table_a where state in (1,2)) from dual

how to filter out null value then compare in oracle

I tried this, and it works,
SELECT name
FROM
(SELECT name,LENGTH FROM river WHERE LENGTH IS NOT NULL
)
WHERE LENGTH >= ALL
(SELECT LENGTH FROM
(SELECT name,LENGTH FROM river WHERE LENGTH IS NOT NULL
)
)
but my final code would be like this:
SELECT a.name,
a.length
FROM
(SELECT name,LENGTH FROM river WHERE LENGTH IS NOT NULL
) a,
geo_river b,
encompasses c
WHERE a.length >= ALL
(SELECT a2.LENGTH
FROM
(SELECT name,LENGTH FROM river WHERE LENGTH IS NOT NULL
) a2
)
AND a.name = b.river
AND b.country = c.country
AND c.continent = 'America'
this is really complicated.
Is there an easy way to let
(SELECT name,LENGTH FROM river WHERE LENGTH IS NOT NULL)
be river, so I don't need to use this
(SELECT name,LENGTH FROM river WHERE LENGTH IS NOT NULL)
two times.
If you want to simplify your code writing, you can use WITH:
with viewA as (SELECT name,LENGTH FROM river WHERE LENGTH IS NOT NULL )
SELECT a.name,
a.length
FROM
viewA a,
geo_river b,
encompasses c
WHERE a.length >= ALL
(SELECT a2.LENGTH
FROM
viewA a2
)
AND a.name = b.river
AND b.country = c.country
AND c.continent = 'America'
Using a single table scan:
SELECT name,
length
FROM (
SELECT name,
length,
RANK() OVER ( ORDER BY length DESC ) AS rnk
FROM river
)
WHERE rnk = 1;
So your code would then be:
SELECT a.name,
a.length
FROM (
SELECT name,
length
FROM (
SELECT name,
length,
RANK() OVER ( ORDER BY length DESC ) AS rnk
FROM river
)
WHERE rnk = 1
) a
INNER JOIN
geo_river b
ON ( a.name = b.river )
INNER JOIN
encompasses c
ON ( b.country = c.country )
WHERE c.continent = 'America';
I don't think you need to filter out null lengths as they won't show up if you subset on length (i.e. when comparing NULL values without using the NVL function the comparison will always evaluate to false and not show the row). So something simple such as:
Select a.name, a.length
from river a, geo_river b, encompasses c
WHERE a.length > 0
AND a.name = b.river
AND b.country = c.country
AND c.continent = 'America'
;
Will do the trick

Convert SQL Server CTE into Oracle CTE

Here is the SQL Server CTE, trying to convert to Oracle CTE or regular oracle query..
;with cte as
(Select AC, M, Y, D, E, F, CD
from tblA
WHere
(Y = YEAR(GETDATE()) and M = Month(dateadd(month, -1, GETDATE())))
),
cte2 as
(Select A.AC,Max(A.Y)as Y, Max(A.M) as M, Max(A.CD) as CD
from tbl A
Inner join cte B on B.AC = A.AC
WHere A.CD is Not Null and B.CD is Null
Group by A.AC)
, cte3 as
(Select C.AC, C.Y, C.M, C.D, C.E, C.F, C.CD
from tblA C
Inner join cte2 D on C.AC = D.AC and C.Y= D.Y and C.M = D.M and
D.CD = C.CD
)
select * from cte
union
select * from cte3;
Assuming you didn't have the m and y columns reversed on purpose in your cte/cte3 select lists, I think you could rewrite your query as:
with cte1 as (select a.ac,
a.m,
a.y,
a.d,
a.e,
a.f,
a.cd,
max(case when a.cd is not null and b.cd is not null then a.y end) over (partition by a.ac) max_y,
max(case when a.cd is not null and b.cd is not null then a.m end) over (partition by a.ac) max_m,
max(case when a.cd is not null and b.cd is not null then a.cd end) over (partition by a.ac) max_cd
from tbla a
left outer join tblb b on (a.ac = b.ac))
select ac,
m,
y,
d,
e,
f,
cd
from cte1
where (y = to_char(sysdate, 'yyyy')
and m = to_char(add_months(sysdate, -1), 'mm'))
or (y = max_y
and m = max_m
and cd = max_cd);
You haven't provided any sample data, so I can't test, but it would be worth converting the date functions to their SQL Server equivalents and testing to make sure the data returned is the same.
This way, you're not querying the same table 3 times, which should improve the performance some.

Linq to Entities Non-Equal Join

I must perform the following SQL command using IQueryable:
SELECT * FROM myTable t1
INNER JOIN myTable t2 ON t1.time = t2.time + 1
OR t1.time = t2.time + 2
OR t1.time = t2.time + 3;
Linq to Entities does not allow me to use IEqualityComparer, so I'm looking for some way to accomplish this Join.
Must use IQueryable and can not put conditions via Where as myTable has millions of records and implementation would be very slow:
qry = qry.Join(...).Where(...);
I need
qry = qry.Join(...);
Is there an alternative like IEqualityComparer for Linq to Entities?
Thank you!
Sorry my bad english!
I am not sure if this works with Lambda-Expression, but you can use Linq to achieve that:
var l = from i1 in conn.List1
from i2 in conn.List2
where
(
i1.time == i2.Time + 1
|| i1.time == i2.Time + 2
|| i1.time == i2.Time + 3
)
select new { i1, i2 }
Try also following:
var l = from i2 in conn.List2.Where(x => i1.time == x.Time + 1
|| i1.time == x.Time + 2
|| i1.time == x.Time + 3)
select new { i1, i2 }
Linq only supports equi-joins, so you will need to do this through a where clause.
That said, I would not expect a significant performance difference between a compound inner join and using a where clause - SQL should create similar (if not equal) plans for the following two queries:
SELECT *
FROM myTable t1
INNER JOIN myTable t2 ON t1.time = t2.time + 1
OR t1.time = t2.time + 2
OR t1.time = t2.time + 3;
SELECT *
FROM myTable t1 ,
myTable t2
WHERE t1.time = t2.time + 1
OR t1.time = t2.time + 2
OR t1.time = t2.time + 3;

get the sum of the maxs group by

I have this table
EquipmentId Value Date
1 2 11/04/2013
1 1 11/04/2013
2 3 11/04/2013
2 2 10/04/2013
2 5 10/04/2013
3 1 10/04/2013
3 3 11/04/2013
I want to group these items by date, and have a dictionary with the date as a key and the sum of the maxs of the all equipments values in that day
the result would be like this
[10/04/2013: 6] // 6 = 5 (as the max of values of the the equipmetId 2) + 1 (as the max of values of the the equipmetId 3)
[11/04/2013: 5] // 5 = 2(as the max of values of the the equipmetId 1) + 3(as the max of values of the the equipmetId 3)
I managed to make the query to get this without the sum, meaning for only one equipment.
var consumptionValues = (from c in context.ConsumptionSet
join pi in context.PropertiesInstanceSet on c.PropertiesInstanceID equals pi.PropertiesInstanceID
join ep in context.EquipmentPropertiesSet on pi.EquipmentPropertiesID equals ep.EquipmentPropertiesID
join e in context.EquipmentSet on ep.EquipmentID equals e.EquipmentID
where (e.EquipmentID == equipmentId && pi.ProprietesName == ProprietesName.Energy && c.Date <= DateTime.Now && c.Date >= firstDayDate)
group c by SqlFunctions.DatePart("weekday", c.Date) into grp
select new
{
dayOfWeek = (DayOfWeek)grp.Key.Value - 1,
value = grp.Max(c => c.Value),
}).ToDictionary(c => c.dayOfWeek.ToString(), c => c.value);
It's the complete query with all the joins, in the example I just gave a simplified example.
Is it possible to do this in one single query ?
I have to say I'm not sure it will work, but you should give it a shot:
var consumptionValues = (from c in context.ConsumptionSet
join pi in context.PropertiesInstanceSet on c.PropertiesInstanceID equals pi.PropertiesInstanceID
join ep in context.EquipmentPropertiesSet on pi.EquipmentPropertiesID equals ep.EquipmentPropertiesID
join e in context.EquipmentSet on ep.EquipmentID equals e.EquipmentID
where (e.EquipmentID == equipmentId && pi.ProprietesName == ProprietesName.Energy && c.Date <= DateTime.Now && c.Date >= firstDayDate)
group new { c, e } by SqlFunctions.DatePart("weekday", c.Date) into grp
select new
{
dayOfWeek = (DayOfWeek)grp.Key.Value - 1,
value = grp.GroupBy(i => i.e.EquipmentID).Sum(g => g.Max(i => i.c.Value)),
}).ToDictionary(c => c.dayOfWeek.ToString(), c => c.value);

Resources