hql distinct order - sql-order-by

Hi i need to select distinct objects ordered by the newest subobject, how can i do this?
i tried to select the parent-objects from the subobjects:
SELECT DISTINCT r.forumTheme FROM ForumResponse r ORDER BY r.responseId DESC
i get
ORDER BY items must appear in the select list if SELECT DISTINCT is specified.
and when i try this:
SELECT DISTINCT r.forumTheme,r.responseId FROM ForumResponse r ORDER BY r.responseId DESC
the result isnt really distinct: forumTheme can appear multible times with different responseId
is there any solution?

For a given forumTheme, you have several responseIds. So how should they be sorted? Is [6, 3, 2] greater or lower than [5, 4, 2]?
This is why you can't do this order by.
You should probably execute the following query:
select r.forumTheme, max(r.responseId) from ForumResponse r
group by r.forumTheme
order by max(r.responseId)

Related

How to use a method of a collection inside a query (count in this case)

I use this example only because you can reproduct it easily. I already know that I could use the aggregate function count for this particular example. But the table t, that I'm using is already created and the column b is a collection.
WITH
s (a, b)
AS
(SELECT 1, 'ff' FROM DUAL
UNION ALL
SELECT 1, 'ee' FROM DUAL
UNION ALL
SELECT 1, 'ee' FROM DUAL
UNION ALL
SELECT 2, 'ee' FROM DUAL),
t (a, b)
AS
( SELECT s.a, COLLECT (s.b)
FROM s
group BY s.a)
select t.a, t.b.count()
from t
ORA-00904: "T"."B"."COUNT": invalid identifier
I have tried with a lot a collection methods but to no avail.
code
this question is similar to How to select the first element of a collection being a column of a query.
In this question I've already proposed a way to avoid using a collection method. Therefore, what I want to know is if it is possible to use a collection method and if yes how?
What I proposed in the similar question is cumbersom, if you have a easier way to do, I would be glad too.

How to add decode but also have count, group by and order by - not a group by expression

