SELECT ename
, job
, CASE deptno
WHEN 10
THEN 'ACCOUNTS'
WHEN 20
THEN 'SALES'
ELSE 'UNKNOWN'
END AS department
FROM emp /* !!! */
WHERE department = 'SALES'
This fails:
ORA-00904: "%s: invalid identifier"
Is there a way to overcome this limitation in Oracle 10.2 SQL ?
How to use the 'case expression column' in where clause ?
The reason for this error is that SQL SELECT statements are logically * processed in the following order:
FROM: selection of one table or many JOINed ones and all rows combinations that match the ON conditions.
WHERE: conditions are evaluated and rows that do not match are removed.
GROUP BY: rows are grouped (and every group collapses to one row)
HAVING: conditions are evaluated and rows that do not match are removed.
SELECT: list of columns is evaluated.
DISTINCT: duplicate rows are removed (if it's a SELECT DISTINCT statement)
UNION, EXCEPT, INTERSECT: the action of that operand is taken upon the rows of sub-SELECT statements. For example, if it's a UNION, all rows are gathered (and duplicates eliminated unless it's a UNION ALL) after all sub-SELECT statements are evaluated. Accordingly for the EXCEPT or INTERSECT cases.
ORDER BY: rows are ordered.
Therefore, you can't use in WHERE clause, something that hasn't been populated or calculated yet. See also this question: oracle-sql-clause-evaluation-order
* logically processed: Note that database engines may as well choose another order of evaluation for a query (and that's what they usually do!) The only restriction is that the results should be the same as if the above order was used.
Solution is to enclose the query in another one:
SELECT *
FROM
( SELECT ename
, job
, CASE deptno
WHEN 10 THEN 'ACCOUNTS'
WHEN 20 THEN 'SALES'
ELSE 'UNKNOWN'
END AS department
FROM emp
) tmp
WHERE department = 'SALES' ;
or to duplicate the calculation in the WHERE condition:
SELECT ename
, job
, CASE deptno
WHEN 10 THEN 'ACCOUNTS'
WHEN 20 THEN 'SALES'
ELSE 'UNKNOWN'
END AS department
FROM emp
WHERE
CASE deptno
WHEN 10 THEN 'ACCOUNTS'
WHEN 20 THEN 'SALES'
ELSE 'UNKNOWN'
END = 'SALES' ;
I guess this is a simplified version of your query or you could use:
SELECT ename
, job
, 'SALES' AS department
FROM emp
WHERE deptno = 20 ;
Your table does not contain a column "department" and thus you can not reference it in your where clause. Use deptno instead.
SELECT ename
, job
, CASE deptno
WHEN 10
THEN 'ACCOUNTS'
WHEN 20
THEN 'SALES'
ELSE 'UNKNOWN'
END AS department
FROM emp /* !!! */ where deptno = 20;
This work for me :
SELECT ename, job
FROM emp
WHERE CASE WHEN deptno = 10 THEN 'ACCOUNTS'
WHEN deptno = 20 THEN 'SALES'
ELSE 'UNKNOWN'
END
= 'SALES'
select emp_.*
from (SELECT ename
, job
, CASE deptno
WHEN 10
THEN 'ACCOUNTS'
WHEN 20
THEN 'SALES'
ELSE 'UNKNOWN'
END AS department
FROM emp /* !!! */ ) emp_ where emp_.department='UNKNOWN';
try:
SQL> SELECT ename
2 , job
3 , CASE
4 WHEN deptno = 10
5 THEN 'ACCOUNTS'
6 WHEN deptno = 20
7 THEN 'SALES'
12 ELSE 'UNKNOWN'
13 END AS department
14 FROM emp /* !!! */ where department = 'SALES';
Oracle tries to filter the number of records to be scanned from table by going for the where clause first before select that is why your query fails. Moreover, your query would have never returned rows with department - "Accounts or Unknown" because of the filter Department="SALES"
Try below instead, that will be easy to be fetched by Engine :
SELECT ename, job,'SALES' AS department
FROM emp
WHERE deptno = 20;
Related
My query looks like below with the foll. output
Current Output
Role Cases prepped % Completed
State Member 1 10 5 50%
State Member 2 10 7 70%
State President 10 2 20%
Summary 30 14 46.6%
Output Expected
Role Cases prepped % Completed
State President 10 2 20%
State Member 1 10 5 50%
State Member 2 10 7 70%
Summary 30 14 46%
Roles table
id name
30 State President
40 State Member
This is my query,
SELECT COALESCE(ROLE, 'Summary') ROLE,
count(*) AS cases,
SUM(CASE WHEN PREPARED = 'Y' THEN 1
ELSE 0
END) AS prepped,
round(avg(case when prepared = 'Y' then 100 else 0 end),2)||'%' as % Completed
FROM
(SELECT CASE
WHEN r.id = 30 THEN r.name
ELSE r.name || ' ' || u.case_member_id
END AS ROLE,
bi.prepared
FROM cases c
LEFT JOIN case_inventory ci ON ci.case_id = c.id
AND c.id = ci.case_id
AND c.delete_date IS NULL
AND ci.case_id =40
Left JOIN users u ON ci.assigned_to = u.id
Left JOIN ROLES r ON u.role_id = r.id
Left JOIN user_cases_map uc ON c.id = uc.case_id
AND uc.id = 1572919346)
GROUP BY ROLLUP (ROLE);
I now want to order the rows with respect to the role. The 1st record should be the State president and then followed by state memebr 1. state member 2. and so on. I tried to have an order by in the inner clause but it did not help. It doesnt have any effect. Adding in the outer select also doesnt change anything. Any help highly appreciated. Thank you.
You could do something like this. I don't have your input data, so I used SCOTT.EMP instead.
Notice a few things. I grouped by JOB, and I used GROUPING(JOB) both in SELECT (to add the label TOTAL for the summary row) and in ORDER BY. Since I reuse the column name JOB in SELECT (for the output column), in ORDER BY I must be careful to qualify the column name JOB (to make it clear I am referring to the input table column, not to the column in SELECT - which would be the default if column names in ORDER BY were not qualified). The need to qualify column names in ORDER BY, then, forced me to alias the table in the FROM clause (otherwise I would have had to carry the full table name everywhere).
Using the GROUPING function in SELECT (rather than NVL) is particularly important if JOB can be null. You don't want the group for null job to be labeled TOTAL - you only want that for the rollup row. This point confuses even a lot of very advanced programmers.
I show how you can "manually" decide the order: PRESIDENT first, then MANAGER, and then all other jobs (ordered alphabetically). If you have the order of priority saved somewhere, for example in a table, you can join to that table and use the ordering column instead of the "manual" CASE expression in my query.
select case grouping(job) when 0 then job else 'TOTAL' end as job
, sum(sal) as total_salary
from scott.emp e
group by rollup(job)
order by grouping(e.job) -- to get the total in the last row
, case e.job when 'PRESIDENT' then 1 when 'MANAGER' then 2 end
, e.job
;
JOB TOTAL_SALARY
--------- ------------
PRESIDENT 5000
MANAGER 8275
ANALYST 6000
CLERK 4150
SALESMAN 5600
TOTAL 29025
I have the following sql query that I m not able to process since this afternoon.
I have seen lot of threads about this issue but I m not getting it right, I believe that I m miss understanding this one topic that is shaming my day.
SELECT
cor.c_order_id, cor.totallines,cor.documentno,cbp.name
FROM
c_orderline col
LEFT JOIN c_order cor ON cor.c_order_id = col.c_order_id
LEFT join c_bpartner cbp on cbp.c_bpartner_id = cor.c_bpartner_id
WHERE
cor.issotrx = 'Y'
and cor.docstatus not in ('DR','IP')
AND cor.salesrep_id = 1037317
and col.qtyordered <> 0
and cor.dateordered between SYSDATE - 30 and SYSDATE + 30
AND col.c_orderline_id NOT IN (
SELECT
cil.c_orderline_id
FROM
c_invoiceline cil
WHERE
cil.c_orderline_id IS NOT NULL
)
group by cor.c_order_id, cor.documentno
order by cor.c_order_id, cor.documentno
What I m doing wrong ??
A simplified example, based on Scott's EMP table.
This is what you did:
SQL> select deptno, job
2 from emp
3 group by deptno;
select deptno, job
*
ERROR at line 1:
ORA-00979: not a GROUP BY expression
As you can see, Oracle marked the culprit - the JOB column.
Therefore, if you want to use a GROUP BY clause (which is correct, but - you'd get the same result using DISTINCT; these two should not be used together. GROUP BY is usually used with aggregates such as min, max, avg and such), then put all columns into the GROUP BY:
SQL> select deptno, job
2 from emp
3 group by deptno, job;
DEPTNO JOB
---------- ---------
20 CLERK
30 SALESMAN
20 MANAGER
30 CLERK
10 PRESIDENT
30 MANAGER
10 CLERK
10 MANAGER
20 ANALYST
9 rows selected.
Or, as I said - using DISTINCT:
SQL> select distinct deptno, job
2 from emp;
DEPTNO JOB
---------- ---------
20 CLERK
30 SALESMAN
20 MANAGER
30 CLERK
10 PRESIDENT
30 MANAGER
10 CLERK
10 MANAGER
20 ANALYST
9 rows selected.
SQL>
group by is used for aggregate functions like sum(), max(), min() etc. What value are you calculating in groups?
remove the group by and your query looks good besides that
To correct the error this query is producing you need to
group by cor.c_order_id, cor.totallines,cor.documentno,cbp.name
Group by all the columns that are in the select statement and are not part of aggregate function.
What else is a problem?
Here is the DEMO
In this demo you will see that the query works(with the correction I have suggested), but as I asked, what else is a problem to you. Do elaborate so we can help. Cheers!
I am facing difficulty in understanding oracle(12c) sql order by clause with case statement.
I have a table with the below data,
SELECT DEPT_NO, DEPT_NAME FROM SORTNG_LOGIC;
DEPT_NO DEPT_NAME
---------- --------------------
1 FINANCE
2 ACCOUNT
3 HUMAN RESOURCE
4 AUDIT
5 TRAINING
I am executing the below sql query for this table to add custom order, on oracle sql developer.
SELECT DEPT_NO, DEPT_NAME FROM SORTNG_LOGIC ORDER BY (
CASE DEPT_NAME
WHEN 'ACCOUNT' THEN '1'
WHEN 'AUDIT' THEN '2'
WHEN 'FINANCE' THEN '3'
ELSE '4' END
)DESC;
This is giving the below result :
DEPT_NO DEPT_NAME
---------- --------------------
3 HUMAN RESOURCE
5 TRAINING
1 FINANCE
4 AUDIT
2 ACCOUNT
But I expected that, the result should be
DEPT_NO DEPT_NAME
---------- --------------------
5 TRAINING
3 HUMAN RESOURCE
1 FINANCE
4 AUDIT
2 ACCOUNT
As I am sorting the dept_name in descending order, I thought'Training' should be above 'human resource'.
Where is my understanding going wrong? Could someone please explain this in detail?
If you want the department name in descending order, then you have to include that information in the query:
ORDER BY (CASE DEPT_NAME
WHEN 'ACCOUNT' THEN 1
WHEN 'AUDIT' THEN 2
WHEN 'FINANCE' THEN 3
ELSE 4
END) DESC,
DEPT_NAME DESC;
There is no reason for the value of the CASE to be a character string. The logic really calls for a number. If you use strings, then values larger than 9 will not work as you expect them to.
Try this with decode function, basically does the same thing.
SELECT DEPT_NO, DEPT_NAME
FROM SORTNG_LOGIC
ORDER BY
decode (DEPT_NAME,'ACCOUNT','1','AUDIT','2','FINANCE','3','4') DESC;
Using Like operator, how to retrieve a name which is having exact 100 characters
note: I don't want to use 100 underscores _
ex:
select ename from emp where ename like '_____________';
it should not like above
is there any other way
For exactly 100 characters , do
select ename from emp where LEN(ename)=100
For greater than equal to 100 characters
select ename from emp where LEN(ename) >= 100
Many dbms products support the REPEAT function (not ANSI however...)
select ename from emp where ename like repeat('_',100)
Or use CHAR_LENGTH:
select ename from emp where CHAR_LENGTH(ename) = 100
I'm not quite sure what DBMS you using, this is should work under mysql :
select ename from emp where ename like concat('%', REPEAT('_',100),'%');
Above condition is where string have 100 UNDERSCORE whether in beginning, middle or end of string. For condition where string exactly have 100 UNDERSCORE :
select ename from emp where ename = REPEAT('_',100);
select ename from emp where LEN(ename)=100 and ename like '%_%';
LEN is used for length of value and % before and after character means any string which contains atleast one _
for more that ore equal to 100
select ename from emp where LEN(ename)>=100 and ename like '%_%';
You can use following:
WHERE column_name REGEXP [a-z0-9]{100}
I’m working on creating three variables in the my Universe. The variables are Applications, Operating System, and Physical Location. The problem I’m running into is that all three of these is pulled from the same table and all of them are within the Value.
So the Table BMC_CORE_BMC_BASERELATIONSHIP has the variable Name. I am trying to pull all of the destination instance id's for the operating system when name is equal to SYSTEMOS.
My first guest was to use derived tables having each of the three a separate table with the following coding
“Operating System Relationship” Derive Table
SELECT
BMC_CORE_BMC_BASERELATIONSHIP.DESTINATION_INSTANCEID
FROM
BMC_CORE_BMC_BASERELATIONSHIP
Where
BMC_CORE_BMC_BASERELATIONSHIP.Name = 'SYSTEMOS'
“Physical Location Relationship” Derive Table
SELECT
BMC_CORE_BMC_BASERELATIONSHIP.DESTINATION_INSTANCEID
FROM
BMC_CORE_BMC_BASERELATIONSHIP
Where
BMC_CORE_BMC_BASERELATIONSHIP.Name = 'ELEMENTLOCATION'
“Applications Relationship” Derive Table
SELECT
BMC_CORE_BMC_BASERELATIONSHIP.DESTINATION_INSTANCEID
FROM
BMC_CORE_BMC_BASERELATIONSHIP
Where
BMC_CORE_BMC_BASERELATIONSHIP.Name = 'APPLICATIONSYSTEMCOMPUTER'
However when I try pulling the variable in with the following syntax, only one of the variables will show up in Webi. The others are being nulled I figured out.
App Var
Case
WHEN CI_RELATED_CI.INSTANCEID ="Applications Relationship".DESTINATION_INSTANCEID
Then CI_RELATED_CI.NAME
END
Location Var
CASE
WHEN CI_RELATED_CI.INSTANCEID = "Physical Location Relationship".DESTINATION_INSTANCEID
THEN CI_RELATED_CI.NAME
END
OS Var
Case
WHEN CI_RELATED_CI.INSTANCEID ="Operating System Relationship".DESTINATION_INSTANCEID
Then CI_RELATED_CI.NAME
END
I was trying to think of a way to pull all of these into one derived table as separate variables, but so far I have been unsuccessful. Any thoughts or suggestions would be appreciated. I'm new so let me know if there is anything I can do to make my questions better.
you can use case like below or Decode,
select Case
WHEN BMC_CORE_BMC_BASERELATIONSHIP.Name = 'SYSTEMOS'
Then BMC_CORE_BMC_BASERELATIONSHIP.DESTINATION_INSTANCEID
WHEN BMC_CORE_BMC_BASERELATIONSHIP.Name = 'ELEMENTLOCATION'
Then BMC_CORE_BMC_BASERELATIONSHIP.DESTINATION_INSTANCEID
When BMC_CORE_BMC_BASERELATIONSHIP.Name = 'APPLICATIONSYSTEMCOMPUTER'
Then BMC_CORE_BMC_BASERELATIONSHIP.DESTINATION_INSTANCEID
Else 'Ur Comments'
END
from BMC_CORE_BMC_BASERELATIONSHIP;
or Decode
select Decode( BMC_CORE_BMC_BASERELATIONSHIP.Name,'SYSTEMOS',BMC_CORE_BMC_BASERELATIONSHIP.DESTINATION_INSTANCEID,'ELEMENTLOCATION',BMC_CORE_BMC_BASERELATIONSHIP.DESTINATION_INSTANCEID,'APPLICATIONSYSTEMCOMPUTER',BMC_CORE_BMC_BASERELATIONSHIP.DESTINATION_INSTANCEID,else) from BMC_CORE_BMC_BASERELATIONSHIP;
am able to get the out put
create table BMC_CORE_BMC_BASERELATIONSHIP (name1 varchar2(100),id number);
insert into BMC_CORE_BMC_BASERELATIONSHIP (name1,id) values('SYSTEMOS',1);
insert into BMC_CORE_BMC_BASERELATIONSHIP (name1,id) values('ELEMENTLOCATION',2);
insert into BMC_CORE_BMC_BASERELATIONSHIP (name1,id) values('APPLICATIONSYSTEMCOMPUTER',3);
select Case
WHEN Name1 = 'SYSTEMOS'
Then id
WHEN Name1 = 'ELEMENTLOCATION'
Then id
When Name1 = 'APPLICATIONSYSTEMCOMPUTER'
Then id
Else id
END
from BMC_CORE_BMC_BASERELATIONSHIP ;
o/p #
1
2
3
select Decode(Name1,'SYSTEMOS',id,'ELEMENTLOCATION',id,'APPLICATIONSYSTEMCOMPUTER',id,id)
from BMC_CORE_BMC_BASERELATIONSHIP;
o/p #
1
2
3
Not sure if I understand you correctly and this is what you want... This is Oracle example where each column has own name or label. You can create table as select - just add create table as before the select and your column names will be the label names:
SELECT ename, empno,
(CASE deptno WHEN 10 THEN 'Accounting' END) dept10
, (CASE deptno WHEN 20 THEN 'Research' END) dept20
, (CASE deptno WHEN 30 THEN 'Sales' END) dept30
, (CASE deptno WHEN 40 THEN 'Operations' END) dept40
FROM scott.emp
ORDER BY ename
/
ENAME EMPNO DEPT10 DEPT20 DEPT30 DEPT40
---------------------------------------------------------------------
ADAMS 7876 Research
ALLEN 7499 Sales
BLAKE 7698 Sales
CLARK 7782 Accounting
.....