Concatenate and use in where clause oracle plsql - sql

I have to concatenate two fields and use concatenated field in where clause but it gives me invalid identifier. How to solve this query.
select i.FIRST_NAME || ' - ' || i.LAST_NAME as NAME, i.* from CONTACT i
where NAME = 'JOHN - HANKS'
This gives me
ORA-00904: "NAME": invalid identifier
00904. 00000 - "%s: invalid identifier"

You cannot use a column alias at the same level. Just use a subquery (or repeat the expression):
select c.*
from (select i.FIRST_NAME || ' - ' || i.LAST_NAME as NAME, i.*
from CONTACT i
) c
where c.NAME = 'JOHN - HANKS';

The WITH clause is also a good alternative, better readability. Also, if the subquery is to be used multiple times, it is even better.
WITH data as(
select i.FIRST_NAME || ' - ' || i.LAST_NAME as NAME, i.* from CONTACT i)
select * from data where name = 'JOHN - HANKS';

select i.FIRST_NAME || ' - ' || i.LAST_NAME as NAME, i.* from CONTACT i
where i.first_name ||'~'||i.last_name = 'JHON~HANKS';

Related

How to sort when you are using UNION operator in Oracle SQL. I am using two select statements and UNION operator, I want to sort results of both query

I am trying to solve HackerRank SQL - The PADS question.
The Question is:
Generate the following two result sets:
Query an alphabetically ordered list of all names in OCCUPATIONS, immediately followed by the first letter of each profession as a parenthetical (i.e.: enclosed in parentheses). For example: AnActorName(A), ADoctorName(D), AProfessorName(P), and ASingerName(S).
Query the number of ocurrences of each occupation in OCCUPATIONS. Sort the occurrences in ascending order, and output them in the following format:
There are a total of [occupation_count] [occupation]s.
where [occupation_count] is the number of occurrences of an occupation in OCCUPATIONS and [occupation] is the lowercase occupation name. If more than one Occupation has the same [occupation_count], they should be ordered alphabetically.
My Solution is:
SELECT NAME || '(' || SUBSTR(OCCUPATION,1,1) || ')'
FROM OCCUPATIONS
ORDER BY NAME
UNION
SELECT 'There are a total of ' || COUNT(OCCUPATION) || ' ' || LOWER(OCCUPATION) || 's.'
FROM OCCUPATIONS
GROUP BY OCCUPATION
ORDER BY OCCUPATION;
OP:
ERROR at line 4:
ORA-00933: SQL command not properly ended
(It seems, we cannot use ORDER BY BEFORE UNION)
I revised my code to:
SELECT NAME || '(' || SUBSTR(OCCUPATION,1,1) || ')'
FROM OCCUPATIONS
UNION
SELECT 'There are a total of ' || COUNT(OCCUPATION) || ' ' || LOWER(OCCUPATION) || 's.'
FROM OCCUPATIONS
GROUP BY OCCUPATION
ORDER BY NAME, OCCUPATION;
OP:
ERROR at line 7:
ORA-00904: "NAME": invalid identifier
Please, help me out here.
Generate the following two result sets
You are NOT generating two result sets. You are performing two SELECTs and trying to merge them into a single result set using UNION and that is not what the question asks for. Stop using UNION and use two queries.
The first result set would be:
SELECT NAME || '(' || SUBSTR(OCCUPATION,1,1) || ')'
FROM OCCUPATIONS
ORDER BY NAME;
The second result set would be:
SELECT 'There are a total of ' || COUNT(OCCUPATION) || ' ' || LOWER(OCCUPATION) || 's.'
FROM OCCUPATIONS
GROUP BY OCCUPATION
and then you need to ORDER BY the number of occurrences AND then by the occupation name (which I leave to you to solve).
Since you're wanting to output two ordered sets of data in one query, the easiest way is to assign an identifier to each query and then order by that and the column you want to order by, e.g.:
SELECT info
FROM (SELECT 1 qry, NAME || '(' || SUBSTR(OCCUPATION,1,1) || ')' info
FROM OCCUPATIONS
UNION ALL
SELECT 2 qry, 'There are a total of ' || COUNT(OCCUPATION) || ' ' || LOWER(OCCUPATION) || 's.' info
FROM OCCUPATIONS
GROUP BY OCCUPATION)
ORDER BY qry, info;
Note that, because the two queries aren't going to return the same rows, I've used a UNION ALL, since a UNION does a DISTINCT on the resultant data set, whereas UNION ALL doesn't. Also, I'm assuming that if you had two different people with the same name and occupation (e.g. different birth dates), you should output both rows, rather than one row?
Note also that when you have a UNION/UNION ALL query, the output columns inherit the column name from the first query, which is why your second query was giving you the invalid identifier error (you hadn't given your column an alias!).
Please try here hope this help:
select name||'('||SUBSTR(OCCUPATION,1,1)||')' as col
from OCCUPATIONS
UNION ALL
select
'There are a total of '||count(occupation)||' '||LOWER(occupation)||'s.' as col
from OCCUPATIONS
group by occupation
order by col
;
If we need to tune up performance and we also know the 2 selection is not duplicate, just use UNION ALL .

Scalar function throws error while using in SQL

My question is:
Write a query to display user name and password. Password should be generated by concatenating first two characters of user name , length of the user name and last three numbers in the phone number and give an alias name as USER_PASSWORD. Sort the results based on the user name in descending order.
select
name,
concat(substring(name, 1, 2), cast(len(name) as varchar), cast(right(phno, 3) as varchar)) as USER_PASSWORD
from
users
order by
name desc;
I get this error:
cast(len(name) as varchar),
ERROR at line 5: ORA-00906: missing left parenthesis
Thanks
You have five issues:
CONCAT only takes two arguments so you either need CONCAT(a, CONCAT(b, c)) or use the || string concatenation operator a || b || c
CAST requires the data type and length CAST(a AS VARCHAR2(10))
SUBSTRING is not an Oracle function, you want SUBSTR;
LEN is not an Oracle function, you want LENGTH;
RIGHT is not an Oracle function, your want SUBSTR with a negative index.
SELECT name,
concat(
substr(name, 1, 2),
concat(
cast(length(name) as varchar2(10)),
cast(SUBSTR(phno, -3) as varchar2(10))
)
) as USER_PASSWORD
from users
order by name desc;
However, you do not need to explicitly use CAST as you can use an implicit conversion between data types:
SELECT name,
substr(name, 1, 2) || length(name) || SUBSTR(phno, -3) as USER_PASSWORD
from users
order by name desc;
Which, for the sample data:
CREATE TABLE users (name, phno) AS
SELECT 'Benny', '0123111' FROM DUAL UNION ALL
SELECT 'Betty', '4567111' FROM DUAL UNION ALL
SELECT 'Beryl', '2222111' FROM DUAL;
Both output:
NAME
USER_PASSWORD
Betty
Be5111
Beryl
Be5111
Benny
Be5111
fiddle
Which leads to the final point, don't generate obvious passwords; generate random or pseudo-random passwords. Then don't store them as plain text; instead store them as a salted-hash.
Concat() is limited to two arguments in Oracle. Use || instead.
with my_data as (
select 'abcdefg' as name, 12345 as phno from dual
)
select
name,
substr(name, 1, 2) ||
length(name) ||
substr(to_char(phno),-3) as user_password
from my_data
| NAME | USER_PASSWORD |
| --------|---------------|
| abcdefg | ab7345 |
fiddle

Adding " before distinct value in select

I have written the select to get the distinct table name (I have to use dba_tab_cols table because it's the only one with table names I have permission:
select distinct(table_name)||'"'||':' as SQL_TXT from dba_tab_cols where table_name = 'SAMPLE_TABLE'
I would like to add " before the table_name in this select, however when I write the following:
select '"'||distinct(table_name) I got the error:
**00936. 00000 - "missing expression"
*Cause:
*Action:**
I could not find similar topic, that is why I am sending this question.
The distinct is part of the select. So:
select distinct ('"' || table_name || '"' || ':') as SQL_TXT
from dba_tab_cols
where table_name = 'SAMPLE_TABLE';
select distinct is a "single" keyword that applies to all expressions in the select. It is not a function that applies to a single column.

Generate a list of rentals, with the client's information for the outlet with the most rentals

I have 4 tables : RentalAgreement (Rentals), Clients, vehicle and outlet.
I need to list rentalAgreementNumbers of THE outlet with the highest rentals with client info and outlet address.
Thanks!
So far, I am getting all 11 rows - that is, all agreements for all outlets
SELECT outlet.Street || ' ' || outlet.City || ', ' || outlet.state || ' - ' || outlet.zipcode AS "Outlet Street Address", rentalNo AS "ID", startDate AS "Start Date", returnDate AS "Return Date", clientName, client.Phone
FROM
client JOIN (ragreement JOIN (vehicle JOIN outlet USING (outNo)) USING (licenseNo)) USING (clientNo)
GROUP BY outlet.Street || ' ' || outlet.City || ', ' || outlet.state || ' - ' || outlet.zipcode, rentalNo, startDate, returnDate, clientName, client.Phone
HAVING COUNT(rentalNo) = (SELECT
MAX(COUNT(rentalNo))
FROM
ragreement
GROUP BY (rentalNo));
How can I modify this to get only 5 rental agreements listed for outlet1 - which has the highest rental agreements in my table?
After the select command, you can set a limit. Mssql syntaxt for this is
Select top(5) [columns] from....
You also need to add a order by clause at the end of the query
... Order by [columns or calculations]

I want to fetch data but there is some error like ORA-00904: "A.TRIP_ID": invalid identifier 00904. 00000 - "%s: invalid identifier"

I want to find 2nd minimum cat1_in_flag and cat2_in_flag but in this case i got this error can u please anyone suggest me how to solve that.
select trip_id,
(SELECT T1||' to '||T2 FROM(
SELECT cat1_in_flag T1,cat2_in_flag T2,
DENSE_RANK()OVER(ORDER BY min(to_number(cat1_in_flag)),min(to_number(cat2_in_flag))) RM
FROM TRIP_DTL
WHERE TRIP_ID = A.TRIP_ID
GROUP BY cat1_in_flag,cat2_in_flag
)WHERE RM=2)
from trip_mst A
ORA-00904: "A.TRIP_ID": invalid identifier
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
Error at Line: 17 Column: 20
You can try the following query to achieve the same result:
SELECT
TRIP_ID,
T1
|| ' to '
|| T2
FROM
(
SELECT
TRIP_ID,
CAT1_IN_FLAG T1,
CAT2_IN_FLAG T2,
ROW_NUMBER() OVER(
ORDER BY
TO_NUMBER(CAT1_IN_FLAG), TO_NUMBER(CAT2_IN_FLAG)
) RM
FROM
TRIP_MST A
JOIN TRIP_DTL B ON ( A.TRIP_ID = B.TRIP_ID )
)
WHERE
RM = 2
Cheers!!
----- Update -----
Updated the answer according to the situation mentioned in the comment.
Now, You can join TRIP_MST table with other tables:
SELECT
TRIP_ID,
T1
|| ' to '
|| T2
FROM
TRIP_MST A
JOIN (
SELECT
TRIP_ID,
CAT1_IN_FLAG T1,
CAT2_IN_FLAG T2,
ROW_NUMBER() OVER(
ORDER BY
TO_NUMBER(CAT1_IN_FLAG), TO_NUMBER(CAT2_IN_FLAG)
) RM
FROM
TRIP_DTL
) B ON ( A.TRIP_ID = B.TRIP_ID )
WHERE
B.RM = 2;
Cheers!!
The error is because the reference to a.trip_id is nested too deeply for your older Oracle version. It is equivalent to this:
select dummy
, ( select testcol
from ( select 123 as testcol from dual
where dummy = a.dummy )
) as testcol
from dual a;
This fails in Oracle 11.2 with
ORA-00904: "A"."DUMMY": invalid identifier
because the reference to A is two levels down and so it can't see it. It succeeds in dbfiddle if you change the version to a later one.
If it was clearer what data you had and what results you wanted to see it should be possible to suggest an alternative query for 11g.