ORDER BY upper(...) with a UNION giving me problems - sql

I'm having a bit of trouble figuring out why I'm having this problem.
This code works exactly how it should. It combines the two tables (MESSAGES and MESSAGES_ARCHIVE) and orders them correctly.
SELECT * FROM (
SELECT rownum as rn, a.* FROM (
SELECT
outbound.FROM_ADDR, outbound.TO_ADDR, outbound.EMAIL_SUBJECT
from MESSAGES outbound
where (1 = 1)
UNION ALL
SELECT
outboundarch.FROM_ADDR, outboundarch.TO_ADDR, outboundarch.EMAIL_SUBJECT
from MESSAGES_ARCHIVE outboundarch
where (1 = 1)
order by FROM_ADDR DESC
) a
) where rn between 1 and 25
However, this code does not work.
SELECT * FROM (
SELECT rownum as rn, a.* FROM (
SELECT
outbound.FROM_ADDR, outbound.TO_ADDR, outbound.EMAIL_SUBJECT
from MESSAGES outbound
where (1 = 1)
UNION ALL
SELECT
outboundarch.FROM_ADDR, outboundarch.TO_ADDR, outboundarch.EMAIL_SUBJECT
from MESSAGES_ARCHIVE outboundarch
where (1 = 1)
order by upper(FROM_ADDR) DESC
) a
) where rn between 1 and 25
and returns this error
ORA-01785: ORDER BY item must be the number of a SELECT-list expression
01785. 00000 - "ORDER BY item must be the number of a SELECT-list expression"
I'm trying to get the two tables ordered regardless of letter case, which is why I'm using upper(FROM_ADDR). Any suggestions? Thanks!

I'm not quite sure why this is generating an error, but it probably has to do with scoping rules for union queries. There is an easy work-around, using row_number():
SELECT * FROM (
SELECT row_number() over (order by upper(FROM_ADDR)) as rn, a.*
FROM (
SELECT
outbound.FROM_ADDR, outbound.TO_ADDR, outbound.EMAIL_SUBJECT
from MESSAGES outbound
where (1 = 1)
UNION ALL
SELECT
outboundarch.FROM_ADDR, outboundarch.TO_ADDR, outboundarch.EMAIL_SUBJECT
from MESSAGES_ARCHIVE outboundarch
where (1 = 1)
) a
)
where rn between 1 and 25

Your upper() is returning a value, but not a column name.
Instead of:
order by upper(FROM_ADDR) DESC
try:
order by upper(FROM_ADDR) as FROM_ADDR DESC

Related

oracle db from keyword not found where expected in double cte

I have a double cte expression , the first one join two tables and the second is implementing a partition by function:
with cte as (
select *
from memuat.product p
join memuat.licence l on p.id = l.product_id
where l.managed = 'TRUE'
),
joined as (
select
*,
row_number() over (partition by id order by id) as rn
from cte
)
select * from joined;
I get the following error:
ORA-00923: FROM keyword not found where expected, ERROR at line 12.
I cannot figure out which syntax error is wrong in my query.
Oracle is nitpicking when it comes to SELECT *. SELECT * means "select everything", so how can you possibly add something to it? In Oracle you cannot SELECT *, 1 AS something_else FROM some_table. You must have SELECT some_table.*, 1 AS something_else FROM some_table, so you are no longer selecting "everything", but "everything from the table" :-)
You have
select
*,
row_number() over (partition by id order by id) as rn
from cte
It must be
select
cte.*,
row_number() over (partition by id order by id) as rn
from cte
instead.

How to use conditions with a RANK statement

The following piece of code does its job : it gives me the top 10 results for each category.
SELECT *
FROM (
SELECT *, RANK() OVER (PARTITION BY "pera_id" ORDER BY "surface" DESC) AS rnk
FROM "testBadaBing"
) AS x
WHERE rnk <= 10
Now I'd like to add conditions so that the number of results may vary based on a criteria. Example : if "note" = 1, then I want to retain 1 result, else make it 3.
I tried something along the lines which you can see below using the CASE WHEN statement but as you might expect it doesn't work. Error returned :
1 - near "CASE": syntax error
SELECT *
CASE WHEN "note" = 1 THEN
SELECT *
FROM (
SELECT *, RANK() OVER (PARTITION BY "pera_id" ORDER BY "surface" DESC) AS rnk
FROM "testBadaBing"
) AS x
WHERE rnk <= 1
ELSE
SELECT *
FROM (
SELECT *, RANK() OVER (PARTITION BY "pera_id" ORDER BY "surface" DESC) AS rnk
FROM "testBadaBing"
) AS x
WHERE rnk <= 3
END
Do you have any ideas how to make this work? My knowledge of SQL is pretty limited. The code has to be SQLite/SpatiaLite compatible as I'm working in the QGIS environment. Thanks.
You can use boolean logic in the WHERE clause of the outer query:
SELECT *
FROM (
SELECT t.*,
RANK() OVER (PARTITION BY "pera_id" ORDER BY "surface" DESC) AS rnk
FROM "testBadaBing" t
) AS x
WHERE ("note" = 1 and rnk = 1) OR rnk <= 3

