I am working on the following query in which
Select name from (Select 'Mana' as name from table1
union
Select 'Tom' as name from dual)A
order by case
when name = 'TOM' then '1'
else name
end ;
which is giving the output
Mana
Tom
and the result i want after the custom sorting is
Tom
Mana
Please don't answer for Order By desc as i have other values in the
column, i need custom sorting
thanks
You're comparing name with 'TOM', but the value you have in that column is 'Tom' - the case doesn't match.
Select name from (Select 'Mana' as name from dual
union
Select 'Tom' as name from dual)A
order by case
when name = 'Tom' then '1'
else name
end ;
NAME
----
Tom
Mana
You might prefer to add a flag to sort by, and then further sort by name:
Select name from (Select 'Mana' as name from dual
union
Select 'Tom' as name from dual)A
order by case when name = 'Tom' then 1 else 2 end,
name;
NAME
----
Tom
Mana
That also avoids any potential issues with character sets - you're assuming that the character '1' always sorted before 'T'. (Which may be true, but still...)
Is it what you need?
order by case
when name = 'TOM' then 1
else 2
end ;
In your order by clause you have a number and varchar as result of case this cause comparing them as varchar pleas use same type.
Select name from
(
Select 'Mana' as name from dual
union all
Select 'Tom' as name from dual
) A
order by
case
when upper(name) = 'TOM' then 1
else 2
end;
And please take care of upper/lower case sensitivity
You can do something like:
order by case
when upper(name) = 'TOM' then 1
else 2
end, name ;
This will keep TOM at top and rest sorted afterwards
Related
I am feeling stupid today but I have a query that I want to write but I am sensing that it might be out of my reach.
I will try to simplify the problem just for the sake of simplicity.
I have a table like this
[Table A]
ID | Class | Name
0 A Sarah
1 B Tom
2 C Bob
3 A Jen
4 A John
5 A Jack
6 B Name1
7 B Jack
8 B Bob
I need to get all the records (the actual records not grouped by) for all the people that share the same class, but with the following restrictions:
Only get me the records where Jen, Jack & John share the same class (only those 3 no others and no duplicates).
That means the records will come as sets of 3.
So in the above example I would get
3 A Jen
4 A John
5 A Jack
So far I've gotten:
SELECT Class, Name, COUNT(*)
FROM TableA
GROUP BY Class, Name
HAVING COUNT(*) = 3
But in addition to this not working correctly, I am unable to specify that the records must have the names Jen, Jack and John and nothing else.
EDIT:
I was able to do it using inner query but it is a bit slow..If anyone knows a more optimal way please let me know:
SELECT ....
FROM TableA t1
join TableA t2 on t1.class = t2.class
WHERE t1.name = 'Jen' AND t2.name = 'John'
AND t1.class IN(SELECT class FROM TableA t3 WHERE t3.name = 'Jack')))
I could probably have included t3 with the original query but I prefer this way for readability.
Not sure if this is the exact answer but the query I was looking for worked using this style and I tried to write the simple one using the same method for anyone stuck like I was.
If you're after the classes where your three people all shared the same class, even if there were other people attending, then you were pretty close with your query, except you were missing the WHERE clause to restrict the rows to the names that you were interested in.
Plus, seeing as you didn't want to collapse the rows ("the actual records, not grouped by"), then you're after an analytic COUNT, not an aggregate.
Therefore, what you're after would look something like:
WITH table_a AS (SELECT 0 ID, 'A' CLASS, 'Sarah' NAME FROM dual UNION ALL
SELECT 1 ID, 'B' CLASS, 'Tom' NAME FROM dual UNION ALL
SELECT 2 ID, 'C' CLASS, 'Bob' NAME FROM dual UNION ALL
SELECT 3 ID, 'A' CLASS, 'Jen' NAME FROM dual UNION ALL
SELECT 4 ID, 'A' CLASS, 'John' NAME FROM dual UNION ALL
SELECT 5 ID, 'A' CLASS, 'Jack' NAME FROM dual UNION ALL
SELECT 6 ID, 'B' CLASS, 'Name1' NAME FROM dual UNION ALL
SELECT 7 ID, 'B' CLASS, 'Jack' NAME FROM dual UNION ALL
SELECT 8 ID, 'B' CLASS, 'Bob' NAME FROM dual)
-- End of mimicking your table_a with data in it
-- See query below:
SELECT ID,
CLASS,
NAME
FROM (SELECT ID,
CLASS,
NAME,
COUNT(NAME) OVER (PARTITION BY CLASS) name_cnt
FROM table_a
WHERE NAME IN ('Jen', 'Jack', 'John'))
WHERE name_cnt = 3;
You'll note that analytic functions don't have an equivalent HAVING clause that aggregate functions do, which means that you have to do the filtering in an outer query. Hopefully you can see that my query is similar to yours, though?
I have a query in which I want to remove the MISS, MR type of things from the user_name
I tried with below query
SELECT 0 user_id, '--- Select ---' user_name
FROM DUAL
UNION
SELECT DISTINCT user_id, LTRIM (user_name) user_name
FROM xxcus.xxacl_pn_user_det_v
ORDER BY user_name
but still it is not working for me.
Here is the screenshot
If you have several possible prefixes you want to delete, you can use regexp_replace():
regexp_replace(user_name, '^(MISS|MS\.|MS|MRS\.|MRS|MR\.|MR)\s*', '') as user_name
^ anchors the search at the beginning of the string, (...|...|...) means match any of the choices in parentheses, and \s is a single space; \s* means zero or more consecutive spaces. All that is deleted from the beginning of each string. The dot . must be escaped with backspace (otherwise it stands for "any single character").
If you need case-insensitive matching, if you may also have Miss in addition to MISS, use the full syntax of regexp_replace.
Edit: one more thing... the alternatives are tried one by one, from left to right, and the first match is used. So MS\. should appear before MS, otherwise MS (without a dot) will match MS in MS. SMITH and this will leave the dot and the space at the beginning of the string. I had to correct that in the solution.
You can use REPLACE() function like
REPLACE(user_name,'MISS','') as user_name
if you have column struct like (mr|mrs|other)/space/username you can try this
with users(user_name) as
(select 'mr user name1' from dual union all
select 'miss username2 ' from dual union all
select 'other username 3' from dual )
select substr(user_name,instr(user_name,' ')+1) real_username from users
output
REAL_USERNAME
----------------
user name1
username2
username 3
it substr from first founded space symbol
in your query
SELECT 0 user_id, '--- Select ---' user_name
FROM DUAL
UNION
SELECT DISTINCT user_id, substr(user_name,instr(user_name,' ')+1) user_name
FROM xxcus.xxacl_pn_user_det_v
ORDER BY user_name
if you want --- Select--- start from top you can:
select user_id, user_name
from (
SELECT 0 user_id, '--- Select ---' user_name, 1 order_by
FROM DUAL
UNION
SELECT DISTINCT user_id, substr(user_name,instr(user_name,' ')+1) user_name, 2 order_by
FROM xxcus.xxacl_pn_user_det_v
)
ORDER BY order_by, user_name
H,
How to use Pattern Matching function in "group By" clause.
Below is the Data
emp_name transaction_id
John 1001
John= 1002
Peter 1003
I want to group by based on emp_name. Here 'John' and 'John=' both are same employee. I want to ignore if the employee name has '=' sign at the end of the column.
Expected Result:
Emp_name countt
John 2
Peter 1
replace works fine and is fast. But since you asked for pattern matching, here is an answer with a pattern:
SELECT regexp_replace(emp_name, '=$', ''), count(*) AS countt
FROM employees
GROUP BY regexp_replace(emp_name, '=$', '');
A simple case statement replacing only the right most = if one exists.
SELECT case when right(emp_name,1) = '=' then left(emp_Name,len(emp_name-1))
else emp_name end as EmpName, count(Transaction_ID) countt
FROM dataTable
GROUP BY case when right(emp_name,1) = '=' then left(emp_Name,len(emp_name-1))
else emp_name end
select
replace (emp_name, '=', '') as emp_name,
count (*) as countt
from employees
group by replace (emp_name, '=', '')
Edit, since you said the name can contain an =
select
case
when emp_name like '%='
then substr (emp_name, 1, length (emp_name) - 1)
else emp_name
end as emp_name,
count (1) as countt
from employees
group by
case
when emp_name like '%='
then substr (emp_name, 1, length (emp_name) - 1)
else emp_name
end
How to order by case insensitive ASC or DESC for P/L sql 11g. this p/l sql basic question but i can't find good answer in Google please tell how to sort the select result case insensitive
this what i tried
SELECT DISTINCT
asssss,
saas_acc
FROM DUAL
UNION SELECT '--ALL--','ALL' FROM DUAL
ORDER BY upper(asssss) ASC ;
that gave to me ORA-01785: ORDER BY item must be the number of a SELECT-list expression
The simplest option would be to sort by the upper- (or lower-) case column data
ORDER BY UPPER( column_name )
DISTINCT actually filtered the UNIQUE content in the result set, with whatever expressions given in the SELECT clause.
We cannot order it using a Different expression or column name. Please see the example here.
SQL> l
1 SELECT DISTINCT (col1),(col2)
2 FROM
3 ( SELECT 'Hello' col1,'World' col2 FROM DUAL
4 UNION ALL
5 SELECT 'HELLO','WORLD' FROM DUAL
6* )
SQL> /
COL1 COL2
----- -----
HELLO WORLD
Hello World
You can see that DISTINCT is CASE SENSITIVE here.(2 rows displayed)
So, let me Do a UPPER() on both columns.
SQL> l
1 SELECT DISTINCT UPPER (col1),UPPER(col2)
2 FROM
3 ( SELECT 'Hello' col1,'World' col2 FROM DUAL
4 UNION ALL
5 SELECT 'HELLO','WORLD' FROM DUAL
6* )
SQL> /
UPPER UPPER
----- -----
HELLO WORLD
Just 1 row is Displayed, ignoring the case.
Coming back to the actual problem. To order something on a DISTINCT Resultset, it has to be a part of DISTINCT clause's expression/column.
So, When you issue DISTINCT COL1,COl2, the order by may be by COL1 or COL2/.. it cannot be COL3 or even UPPER(COL1) because UPPER() makes a different expression conflicting the expression over DISTINCT.
Finally, Answer for your Question would be
if you want your ORDER to be case-insensitive, DISTINCT also has to the same way! As given below
SELECT DISTINCT
UPPER(asssss),
saas_acc
FROM DUAL
ORDER BY upper(asssss) ASC ;
OR if UNION has to be used, better do this, or same as above one.
SELECT * FROM
(
SELECT DISTINCT asssss as asssss,
saas_acc
FROM DUAL
UNION
SELECT '--ALL--','ALL' FROM DUAL
)
ORDER BY upper(asssss) ASC ;
Out of my own Experience, I had always felt, what ever expression/column is specified in the ORDER BY, it is implicitly taken to final SELECT as well. Ordering is just based on the column number(position) in the result actually . In this situation, DISTINCT COL1,COl2 is already there. When you give ORDER BY UPPER(COL1), it will be tried to append into the SELECT expression, which is NOT possible at all. So, Semantic check itself, would disqualify this query with an Error!
To sort case insensitive you need to set the NLS_COMP to ANSI
NLS_COMP=ANSI
Details: http://www.orafaq.com/node/999
You can use upper or lower functions.
order by upper(columnName)
Update1
Try removing order-by clause from your query which will give you correct error, which is ORA-00904: "SAAS_ACC": invalid identifier. So you can search on google for this error or ask another question on SO.
Also have a look at how to use order by in union.
I am trying to fetch phone numbers from my Oracle database table. The phone numbers may be separated with comma or "/". Now I need to split those entries which have a "/" or comma and fetch the first part.
Follow this approach,
with t as (
select 'Test 1' name from dual
union
select 'Test 2, extra 3' from dual
union
select 'Test 3/ extra 3' from dual
union
select ',extra 4' from dual
)
select
name,
regexp_instr(name, '[/,]') pos,
case
when regexp_instr(name, '[/,]') = 0 then name
else substr(name, 1, regexp_instr(name, '[/,]')-1)
end first_part
from
t
order by first_part
;
Lookup substr and instr functions or solve the puzzle using regexp.
I added a table test with one column phone_num. And added rows similar to your description.
select *
from test;
PHONE_NUM
------------------------------
0123456789
0123456789/1234
0123456789,1234
3 rows selected.
select
case
when instr(phone_num, '/') > 0 then substr(phone_num, 0, instr(phone_num, '/')-1)
when instr(phone_num, ',') > 0 then substr(phone_num, 0, instr(phone_num, ',')-1)
else phone_num
end phone_num
from test
PHONE_NUM
------------------------------
0123456789
0123456789
0123456789
3 rows selected.
This generally works. Although it will fail if you have rows with commas and slashes.