Oracle Inner Table Query - oracle

I am trying to write a query in Oracle to give totals of active legal entities and inactive legal entities.
The query so far I have is:
select le.Name, b.LE_ID, count(*) As TOTAL, dead.LE_ID as DEAD
from BOOK b
left join Legal_Entity le on le.LE_ID = b.LE_ID
left join
(
select count(LE_ID) as LE_ID
from BOOK
where (Name like '%DUMMY%' or name like '%TEST%' or name like '%DEAD%' or name like '%DO NOT%' or status <> 'Active')
) dead on dead.LE_ID = b.LE_ID
where b.LE_ID = 1234
group by le.Name, b.LE_ID, dead.LE_ID
order by b.LE_ID;
The results I am expecting are:
Name EntityID Total Dead
Entity A 1234 500 200
i.e. for Book.LE_ID = 1234 I would like one row in the result set and a column with the Total number i.e. select * from Book where LE_ID = 1234 and a column with the number of dead books i.e. the inner query
But at the moment, my query is returning NULL for the number of dead rows.
The inner query is working without issue, but I'm clearly missing something here.

I am not sure, but shouldn't it be something like this?
select le.Name, b.LE_ID, count(*) As TOTAL, dead.DEAD as DEAD
from BOOK b
left join Legal_Entity le on le.LE_ID = b.LE_ID
left join
(
select LE_ID, count(LE_ID) as DEAD
from BOOK
where (Name like '%DUMMY%' or name like '%TEST%' or name like '%DEAD%' or name like '%DO NOT%' or status <> 'Active')
group by LE_ID
) dead on dead.LE_ID = b.LE_ID
where b.LE_ID = 1234
group by le.Name, b.LE_ID, dead.LE_ID
order by b.LE_ID;

It is a bit hard to figure out exactly what you are trying to do. After all, you are trying to join between a count and an id, something that is not likely to lead to success.
Your example has a name 'Entity A'. By the rules specified in the query for "dead" entities, there should be none. The name doesn't match this rule.
In all likelihood, you want conditional aggregation. Here is a query that I think gets the totals over all entities:
select count(*) As TOTAL,
sum(case when Name like '%DUMMY%' or name like '%TEST%' or name like '%DEAD%' or name like '%DO NOT%' or status <> 'Active'
then 1 else 0
end) as dead
from BOOK b left join
Legal_Entity le
on le.LE_ID = b.LE_ID;

Related

ORA-00904: invalid column name but I am using the correct column name

Can someone see where I am going wrong in the below query? I am getting the error message that the GROUP BY column doesn't exist, but it clearly does as I see that column name in the output when I don't use the GROUP BY.
SELECT
(SELECT customer_address.post_code FROM customer_address WHERE customer_address.address_type = 0 AND customer_address.customer_no = orders.customer_no) postcode, SUM(orders.order_no) orders
FROM
orders, customer_address
WHERE
orders.delivery_date = '27-MAY-15'
GROUP BY
postcode;
The answer is: You cannot use an alias name in GROUP BY.
So:
GROUP BY (SELECT customer_address.post_code ...);
Or:
select postcode, sum(order_no)
from
(
SELECT
(SELECT customer_address.post_code FROM customer_address WHERE customer_address.address_type = 0 AND customer_address.customer_no = orders.customer_no) postcode,
orders.order_no
FROM orders, customer_address
WHERE orders.delivery_date = '27-MAY-15'
)
GROUP BY postcode;
EDIT:
However, your query seems wrong. Why do you cross-join orders and customer_address? By mistake I guess. Use explicit joins (INNER JOIN customer_address ON ...), when using joins to avoid such errors. But here I guess you'd just have to remove , customer_address.
Then why do you add order numbers? That doesn't seem to make sense.

Hibernate HQL GroupBy in Oracle