Missing Expression for the Oracle query

I am trying to run this query but I am getting a Missing Expression error.
SELECT *
FROM (
SELECT ROW_NUMBER() OVER(order by 'rownum') row_num1,
*
FROM A
WHERE refresh_date = (
SELECT max(refresh_date)
FROM A
WHERE upper(flaw_table_name) = upper('B')
)
)
WHERE row_num1 >= 1
AND row_num1 <=20
Can you please help me out, where I am getting wrong.
You have a constant in the order by clause. In addition, it is redundant to put rownum there in the first place. Just use rownum.
I think you want:
SELECT A.*
FROM A
WHERE refresh_date = (SELECT max(refresh_date)
FROM A
WHERE upper(flaw_table_name) = upper('B')
) AND
rownum between 1 and 20;
The subquery is not necessary and Oracle is smart enough to evaluate the rownum expression after the other conditions in the WHERE clause.
select star is in Oracle(?) not possible to combine with other explicite columns. You need to qualify the star with the alias A in the subquery.
SELECT ROW_NUMBER() OVER(order by 'rownum') row_num1,
A.*
FROM A
This is causing the Missing Expression error - after that you will see other errors
you have to add an alias, you cannot use * without a name if you're using other colnames or functions too
SELECT *
FROM (SELECT row_number() over(ORDER BY 'rownum') row_num1,
t.*
FROM a t
WHERE refresh_date =
(SELECT MAX(refresh_date)
FROM a
WHERE upper(flaw_table_name) = upper('B')))
WHERE row_num1 >= 1
AND row_num1 <= 20
SELECT * from (
select ROW_NUMBER() OVER(order by 'rownum') row_num1, * from A
where refresh_date = ( Select max(refresh_date)
from A
where upper(flaw_table_name) = upper('B')
)
) where row_num1>= 1 and row_num1<=20
replace last where clause with "and" as where is already present in query

Window Function in PostgreSQL

I have a with my SELECT statement that I just can't figure out. The query is as follows:
SELECT
count(1),
interaction_type_id
FROM
tibrptsassure.d_interaction_sub_type
GROUP BY
interaction_type_id
HAVING
count(interaction_type_id) > 1
ORDER BY
count(interaction_type_id) DESC
LIMIT 5;
Since my application does not support the use of the LIMIT keyword, I tried changing my query using the rank() function like so:
SELECT
interaction_type_id,
rank() OVER (PARTITION BY interaction_type_id ORDER BY count(interaction_type_id)
DESC)
FROM
tibrptsassure.d_interaction_sub_type;
However, this way I ended up with the following error message:
ERROR: column "d_interaction_sub_type.interaction_type_id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT interaction_type_id, rank() OVER (PARTITION BY inter...
^
********** Error **********
ERROR: column "d_interaction_sub_type.interaction_type_id" must appear in the GROUP BY clause or be used in an aggregate function
SQL state: 42803
Character: 9
Is there an equivalent of rownum() in PostgreSQL? (Apart from using the LIMIT keyword to achieve the same result, that is.)
Does anybody have any suggestions for me? Thanks in advance.
Test whether the following works (it is standard postgresql syntax and should work):
with
t as (
select 1 as id union all
select 1 as id union all
select 2 union all
select 2 union all
select 3)
select
id
from
t
group by
id
having
count(id) > 1
order by
id desc
limit 1
If this works then you have some syntax problem. If this does not work then you have some other issue - maybe the software you are using is constrained in some really strange way.
You can also use row_number(), but it is not very efficient way:
with
t as (
select 1 as id union all
select 1 as id union all
select 2 union all
select 2 union all
select 3)
, u as (
select
id,
count(*)
from
t
group by
id
)
, v as (
select
*,
row_number() over(order by id) c
from
u
)
select
*
from
v
where
c < 2
The problem was in my query, i.e. there was a syntax error.
What I needed was the top 5 category_id and top 5 instances of type_id in each category_id and top 5 instances of sub_type_id in each type_id. To achieve this, I changed the query in the following way and finally got the expected output:
SELECT * FROM (
SELECT t1.int_subtype_key, t2.interaction_sub_type_desc, interaction_category_id,
interaction_type_id, interaction_sub_type_id, count(interaction_sub_type_id) AS
subtype_cnt,
rank()
over (PARTITION BY interaction_category_id, interaction_type_id ORDER BY
count(interaction_sub_type_id) DESC) AS rank
FROM tibrptsassure.f_cc_call_analysis t1 INNER JOIN
tibrptsassure.d_interaction_sub_type t2 ON t1.int_cat_key = t2.intr_catg_ref_nbr
AND t1.int_subtype_key = t2.intr_sub_type_ref_nbr INNER JOIN
tibrptsassure.d_calendar t3 ON t1.interaction_date = t3.calendar_date GROUP BY
t2.interaction_sub_type_desc, t1.int_subtype_key, interaction_category_id,
interaction_type_id, interaction_sub_type_id) AS sub_type
WHERE rank <= 5;
Thanks to everyone for paying attention and helping me with this.

