ORA-00904 : invalid identifier [duplicate] - sql

This question already has answers here:
Using an Alias in a WHERE clause
(5 answers)
Closed 8 months ago.
I am only a beginner in SQL, but I've come across this annoying error. SQL is having an issue with the WHERE clause of this script:
SELECT
ITEM_ID, ITEM_PRICE, DISCOUNT_AMOUNT, QUANTITY,
(ITEM_PRICE*QUANTITY) AS price_total,
(DISCOUNT_AMOUNT*QUANTITY) AS discount_total,
((ITEM_PRICE-DISCOUNT_AMOUNT)*QUANTITY) AS item_total
FROM ORDER_ITEMS
WHERE item_total > 500
ORDER BY item_total;
I am receiving this error:
Error starting at line : 1 in command -
SELECT
ITEM_ID, ITEM_PRICE, DISCOUNT_AMOUNT, QUANTITY,
(ITEM_PRICE*QUANTITY) AS price_total,
(DISCOUNT_AMOUNT*QUANTITY) AS discount_total,
((ITEM_PRICE-DISCOUNT_AMOUNT)*QUANTITY) AS item_total
FROM ORDER_ITEMS
WHERE item_total > 500
ORDER BY item_total DESC;
Error at Command Line : 7 Column : 7
Error report -
SQL Error: ORA-00904: "ITEM_TOTAL": invalid identifier
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
I have no idea why it has no issue with price_total nor discount_total, but is reporting item_total as invalid. I am trying to first select only the items which have a total greater than 500 when the discount amount is subtracted and it is multiplied by the quantity. Then, I need to sort the results in descending order by item_total

An alias can be used in a query select list to give a column a different name. You can use the alias in GROUP BY, ORDER BY, or HAVING
clauses to refer to the column.
Standard SQL disallows references to column aliases in a WHERE clause. This restriction is imposed because when the WHERE clause is
evaluated, the column value may not yet have been determined.
So, the following query is illegal:
SQL> SELECT empno AS employee, deptno AS department, sal AS salary
2 FROM emp
3 WHERE employee = 7369;
WHERE employee = 7369
*
ERROR at line 3:
ORA-00904: "EMPLOYEE": invalid identifier
SQL>
The column alias is allowed in:
GROUP BY
ORDER BY
HAVING
You could refer to the column alias in WHERE clause in the following cases:
Sub-query
Common Table Expression(CTE)
For example,
SQL> SELECT * FROM
2 (
3 SELECT empno AS employee, deptno AS department, sal AS salary
4 FROM emp
5 )
6 WHERE employee = 7369;
EMPLOYEE DEPARTMENT SALARY
---------- ---------- ----------
7369 20 800
SQL> WITH DATA AS(
2 SELECT empno AS employee, deptno AS department, sal AS salary
3 FROM emp
4 )
5 SELECT * FROM DATA
6 WHERE employee = 7369;
EMPLOYEE DEPARTMENT SALARY
---------- ---------- ----------
7369 20 800
SQL>

Starting from Oracle 12c you could use CROSS APPLY to define expression and then you could refer to them in WHERE clause:
SELECT
o.ITEM_ID, o.ITEM_PRICE, o.DISCOUNT_AMOUNT, o.QUANTITY,
s.price_total, s.discount_total, s.item_total
FROM ORDER_ITEMS o
CROSS APPLY (SELECT ITEM_PRICE*QUANTITY AS price_total,
DISCOUNT_AMOUNT*QUANTITY AS discount_total,
(ITEM_PRICE-DISCOUNT_AMOUNT)*QUANTITY AS item_total FROM dual) s
WHERE s.item_total > 500
ORDER BY s.item_total;

You cannot use the column name which is used as alias one in the query
Reason:
The query will first checks for runtime at that time the column name "item_total" is not found in the table "ORDER_ITEMS" because it was give as alias which is not stored in anywhere and you are assigning that column in desired output only
Alternate:
If you want to use that type go with sub queries it's performance is not good but it is one of the alternate way
SELECT * FROM
(SELECT
ITEM_ID, ITEM_PRICE, DISCOUNT_AMOUNT, QUANTITY,
(ITEM_PRICE*QUANTITY) AS price_total,
(DISCOUNT_AMOUNT*QUANTITY) AS discount_total,
((ITEM_PRICE-DISCOUNT_AMOUNT)*QUANTITY) AS item_total
FROM ORDER_ITEMS) as tbl
WHERE tbl.item_total > 500
ORDER BY tbl.item_total;

Related

sql Group by does not work on selecting multiple columns