I created this query using HQL with Hibernate and Oracle
select c from Cat c
left join c.kittens k
where (c.location= 1 OR c.location = 2)
and (i.activo = 1)
group
by c.id,
c.name,
c.fulldescription,
c.kittens
order by count(e) desc
The problem comes with the fact that in HQL you need to specify all fields in Cat in order to perform a Group By, but fulldescription is a CLOB, and you cannot group by by a CLOB (I get a "Not a Group By Expression" error. I've seen a few solutions around for a pure SQL sentence but none for HQL.
A serious issue GROUP BY of HQL because if you specify your object in GROUP BY and in your SELECT field list behaviours are differents. In GROUP BY has considered only id field but in SELECT field list all fields are considered.
So you can use a subquery with GROUP BY to return only id from your object, so that result becomes an input for the main query, like the follow I write for you.
Pay attention there are some alias table (i and e) not defined, so this query doesn't work, but you know as fixed.
Try this:
select c2 from Cat c2
where c2.id in (
select c.id from Cat c
left join c.kittens k
where (c.location= 1 OR c.location = 2)
and (i.activo = 1) <-- who is i alias??
group by c.id)
order by count(e) desc <-- who is e alias???

Group and count query in HQL

I have HQL query that is giving me a headache and am hoping a friendly HQL wizard is out there who can help.
I think I'm trying to do something really simple but can't fathom it all.
I want to group and count some data to present it in a table and think I need a nested query of some sort but can't figure out the way to do it.
Basically I have a table (clients) which has relations to other tables that are used as lookups (clienttype) and (clientsex). The relationships is 1-m. I want to group the clients by type and then have a column counting males, and another counting females. e.g
Type | males | females
type A | x | x
type B | x | x
I can do the query just to get males or females but can't figure out how to get a second column.
Hope this makes sense, is possible and that someone is able to help.
Many thanks,
Craig
Query to get just males is:
SELECT a.clientStatus, COUNT(c.sex)
FROM
Tblclientstatus AS a RIGHT OUTER JOIN a.tblclients AS b
LEFT OUTER JOIN b.tblsex AS c
WHERE c.sex = 'male'
GROUP BY a.clientStatus
You can have a case when to add up "1" for each sex.
Something like this :
SELECT a.clientStatus,
COUNT(
case when c.sex = 'male' then 1
else 0 end
) as males,
COUNT(
case when c.sex = 'female' then 1
else 0 end
) as females,
FROM
Tblclientstatus AS a RIGHT OUTER JOIN a.tblclients AS b
LEFT OUTER JOIN b.tblsex AS c
GROUP BY a.clientStatus

Reference parent query column in subquery (Oracle)

How can I reference a column outside of a subquery using Oracle? I specifically need to use it in the WHERE statement of the subquery.
Basically I have this:
SELECT Item.ItemNo, Item.Group
FROM Item
LEFT OUTER JOIN (SELECT Attribute.Group, COUNT(1) CT
FROM Attribute
WHERE Attribute.ItemNo=12345) A ON A.Group = Item.Group
WHERE Item.ItemNo=12345
I'd like to change WHERE Attribute.ItemNo=12345 to WHERE Attribute.ItemNo=Item.ItemNo in the subquery, but I can't figure out if this is possible. I keep getting "ORA-00904: 'Item'.'ItemNo': Invalid Identifier"
EDIT:
Ok, this is why I need this kind of structure:
I want to be able to get a count of the "Error" records (where the item is missing a value) and the "OK" records (where the item has a value).
The way I have set it up in the fiddle returns the correct data. I think I might just end up filling in the value in each of the subqueries, since this would probably be the easiest way. Sorry if my data structures are a little convoluted. I can explain if need be.
My tables are:
create table itemcountry(
itemno number,
country nchar(3),
imgroup varchar2(10),
imtariff varchar2(20),
exgroup varchar2(10),
extariff varchar2(20) );
create table itemattribute(
attributeid varchar2(10),
tariffgroup varchar2(10),
tariffno varchar2(10) );
create table icav(
itemno number,
attributeid varchar2(10),
value varchar2(10) );
and my query so far is:
select itemno, country, imgroup, imtariff, im.error "imerror", im.ok "imok", exgroup, extariff, ex.error "exerror", ex.ok "exok"
from itemcountry
left outer join (select sum(case when icav.itemno is null then 1 else 0 end) error, sum(case when icav.itemno is not null then 1 else 0 end) ok, tariffgroup, tariffno
from itemattribute ia
left outer join icav on ia.attributeid=icav.attributeid
where (icav.itemno=12345 or icav.itemno is null)
group by tariffgroup, tariffno) im on im.tariffgroup=imgroup and imtariff=im.tariffno
left outer join (select sum(case when icav.itemno is null then 1 else 0 end) error, sum(case when icav.itemno is not null then 1 else 0 end) ok, tariffgroup, tariffno
from itemattribute ia
left outer join icav on ia.attributeid=icav.attributeid
where (icav.itemno=12345 or icav.itemno is null)
group by tariffgroup, tariffno) ex on ex.tariffgroup=exgroup and extariff=ex.tariffno
where itemno=12345;
It's also set up in a SQL Fiddle.
You can do it in a sub-query but not in a join. In your case I don't see any need to. You can put it in the join condition.
select i.itemno, i.group
from item i
left outer join ( select group, itemno
from attribute b
group by group itemno ) a
on a.group = i.group
and i.itemno = a.itemno
where i.itemno = 12345
The optimizer is built to deal with this sort of situation so utilise it!
I've changed the count(1) to a group by as you need to group by all columns that aren't aggregated.
I'm assuming that your actual query is more complicated than this as with the columns you're selecting this is probably equivilent to
select itemno, group
from item
where itemno = 12345
You could also write your sub-query with an analytic function instead. Something like count(*) over ( partition by group).
As an aside using a keyword as a column name, in this case group is A Bad Idea TM. It can cause a lot of confusion. As you can see from the code above you have a lot of groups in there.
So, based on your SQL-Fiddle, which I've added to the question I think you're looking for something like the following, which doesn't look much better. I suspect, given time, I could make it simpler. On another side note explicitly lower casing queries is never worth the hassle it causes. I've followed your naming convention though.
with sub_query as (
select count(*) - count(icav.itemno) as error
, count(icav.itemno) as ok
, min(itemno) over () as itemno
, tariffgroup
, tariffno
from itemattribute ia
left outer join icav
on ia.attributeid = icav.attributeid
group by icav.itemno
, tariffgroup
, tariffno
)
select ic.itemno, ic.country, ic.imgroup, ic.imtariff
, sum(im.error) as "imerror", sum(im.ok) as "imok"
, ic.exgroup, ic.extariff
, sum(ex.error) as "exerror", sum(ex.ok) as "exok"
from itemcountry ic
left outer join sub_query im
on ic.imgroup = im.tariffgroup
and ic.imtariff = im.tariffno
and ic.itemno = im.itemno
left outer join sub_query ex
on ic.exgroup = ex.tariffgroup
and ic.extariff = ex.tariffno
and ic.itemno = ex.itemno
where ic.itemno = 12345
group by ic.itemno, ic.country
, ic.imgroup, ic.imtariff
, ic.exgroup, ic.extariff
;
You can put WHERE attribute.itemno=item.itemno inside the subquery. You are going to filter the data anyway, filtering the data inside the subquery is usually faster too.

Best way to exclude records from multiple tables

I got the following tables (just an example): vehicles, vehicle_descriptions, vehicle_parts
vehicles have 1 to many with vehicle_descriptions and vehicle_parts. There may not be a corresponding vehicle_description/part for a given vehicle.
SELECT * FROM vehicles
LEFT OUTER JOIN vehicles d ON vehicles.vin = d.vin AND d.summary NOT LIKE 'honda'
LEFT OUTER JOIN
(SELECT SUM(desc_total) FROM vehicle_descriptions WHERE NOT LIKE desc 'honda' GROUP BY vin) b
ON vehicles.vin = vehicle_b.vin
LEFT OUTER JOIN
(SELECT SUM(part_count) FROM vehicle_parts WHERE part_for NOT LIKE 'honda' GROUP BY vin) c ON vehicles.vin = c.vin
If either vehicle_desc, vehicles, or part contains the exclusion term, the whole record should not show up in the result set. The query above will return a record even if one of the tables contain the exclusion term Honda. How would I fix the above query?
You're not using any of the information in either sum() as part of what you show, just to decide whether to include the vehicle. And you're doing an unnecessary self join in your first clause. Generally in situations like this, the "exists" and "not exists" clauses work well. So what about this? I'll use Oracle syntax, you can convert to ANSI of course.
SELECT * FROM vehicles v where summary <> 'honda'
and not exists (select 1 from vehicle_descriptions d where d.vin = v.vin and d.desc <> 'honda')
and not exists (select 1 from vehicle_parts p where p.vin = v.vin and p.part_for <> 'honda')

Resources