Select Nth Row From A Table In Oracle

How can I select the Nth row from a table in Oracle?
I tried
SELECT PRICE FROM AAA_PRICING WHERE ROWNUM = 2
but that didn't work. Please help!
Based on the classic answer:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:127412348064
select *
from ( select a.*, rownum rnum
from ( YOUR_QUERY_GOES_HERE -- including the order by ) a
where rownum <= N_ROWS )
where rnum >= N_ROWS
/
Will not works with '=' (will works <2 or >2, but not equal)
so you can
SELECT Price from (SELECT PRICE, ROWNUM AS RN FROM AAA_PRICING) WHERE RN = 2
To address the reason for this:
The RowNum is a pseudo-column supplied by Oracle. It is generated while the SELECT-clause is being processed. Since the WHERE-clause is handled before the SELECT-clause, the RowNum does not have a proper value yet.
One can argue whether or not it makes sense to have Oracle throw an exception in situation, but because RowNum still is a pseudo-column it's still valid to have it there.
Note: Don't confuse this with RowId, which is an entire different story!
IMPORTANT EDIT:
Note that what I wrote about RowNum is only true for =, >, >=, IN () and maybe others. If you check for, e.g. RowNum < 10, you only get nine records!? I don't know why that is the case!
Select * From
(
Select Row_Number() OVER (Order by empno) rno, e.*
From scott.emp e
)
Where rno in (1, 3, 11)
SELECT PRICE
FROM (
SELECT PRICE,
ROWNUM rnum
FROM AAA_PRICING
ORDER BY PRICE ASC
)
WHERE rnum = 2
If you are on Oracle 12 or above, You can use the result offset and fetch clauses:
SELECT PRICE FROM AAA_PRICING
offset 1 rows fetch next 1 rows only
SELECT * FROM
(SELECT PRICE, ROWNUM AS RN FROM AAA_PRICING )
WHERE RN = 2;
select * from (Select Price, rownum as rn from(Select * from AAA_PRICING a order by a.Price))
where rn=2;
It will give you 2nd lowest price from the Price column. If you want simply 2nd row remove Order By condition.
ROWNUM is a pseudo column which generates unique pseudo values (equals to the number of records present in the SELECT statement o/p) during the execution of SELECT clause. When this pseudo column is specified with the WHERE clause it's value becomes 1 by default. So it behaves according to the comparison operator specified with it.
SELECT * FROM (
SELECT ROWNUM RN, E.*
FROM Emp E
)
WHERE RN = 10;
select *
From (select PRICE, DENSE_RANK() over(ORDER BY PRICE desc) as RNO
From AAA_PRICING
) t where RNO=2;
select a.*, rownum rnum
from ( select * from xyz_menu order by priority desc) a
where rownum < 5 ;
select * from xyz_menu order by priority desc
creating virtual table and also defining row number in virtual table
note: for oracle
Problem solved!
To select 2nd row in Oracle..
select SEN_NO,ITEM_NO from (select * from master_machine where
sen_no ='BGCWKKL23' and rownum <=2 order by
rownum desc,timestamp asc) where rownum <=1
Thank You!