I have following query
SELECT ACTIONFINANCIALTRANSACTIONLOG.ID_CSE,
ACTIONFINANCIALTRANSACTIONLOG.DTE_PROC
FROM CSESDEV02.FINANCIAL_TRAN_LOG ACTIONFINANCIALTRANSACTIONLOG
GROUP BY ACTIONFINANCIALTRANSACTIONLOG.ID_CSE
HAVING COUNT(TXT_DESC) > 9
this results in
ORA-00979: not a GROUP BY expression
00979. 00000 - "not a GROUP BY expression"
*Cause:
*Action: Error at Line: 57 Column: 47
however, if i select only 1 column , it works
SELECT ACTIONFINANCIALTRANSACTIONLOG.ID_CSE
FROM CSESDEV02.FINANCIAL_TRAN_LOG ACTIONFINANCIALTRANSACTIONLOG
GROUP BY ACTIONFINANCIALTRANSACTIONLOG.ID_CSE
HAVING COUNT(TXT_DESC) > 9
why is that?
Although there's no aggregate function in SELECT column list, all columns that aren't aggregated should be part of the group by clause.
If there are 2 columns you're selecting, both have to be part of the group by.
BTW, table alias should be short so that it "simplifies" query and makes it easier to read. You did the opposite.
This is what works OK - only one column in select and it is part of group by:
SQL> select deptno
2 from emp
3 group by deptno
4 having count(job) > 1;
DEPTNO
----------
30
20
10
This doesn't work: two columns in select list, only one in group by:
SQL> select deptno,
2 ename
3 from emp
4 group by deptno
5 having count(job) > 1;
ename
*
ERROR at line 2:
ORA-00979: not a GROUP BY expression
But, when they both are in group by, query is OK:
SQL> select deptno,
2 ename
3 from emp
4 group by deptno, ename
5 having count(job) > 1;
no rows selected
SQL>
Read documentation.
Gist:
SelectItems in the SelectExpression with a GROUP BY clause must
contain only aggregates or grouping columns.
This is happening because GROUP by require all the column defined in SELECT clause.
The SELECT statement used in the GROUP BY clause can only be used contain column names, aggregate functions, constants and expressions.
select count(1),deptno
from emp
group by deptno
having count(1) > 1;
ACTIONFINANCIALTRANSACTIONLOG.DTE_PROC is not the product of a summary function and is not mentioned in the GROUP_BY clause so you get the error you've gotten. Perhaps you could use:
SELECT ftl.ID_CSE,
ftl.DTE_PROC
FROM (SELECT af.ID_CSE,
COUNT(af.TXT_DESC) AS TXT_DESC_COUNT
FROM CSESDEV02.FINANCIAL_TRAN_LOG af
GROUP BY af.ID_CSE
WHERE COUNT(af.TXT_DESC) > 9) iq
INNER JOIN CSESDEV02.FINANCIAL_TRAN_LOG ftl
ON ftl.ID_CSE = iq.ID_CSE
Syntax aside, think about the aggregation group you are defining with your group by clause:
GROUP BY ID_CSE
means you want one row per ID_CSE. Examples would be average salary per department, total sales per region, vaccinations per country.
In that one row for each id_cse, what dte_proc should be displayed if there is more than one distinct value?
For example, say your data contains
ID_CSE DTE_PROC
------ ----------
1 X
1 Y
2 Z
Now if you query
select id_cse, date_proc, count(*) from financial_tran_log
group by id_cse
what results do you expect to see?
ID_CSE DTE_PROC COUNT(*)
------ -------- --------
1 ??? 2
2 Z 1
It can't be done, hence the syntax error.

DB2 SQL Having Clause with a Nested Table Expression

Return the department number and the total payroll for the department that has the highest payroll. Payroll is the sum of all salaries and commissions of the department. Use a having clause with a nested table expression.
select e0.deptno,
(select sum(sal+com) FROM emp
group by deptno
having sum(sal+com) >= all(select sum(sal+com)
from emp
group by deptno) )as top
from emp as e0
group by e0.deptno
;
But my result is not correct. Im not so sure if my nested table expression combined with the having clause is done the right way. Can someone, try to help me? Thanks in advance.
As far as concerned, you don't need a having clause for this. You can just aggregate by department, order the results by payroll and fetch the first record:
select deptno, sum(sal + com) payroll
from emp e
group by deptno
order by payroll desc
fetch first 1 rows only
If you do want to use having (or if you are using a version of db2 that does not support the fetch ... rows ... clause), then we can build on your initial idea as follows:
select deptno, sum(sal + com) payroll
from emp
group by deptno
having sum(sal + com) >= all (
select sum(sal + com) from emp group by deptno
)

Get Unique column value along with other. Columns when using inner join

