PLSQL: Query value and stick it in another query - oracle

I'm trying to select a value from a one row table and stick it in my bigger query like below:
select person.first_name,
(select active_year.year from active_year) as YEAR -- should be '2022'
from person where person.last_name = 'Smith'
The year select returns an error:
ORA-00907: missing right parenthesis
How can I return the year field?

Looks like you're misinterpreting reality, because that query won't return what you reported.
Sample data:
SQL> select * from person;
FIRST_NAME LAST_NAME
-------------------- --------------------
John Smith
SQL> select * from active_year;
YEAR
----------
2002
Your query, literally:
SQL> select person.first_name,
2 (select active_year.year from active_year) as YEAR -- should be '2022'
3 from person where person.last_name = 'Smith'
4 ;
FIRST_NAME YEAR
-------------------- ----------
John 2002
SQL>
Even if it were PL/SQL, it wouldn't work - but due to a different error:
SQL> begin
2 select person.first_name,
3 (select active_year.year from active_year) as YEAR -- should be '2022'
4 from person where person.last_name = 'Smith'
5 ;
6 end;
7 /
select person.first_name,
*
ERROR at line 2:
ORA-06550: line 2, column 1:
PLS-00428: an INTO clause is expected in this SELECT statement
SQL>
Therefore, it seems that you didn't post exactly what you did.

With sample data like this
WITH
person AS
(
Select 'John' "FIRST_NAME", 'Doe' "LAST_NAME" From Dual UNION ALL
Select 'John' "FIRST_NAME", 'Smith' "LAST_NAME" From Dual UNION ALL
Select 'Marry' "FIRST_NAME", 'Smith' "LAST_NAME" From Dual UNION ALL
Select 'Alice' "FIRST_NAME", 'Freeman' "LAST_NAME" From Dual UNION ALL
Select 'Mike' "FIRST_NAME", 'Freeman' "LAST_NAME" From Dual UNION ALL
Select 'Robert' "FIRST_NAME", 'Harris' "LAST_NAME" From Dual
),
active_year AS
(
Select 2022 "ACT_YEAR" From Dual
)
Your select works ok (tested on 11gR2)
SELECT
p.FIRST_NAME,
(Select ACT_YEAR From active_year) "YEAR"
FROM
person p
WHERE
p.LAST_NAME = 'Smith'
--
-- R e s u l t
--
-- FIRST_NAME YEAR
-- ---------- ----------
-- John 2022
-- Marry 2022
I don't know what is the problem,but there is another way to get the same result if active_year is a one row table.
Try to put it this way - as a joined table to your bigger query. It will work.
SELECT
p.FIRST_NAME "FIRST_NAME",
a.ACT_YEAR "YEAR"
FROM
person p
INNER JOIN
active_year a ON(1 = 1)
WHERE
p.LAST_NAME = 'Smith'
--
-- R e s u l t
--
-- FIRST_NAME YEAR
-- ---------- ----------
-- John 2022
-- Marry 2022
All the above is SQL and if you have this select in PL/SQL it will work as a CURSOR definition, but inside the block you will have to insert an INTO clause to store the values in variables and then do whatever you want to do. In that case you should be sure not to select more than one row because an error will be raised...
Declare
varName VarChar2(50);
varYear Number(4);
Begin
SELECT p.FIRST_NAME "FIRST_NAME", a.ACT_YEAR "YEAR"
INTO varName, varYear
FROM person p
INNER JOIN active_year a ON(1 = 1)
WHERE p.LAST_NAME = 'Harris';
End;

Related

Extract Data Between Brackets in Oracle SQL