I'm rather new to Oracle. I'm trying to do a count of ports for a vendor/model. However, I only want ones with port_addr_status of 3 or 4. For some reason, I'm getting error
ORA-00979 not a group by expression
This is what I have so far. It works without the decode part, but I don't think the part with pi.port_addr.status in ('3','4') works without it. I'm open to working around that issue as well.
select
count(pi.port) as cnt, d.VENDOR, trim(d.model) as model,
decode(pi.PORT_ADDR_STATUS, '1', 'Unassigned', '2','Pending','3','In Service',
'4','Pending Disco', '5','Trouble', '6','Reserved',
'7','Reserved Capacity', pi.PORT_ADDR_STATUS)
from
table1 pi,
table2 d,
table3 c
where
pi.id = d.id and
pi.circuit_id = c.circuit_id
and pi.port_addr_status in ('3','4')
and (d.dslam_type_desc not in ('AGGREGATOR') or d.dslam_type_desc is null)
and d.DSLAM not like '%#%'
group by
d.VENDOR, d.model --, trim(d.model), pi.RACK, pi.SHELF, pi.SLOT, pi.PORT, pi.BROADBAND_CIRCUIT_ID, d.DSLAM,
order by
d.VENDOR asc, cnt desc
This is sample output:
1031 Adtran TA5000
10 Adtran TA1248V
3 Adtran TA1248
Since the decoded port type is not required in your output, just remove it from the select list. Group By should include everything in the select list except the aggregate functions. The below query should do the job:
select
count(pi.port) as cnt, d.VENDOR, trim(d.model) as model
from
table1 pi,
table2 d,
table3 c
where
pi.id = d.id and
pi.circuit_id = c.circuit_id
and pi.port_addr_status in ('3','4')
and (d.dslam_type_desc not in ('AGGREGATOR') or d.dslam_type_desc is null)
and d.DSLAM not like '%#%'
group by
d.VENDOR, trim(d.model)
order by
d.VENDOR asc, cnt desc
Note that the filter down to specific port types is achieved here:
and pi.port_addr_status in ('3','4')
in the where clause - the decode statement in your original query did nothing to solve your requirements and was the direct cause of the error. In a basic aggregate query like this, group by should have every item that is in the select list that is not an aggregate function.
You might use decode statement in the select list with an aggregation function preferably max as
max( decode(pi.PORT_ADDR_STATUS, '1', 'Unassigned', '2','Pending', .... )
The reason you're getting that error is:
when using a GROUP BY clause you are asking the DBMS to give you a single row corresponding to your GROUP BY list
in your case, you are asking for one row per (Vendor, Model) combination
since each of these rows represents possibly many "underlying" rows (say, e.g. 5 rows for Vendor=A and Model=B), the only other fields you can have in the select list must be aggregates (that's why the "count" field works, it counts the rows, i.e. it can take many row values and return a single value)
the DECODE function is not an aggregate function - it can't "collapse" multiple values into one value (like, say, MAX() can)
It looks to me as if your DECODE function returns strings, so I recommend you aggregate the strings with the LISTAGG function (so if your 5 rows have values of 'asdf', 'fdsa', 'qwer', 'rewq', and 'zxcv' the LISTAGG function would return a single string: 'asdf,fdsa,qwer,rewq,zxcv')
So you would replace your DECODE(...) call with, e.g. LISTAGG(DECODE(...), ',')
Reference for LISTAGG function: https://docs.oracle.com/cd/E11882_01/server.112/e41084/functions089.htm#SQLRF30030

Using TOP in ORACLE SQL 9

Hello I'am very new to writing SQL and I am trying to find the appropriate way to use TOP in Oracle SQl 9:
My example:
select * from example e, test t
where e.id = t.id
and country = 'USA'
order by state ASC;
What I am trying to do is take the bottom 20 % of my query but I know you cannot use TOP. After researching I still have not found an applicable answer. I know you have to first order them but am unsure of how to then take the bottom 20%(which would be TOP since the order is ASC)
In general (like if you want the top or bottom 17.2% of the rows) you can use row_number() and count() (analytic functions) to get the result.
20% is easier - you are looking for the top (or bottom) quintile. For this, you can use the ntile() function, like so:
select [column_names]
from (
select e.*, t.*, ntile(5) over (order by state) as nt
from ..... etc
)
where nt = 1;
The subquery is your query. The column_names in the outer query are whatever you actually need; you could also use select * but that will show the ntile too (which will be 1 in all rows).
If sorting something in ASCending order gives us the top set then surely sorting in DESCending order can give us the bottom set.
This solution uses the function NTILE() to divide the records into five buckets. The first bucket is the set we want (because sorted in descending order). Sorting in ascending order and taking the fifth quintile would have the same outcome.
select * from (
select e.*
, t.*
, ntile(5) over (order by state desc) nt
from example e, test t
where e.id = t.id
and country = 'USA'
)
where nt = 1
order by state desc
/
You don't say what your sort criteria are, so I've guessed.

Can we perform nonequi join with outer join?

Can we perform outer join with inquality operators.
When I tried I got the result for right outer join but it's not working for left outer join.
SELECT EMP.ENAME,EMP.SALARY,SALG.SALARY_GRADE
FROM EMPLOYEE EMP , SALARY_GRADES SALG
WHERE EMP.SAL BETWEEN SALG.FROM_RANGE(+) AND SALG.TO_RANGE
Above query is generating the result as inner join where as below query is working fine.
SELECT EMP.ENAME,EMP.SALARY,SALG.SALARY_GRADE
FROM EMPLOYEE EMP , SALARY_GRADES SALG
WHERE EMP.SAL(+) BETWEEN SALG.FROM_RANGE AND SALG.TO_RANGE
I meant to say that right outer join is working fine but not left outer join.
Ummm, yes. Did you create a simple test case to demonstrate? Please always do this.
Both LEFT and RIGHT JOINs work fine. Given the following schema:
create table a (
id number
, val number );
insert all
into a values (1, 1)
into a values (2, 2)
into a values (3, 5)
select * from dual;
create table b (
id number
, min_val number
, max_val number );
insert all
into b values (1, 1, 1)
into b values (2, 1, 6)
into b values (3, 4, 6)
into b values (3, 10, 12)
select * from dual;
These two queries return the expected data. Please note my use of ANSI joins.
select *
from a
left outer join b
on a.val between b.min_val and b.max_val;
select *
from a
right outer join b
on a.val between b.min_val and b.max_val;
Here's the proof.
If you're ever in any doubt as to whether there is a problem with the database or your code you should assume either that your code is incorrect or that the data in your database simply does not exist. It's highly unlikely to be the database itself.
A very good way to test this is to do as I have done, create a very simple example. A short, self-contained, correct example that demonstrates the concepts you're using. You can then apply this to your own code to work out where you might have been going wrong.
You've commented:
Thanks for your answer but......when I insert one more record with 4
as id and 50 as value using insert into a values(4,50); then if i
query using oracle proprietary syntax like select * from a, b where
a.val between b.min_val(+) and b.max_val; I am not getting inserted
record in the result...? It is working with ansi syntax but not with
traditional syntax.....
So, this would imply that your query using the Oracle proprietary syntax is incorrect. I much prefer the ANSI standard as it's extremely obvious if you've done something wrong and it's portable. However, if you want to use the Oracle syntax the reason is that you've turned it into an INNER JOIN but not stating that both items in the BETWEEN are part of the OUTER JOIN:
select *
from a
, b
where a.val between b.min_val(+) and b.max_val(+);

Oracle: MIN() Statement causes empty row returns

I'm having a small issue with sorting the data returned from a query, with the aim of getting the oldest updated value in dataset so that I can update only that record. Here's what I'm doing:
WHERE ROWNUM = 1 AND TABLE1.ID != V_IGNOREID
AND TABLE1.LASTREADTIME = (SELECT MIN(TABLE1.LASTREADTIME) FROM TABLE1)
ORDER BY TABLE1.LASTREADTIME DESC;
It makes no difference as to whether the ORDER BY statement is included or not. If I only use the ROWNUM and equality checks, I get data, but it alternates between only two rows, which is why I'm trying to use the LASTREADTIME data (so that I can modify more than these two rows). Anybody have any thoughts on this, or any suggestions as to how I can use the MIN function effectively?
Cheers
select * from (
-- your original select without rownum and with order by
)
WHERE ROWNUM = 1
EDIT some explanation
I think the order by clause is applied on the resultset after the where clause. So if the rownum = 1 is in the same select statement with the order by, then it will be applied first and the order by will order only 1 row, which will be the first row of the unordered resultset.

Resources