I have following query and I need unique value for column
Select unique(t.id), log.*
from tableA log
inner join tableT t on t.id1=log.id1
where log.time>=(somedate)
and log.time<(somedate)
and ref-id=20
and ref-id=30
and t.id not in (select unique t.id
from tableA log
inner join tableT t on t.id1=log.id1
where log.time>=(somedate)
and log.time<(somedate)
and ref-id=20
and ref-id=30);
I am not getting unique values for t.id.Can anyone please help ? I am using oracle data base
Remove LOG.* from the SELECT; UNIQUE (as well as DISTINCT) is applied to all columns you select, not only to the one you put into brackets.
[EDIT]
Scott's EMP table contains employees that work in different departments. List of distinct departments is:
SQL> select distinct deptno from emp;
DEPTNO
----------
30
20
10
SQL>
If you include additional columns, such as JOB, the list is changed to
SQL> select distinct deptno, job from emp order by deptno, job;
DEPTNO JOB
---------- ---------
10 CLERK
10 MANAGER
10 PRESIDENT
20 ANALYST
20 CLERK
20 MANAGER
30 CLERK
30 MANAGER
30 SALESMAN
9 rows selected.
SQL>
It is now distinct per DEPTNO and per JOB; you can't get only distinct DEPTNO in such a query.
[EDIT #2: aggregation]
If "distinct" means distinct DEPTNO and the first job for that DEPTNO, then you might need this:
SQL> select deptno, min(job) first_job from emp
2 group by deptno
3 order by deptno;
DEPTNO FIRST_JOB
---------- ---------
10 CLERK
20 ANALYST
30 CLERK
SQL>
[EDIT #3, example based on your query]
Select t.id,
min(log.id) log_id,
min(log.time) log_time,
<the rest of LOG table columns goes here, all of them with MIN>
from tableA log
inner join table ...
<the rest of your query goes here>
group by t.id;
How about something like this?
Select t.id, log.*
from tableA log inner join
(select t.*, row_number() over (partition by id1 order by id) as seqnum
from tableT t
) t
on t.id1 = log.id1
where log.time >= (somedate) and
log.time < (somedate) and
t.seqnum = 1
ref_id = 20 and ref_id = 30 -- this is ALWAYS false, but I'm ignoring that
Notes:
I have no idea what the subquery is supposed to be doing.
The conditions on ref_id will always evaluate to FALSE, so that logic is almost certainly not what you intend.
If ref_id is in the transaction table, then the conditions should be moved to the subquery.

How do I get rid of this extra grouping_id column when writing this query?

So I wrote this query but I need to get rid of the grouping_id column..I tried just leaving it out of the query statement but its having errors due to the having clause at the end which requires grouping_id...How do I fix this???
Output should look something like this after executed minus the group_id column:
SQL> SELECT DNAME, GENDER, GROUPING_ID(DNAME,GENDER) AS "Group_id", SUM(SALARY) FROM AZDEPARTMENT JOIN
AZCONSULTANT ON AZDEPARTMENT.DID=AZCONSULTANT.DID GROUP BY CUBE(DNAME,GENDER) HAVING GROUPING_ID(DN
AME,GENDER)>0;
DNAME G Group_ID SUM(SALARY)
---------------------------------------- - ---------- -----------
3 1059000
F 2 366500
M 2 692500
Risk and Compliance 1 264500
Finance and Accounting Excellence 1 395000
Internal Audit and Financial Controls 1 399500
6 rows selected.
You could do this using a subquery:
SELECT DNAME, GENDER, SUMSALARY
FROM (SELECT DNAME, GENDER, GROUPING_ID(DNAME,GENDER) AS "Group_id", SUM(SALARY) AS SUMSALARY
FROM AZDEPARTMENT JOIN
AZCONSULTANT
ON AZDEPARTMENT.DID=AZCONSULTANT.DID
GROUP BY CUBE(DNAME,GENDER)
HAVING GROUPING_ID(DNAME,GENDER) > 0
) T

Using the PIVOT clause

I need help creating a table using the pivot clause to include the average salary of each Division_ID and use Division_ID as a Row and Job_ID as Column using data in employees2 table.
Here is my query
SELECT *
FROM (
SELECT JOB_ID, DIVISION_ID, SALARY
FROM employees2
WHERE DIVISION_ID IN (1, 2, 3, 4, 5)
)
PIVOT (
AVG(SALARY) FOR JOB_ID IN (1 AS ENG, 2 AS MGR, 3 AS PRE, 4 AS WOR, 5 AS TEC)
)
ORDER BY DIVISION _ID;
I get the following error when I try to execute the statement
ORA-00933: SQL command not properly ended
00933. 00000 - "SQL command not properly ended"
*Cause:
*Action:
Error at Line: 6 Column: 3
Here is the data that is in employees2 table (note their are only 5 JOB_IDs)
Finally, here is an example of how my result should look like
Given your sample data, your query is checking for int division_ids and job_ids, when it appears those are varchar fields.
Here is a working version:
SELECT *
FROM (
SELECT JOB_ID, DIVISION_ID, SALARY
FROM employees2
WHERE DIVISION_ID IN ('div1','div2')
)
PIVOT (
AVG(SALARY) FOR JOB_ID IN ('job1', 'job2')
)
ORDER BY 1
SQL Fiddle Demo