I have a table with data in below format
COURSE
[]
["12345"]
["12345","7890"
I want to extract the data between [] but without "
So, my output would be in below format
COURSE
12345
12345, 7890
I tried the below code which works fine for first 3 rows
select REGEXP_SUBSTR (COURSE,
'"([^"]+)"',
1,
1,
NULL,
1) from TEST;
But 4th row only results in 12345.
Why not simple translate?
SQL> with test (course) as
2 (select '[]' from dual union
3 select null from dual union
4 select '["12345"]' from dual union
5 select '["12345","7890"]' from dual
6 )
7 select course,
8 translate(course, 'a[]"', 'a') result
9 from test;
COURSE RESULT
---------------- -----------------------------------------
["12345","7890"] 12345,7890
["12345"] 12345
[]
SQL>

combine multiple rows result in single row based on one column value

I i want to combine multiple rows result into single row based on one column called type.
Ex say suppose i have below result from my query .
seqnum type name
456 SH Google2
456 CN transwork
123 SH partyshipper
123 CN consignee
Actual result i want is something like below table
seqnum consigneename shippername
456 transwork Google2
123 consignee partyshipper
Basically i want to get result like consignee name when type is CN and shipper name is when type is SH if its not both then i can add extra column with name just like otherparty.
I can get result and iterate result set and set value of object. but i think this will be better if we get formatted result in query only.can some one help in in getting this.
Thanks for the help.
Something like this usually helps; lines #1 - 7 represent your sample data. Code you need begins at line #8.
SQL> with test (seqnum, type, name) as
2 (select 456, 'SH', 'Google2' from dual union all
3 select 456, 'CN', 'transwork' from dual union all
4 select 123, 'SH', 'partyshipper' from dual union all
5 select 123, 'CN', 'consignee' from dual union all
6 select 999, 'XX', 'littlefoot' from dual
7 )
8 select seqnum,
9 max(case when type = 'CN' then name end) consigneename,
10 max(case when type = 'SH' then name end) shipppername,
11 max(case when type not in ('CN', 'SH') then name end) otherparty
12 from test
13 group by seqnum;
SEQNUM CONSIGNEENAM SHIPPPERNAME OTHERPARTY
---------- ------------ ------------ ------------
123 consignee partyshipper
999 littlefoot
456 transwork Google2
SQL>
Borrowing the query from #Littlefoot. You may also use PIVOT for this getting the expected result.
with test (seqnum, type, name) as
(select 456, 'SH', 'Google2' from dual union all
select 456, 'CN', 'transwork' from dual union all
select 123, 'SH', 'partyshipper' from dual union all
select 123, 'CN', 'consignee' from dual union all
select 999, 'OT', 'littlefoot' from dual
)
select * from test
pivot (
min(name) for type in
(
'SH' shippingname
, 'CN' consigneename
, 'OT' someother
)
)
;
SEQNUM SHIPPINGNAME CONSIGNEENAM SOMEOTHER
---------- ------------ ------------ ------------
999 littlefoot
456 Google2 transwork
123 partyshipper consignee
I'd self join the table and filter different types in each side of the join:
SELECT COALESCE(c.seqnum, s.seqnum) AS seqnum,
COALESCE(c.name, 'other') AS consigneename,
COALESCE(s.name, 'other') AS shippername
FROM (SELECT *
FROM mytable
WHERE type = 'CN') c
FULL OUTER JOIN (SELECT *
FROM mytable
WHERE type = 'SN') s ON c.seqnum = s.seqnum

Match characters in oracle sql where condition

I want to match Col1 from Table a to colum1 from table B.
A B
123 123-ab
234 234-bc
3443 3443-dd
However, value in table b has concatenated data. I want to match only the characters until before special character occurs(-).
I tried this : substr(table1.a,1,3) = substr(table2.b,1,3)
But this doesn’t work as some values have 4 digits.
use join and substr
select * from table_a
inner join table_b on table_a.col_a = substr(table_b.col_b, 1, length(table_a.col_a);
Using REGEXP_SUBSTR() to match on one or more numbers from the beginning of the string up to but not including the first hyphen:
SQL> with a(col1) as (
select '123' from dual union
select '234' from dual union
select '3443' from dual
),
b(col1) as (
select '123-ab' from dual union
select '234-bc' from dual union
select '3443-dd' from dual
)
select a.col1, b.col1
from a, b
where a.col1 = regexp_substr(b.col1, '^(\d+)-', 1, 1, NULL, 1);
COL1 COL1
---- -------
123 123-ab
234 234-bc
3443 3443-dd
SQL>

column A has 3 same values and need to check column B values for the same column A

For example, I have column A Department and column B as employee type, I need to check the following.
Department Emp Type
Dep1 S
Dep1 H
Dep1 P
Dep2 H
Dep2 H
Dep2 H
I need to retrieve the departments only with H employee type for all the 3 rows. If the emp types are different I need to ignore that department.
you can use a group by with having to filter out the ones with only H:
SQL> create table dept(dep varchar2(5), typ varchar2(1));
Table created.
SQL> insert into dept
2 select 'Dep1', 'S' from dual union all
3 select 'Dep1', 'H' from dual union all
4 select 'Dep1', 'P' from dual union all
5 select 'Dep2', 'H' from dual union all
6 select 'Dep2', 'H' from dual union all
7 select 'Dep2', 'H' from dual;
6 rows created.
SQL> select dep
2 from dept
3 group by dep
4 having count(distinct typ) = 1
5 and max(typ) = 'H';
DEP
-----
Dep2
SELECT DISTINCT Department
FROM tableX t
WHERE NOT EXISTS
( SELECT *
FROM tableX s
WHERE s.Department = t.Department
AND s.EmpType <> 'H'
) ;
If you have an index on (Department, EmpType), the fastest way is probably:
SELECT Department
FROM tableX t
GROUP BY Department
HAVING MIN(EmpType) = 'H'
AND MAX(EmpType) = 'H' ;

Oracle sql retrive records based on maximum time

i have below data.
table A
id
1
2
3
table B
id name data1 data2 datetime
1 cash 12345.00 12/12/2012 11:10:12
1 quantity 222.12 14/12/2012 11:10:12
1 date 20/12/2012 12/12/2012 11:10:12
1 date 19/12/2012 13/12/2012 11:10:12
1 date 13/12/2012 14/12/2012 11:10:12
1 quantity 330.10 17/12/2012 11:10:12
I want to retrieve data in one row like below:
tableA.id tableB.cash tableB.date tableB.quantity
1 12345.00 13/12/2012 330.10
I want to retrieve based on max(datetime).
The data model appears to be insane-- it makes no sense to join an ORDER_ID to a CUSTOMER_ID. It makes no sense to store dates in a VARCHAR2 column. It makes no sense to have no relationship between a CUSTOMER and an ORDER. It makes no sense to have two rows in the ORDER table with the same ORDER_ID. ORDER is also a reserved word so you cannot use that as a table name. My best guess is that you want something like
select *
from customer c
join (select order_id,
rank() over (partition by order_id
order by to_date( order_time, 'YYYYMMDD HH24:MI:SS' ) desc ) rnk
from order) o on (c.customer_id=o.order_id)
where o.rnk = 1
If that is not what you want, please (as I asked a few times in the comments) post the expected output.
These are the results I get with my query and your sample data (fixing the name of the ORDER table so that it is actually valid)
SQL> ed
Wrote file afiedt.buf
1 with orders as (
2 select 1 order_id, 'iphone' order_name, '20121201 12:20:23' order_time from dual union all
3 select 1, 'iphone', '20121201 12:22:23' from dual union all
4 select 2, 'nokia', '20110101 13:20:20' from dual ),
5 customer as (
6 select 1 customer_id, 'paul' customer_name from dual union all
7 select 2, 'stuart' from dual union all
8 select 3, 'mike' from dual
9 )
10 select *
11 from customer c
12 join (select order_id,
13 rank() over (partition by order_id
14 order by to_date( order_time, 'YYYYMMDD HH24:MI:SS' ) desc ) rnk
15 from orders) o on (c.customer_id=o.order_id)
16* where o.rnk = 1
SQL> /
CUSTOMER_ID CUSTOM ORDER_ID RNK
----------- ------ ---------- ----------
1 paul 1 1
2 stuart 2 1
Try something like
SELECT *
FROM CUSTOMER c
INNER JOIN ORDER o
ON (o.CUSTOMER_ID = c.CUSTOMER_ID)
WHERE TO_DATE(o.ORDER_TIME, 'YYYYMMDD HH24:MI:SS') =
(SELECT MAX(TO_DATE(o.ORDER_TIME, 'YYYYMMDD HH24:MI:SS')) FROM ORDER)
Share and enjoy.

Resources