Give priority to specific row while fetching via select - oracle

I have a table with following data
Code Dest
atp ananthapur
blr bangalore
chn chennai
del delhi
hmp himachal
hyd hyderbad
goa goa
I need a query to fetch data such that the rows for codes 'hyd' and 'blr' would remain on top always, and then rest of the rows will follow.
I have done this as below -
select code,dest from (
select 1 rown,a.* from LOCATION a
where a.code in ('hyd','blr')
union
select 2 rown,b.* from LOCATION b
where b.code not in ('hyd','blr')
)
order by rown
I can think of doing it in some other ways also. But my question is -
Is there any oracle defined feature to accomplish this?

Yes, Oracle has such a feature, it's the ORDER BY expressions-list clause.
Try:
SELECT * FROM LOCATION a
ORDER BY
CASE WHEN a.code in ('hyd','blr') THEN 1 ELSE 2 END

Related

Find ALL the supervisors (direct and indirect) of Bob?

Im learning about Oracle db and i have this question in my book :
here is the question
so the third note:
Find ALL the supervisors (direct and indirect) of Bob ??
the solution in book like this :
select distinct s.super_name,t.super_name from emp_super s * emp_super t where
s.super_name = t.person_name ;
can any one explain this to me ? i dont understand this solution ?
and any other solution for this ?
Note: my db is oracle .
That looks like a hierarchical query. Would this do?
SQL> with test (person, supervisor) as
2 (select 'bob', 'alice' from dual union all
3 select 'mary', 'susan' from dual union all
4 select 'alice', 'david' from dual union all
5 select 'david', 'mary' from dual
6 )
7 select sys_connect_by_path(supervisor, '->') sv
8 from test
9 start with person = 'bob'
10 connect by person = prior supervisor;
SV
---------------------------------------------------------------------
->alice
->alice->david
->alice->david->mary
->alice->david->mary->susan
SQL>
It starts with "Bob" (as you said that it should), and connects every person with their supervisor (i.e. specifies relationship between parent and child rows in the hierarchy). More about hierarchical queries here.
As of the "solution" you posted: well, it is invalid (instead of * there should have been a ,; but, then again, you'd rather use ANSI JOIN). When it is fixed, it just returns all rows except the first one in your table, so I'm not sure why they call it a "solution".
It joins the same table twice, so it is called a self-join.
I am supposing that you have the following table created with you.
We are going to use the concept of creating a cartesian product as it will contain all the possible combinations.
The tested code is given below:
select t.supervisor from empsuper as s, empsuper as t where s.supervisor=t.person;
The output to it will be:
This is the required output according to your question.
select distinct s.super_name,t.super_name from emp_super s *
emp_super t where
s.super_name = t.person_name ;
This solution will give only two levels of employees
Here when you use * in after from, (you should use a ',' actually), you are actually taking a Cartesian product of the two tables( Here Both tables are the same). Also, s and t represent the same tables. Suppose this is the table:
Cartesian Product of this table with itself:
Cartesian Product of this table with itself with the condition that s.supervisor=t.person:
Now, We can see how it gives us the direct and indirect employees.
select supervisor from emp_super where person='Bob'
UNION
select supervisor from emp_super where person in ( select supervisor from emp_super where person='Bob')
UNION
select supervisor from emp_super where person in (select supervisor from emp_super where person in ( select supervisor from emp_super where person='Bob')
)
UNION
select supervisor from emp_super where person in ( select supervisor from emp_super where person in (select supervisor from emp_super where person in ( select supervisor from emp_super where person='Bob')))

Removing duplicate columns in one row while merging corresponding column values

Apologies if this seems simple to some, I am still in the (very) early stages of learning!
Basically I've got a table database that has multiple users (Users_ID), each with a corresponding access name(NAME). The problem is, some Users have multiple access names, meaning when the data is pulled, there is duplicates in the User_ID column.
I need to remove the duplicates in the User column and join their corresponding access names in the NAME column, so it only takes up 1 row and no data is lost.
The current SQL query I'm using is :
select Table1_user_id, Table2.name,
from Table1
inner join Table2
on Table1.role_id = Table2.role_id
An example of what this would return:
USER_ID | NAME
------- --------------
Tim Level_1 Access
John Level 2 Access
Tim Level 2 Access
Mark Level 3 Access
Tim Level 3 Access
Ideally, I would remove the duplicates for Tim and display as following:
USER_ID | NAME
------- ----------------------------------------------
Tim Level_1 Access, Level 2 Access, Level 3 Access
John Level 2 Access
Mark Level 3 Access
Thanks in advance for any help regarding this and sorry if something similar has been asked before!
Use GROUP_CONCAT with SEPARATOR :
SELECT Table1.user_id, GROUP_CONCAT(Table2.name SEPARATOR ',') AS Ename
FROM Table1
INNER JOIN Table2 ON Table1.role_id = Table2.role_id
GROUP BY Table1.user_id
select Table1_user_id, LISTAGG(Table2.name,', ') WITHIN GROUP (ORDER BY Table2.name) as Name
from Table1
inner join Table2
on Table1.role_id = Table2.role_id

pl-sql include column names in query

A weird request maybe but. My boss wants me to create an admin version of a page we have that displays data from an oracle query in a table.
The admin page, instead of displaying the data (query returns 1 row), needs to return the table name and column name
Ex: Instead of:
Name Initial
==================
Bob A
I want:
Name Initial
============================
Users.FirstName Users.MiddleInitial
I realize I can do this in code but would rather just modify the query to return the data I want so I can leave the report generation code mostly alone.
I don't want to do it in a stored procedure.
So when I spit out the data in the report using something like:
blah blah = MyDataRow("FirstName")
I can leave that as is but instead of it displaying "BOB" it would display "Users.FirstName"
And I want to do the query using select * if possible instead of listing all the columns
So for each of the columns I am querying in the * , I want to get (instead of the column value) the tablename.ColumnName or tablename|columnName
hope you are following- I am confusing myself...
pseudo:
select tablename + '.' + Columnname as WhateverTheColumnNameIs
from Table1
left join Table2 on whatever...
Join Table_Names on blah blah
Whew- after writing all this I think I will just do it on the code side.
But if you are up for it maybe a fun challenge
Oracle does not provide an authentic way(there is no pseudocolumn) to get the column name of a table as a result of a query against that table. But you might consider these two approaches:
Extract column name from an xmltype, formed by passing cursor expression(your query) in the xmltable() function:
-- your table
with t1(first_name, middle_name) as(
select 1,2 from dual
), -- your query
t2 as(
select * -- col1 as "t1.col1"
--, col2 as "t1.col2"
--, col3 as "t1.col3"
from hr.t1
)
select *
from ( select q.object_value.getrootelement() as col_name
, rownum as rn
from xmltable('//*'
passing xmltype(cursor(select * from t2 where rownum = 1))
) q
where q.object_value.getrootelement() not in ('ROWSET', 'ROW')
)
pivot(
max(col_name) for rn in (1 as "name", 2 as "initial")
)
Result:
name initial
--------------- ---------------
FIRST_NAME MIDDLE_NAME
Note: In order for column names to be prefixed with table name, you need to list them
explicitly in the select list of a query and supply an alias, manually.
PL/SQL approach. Starting from Oracle 11g you could use dbms_sql() package and describe_columns() procedure specifically to get the name of columns in the cursor(your select).
This might be what you are looking for, try selecting from system views USER_TAB_COLS or ALL_TAB_COLS.

How to create select SQL statement that would produce "merged" dataset from two tables(Oracle DBMS)?

Here's my original question:
merging two data sets
Unfortunately I omitted some intircacies, that I'd like to elaborate here.
So I have two tables events_source_1 and events_source_2 tables. I have to produce the data set from those tables into resultant dataset (that I'd be able to insert into third table, but that's irrelevant).
events_source_1 contain historic event data and I have to do get the most recent event (for such I'm doing the following:
select event_type,b,c,max(event_date),null next_event_date
from events_source_1
group by event_type,b,c,event_date,null
events_source_2 contain the future event data and I have to do the following:
select event_type,b,c,null event_date, next_event_date
from events_source_2
where b>sysdate;
How to put outer join statement to fill the void (i.e. when same event_type,b,c found from event_source_2 then next_event_date will be filled with the first date found
GREATLY APPRECIATE FOR YOUR HELP IN ADVANCE.
Hope I got your question right. This should return the latest event_date of events_source_1 per event_type, b, c and add the lowest event_date of event_source_2.
Select es1.event_type, es1.b, es1.c,
Max(es1.event_date),
Min(es2.event_date) As next_event_date
From events_source_1 es1
Left Join events_source_2 es2 On ( es2.event_type = es1.event_type
And es2.b = es1.b
And es2.c = es1.c
)
Group By c1.event_type, c1.b, c1.c
You could just make the table where you need to select a max using a group by into a virtual table, and then do the full outer join as I provided in the answer to the prior question.
Add something like this to the top of the query:
with past_source as (
select event_type, b, c, max(event_date)
from event_source_1
group by event_type, b, c, event_date
)
Then you can use past_source as if it were an actual table, and continue your select right after the closing parens on the with clause shown.
I end up doing two step process: 1st step populates the data from event table 1, 2nd step MERGES the data between target (the dataset from 1st step) and another source. Please forgive me, but I had to obfuscate table name and omit some columns in the code below for legal reasons. Here's the SQL:
INSERT INTO EVENTS_TARGET (VEHICLE_ID,EVENT_TYPE_ID,CLIENT_ID,EVENT_DATE,CREATED_DATE)
select VEHICLE_ID, EVENT_TYPE_ID, DEALER_ID,
max(EVENT_INITIATED_DATE) EVENT_DATE, sysdate CREATED_DATE
FROM events_source_1
GROUP BY VEHICLE_ID, EVENT_TYPE_ID, DEALER_ID, sysdate;
Here's the second step:
MERGE INTO EVENTS_TARGET tgt
USING (
SELECT ee.VEHICLE_ID VEHICLE_ID, ee.POTENTIAL_EVENT_TYPE_ID POTENTIAL_EVENT_TYPE_ID, ee.CLIENT_ID CLIENT_ID,ee.POTENTIAL_EVENT_DATE POTENTIAL_EVENT_DATE FROM EVENTS_SOURCE_2 ee WHERE ee.POTENTIAL_EVENT_DATE>SYSDATE) src
ON (tgt.vehicle_id = src.VEHICLE_ID AND tgt.client_id=src.client_id AND tgt.EVENT_TYPE_ID=src.POTENTIAL_EVENT_TYPE_ID)
WHEN MATCHED THEN
UPDATE SET tgt.NEXT_EVENT_DATE=src.POTENTIAL_EVENT_DATE
WHEN NOT MATCHED THEN
insert (tgt.VEHICLE_ID,tgt.EVENT_TYPE_ID,tgt.CLIENT_ID,tgt.NEXT_EVENT_DATE,tgt.CREATED_DATE) VALUES (src.VEHICLE_ID, src.POTENTIAL_EVENT_TYPE_ID, src.CLIENT_ID, src.POTENTIAL_EVENT_DATE, SYSDATE)
;

PL SQL concatenate 2 resultsets

I need to get the result of concatenating 2 similar querys' resulsets. For some reason had to split the original query in 2, both with their corresponding order by clause. Should be something like (this is an oversimplification of the original queries)
Query1: Select name, age from person where age=10
Resultset1:
Person1, 10
Person3, 10
Query2: Select name, age from person where age=20
Resultset1:
Person2, 20
Person6, 20
The expected result:
Person1, 10
Person3, 10
Person2, 20
Person6, 20
I can not simply use Query1 UNION Query2.
Below the 2 original querys:
(#1)
select cp.CP_ID, cpi.CI_DESCRIPCION, cp.CP_CODIGOJERARQUIZADO, cp.CP_ESGASTO as gasto, cp.CP_CONCEPTOPADRE, LEVEL
from TGCCP_ConceptoPagoIng cp
left join tgcci_ConceptoPagoIngIdioma cpi on cpi.CI_IDCONCEPTOPAGOING = cp.CP_ID and cpi.CI_IDIDIOMA = 1
start with ((CP_CONCEPTOPADRE is null) and (**cp.CP_ESGASTO = 1**))
connect by prior cp.CP_ID = cp.CP_CONCEPTOPADRE
order siblings by CP_CODIGOJERARQUIZADO
(#2)
select cp.CP_ID, cpi.CI_DESCRIPCION, cp.CP_CODIGOJERARQUIZADO, cp.CP_ESGASTO as gasto, cp.CP_CONCEPTOPADRE, LEVEL
from TGCCP_ConceptoPagoIng cp
left join tgcci_ConceptoPagoIngIdioma cpi on cpi.CI_IDCONCEPTOPAGOING = cp.CP_ID and cpi.CI_IDIDIOMA = 1
start with ((CP_CONCEPTOPADRE is null) and (**cp.CP_ESGASTO = 2**))
connect by prior cp.CP_ID = cp.CP_CONCEPTOPADRE
order siblings by CP_CODIGOJERARQUIZADO
I think you want a
select * from ( first query )
UNION ALL
select * from ( second query )
Where first query and second query are the queries from above, so you are turning them into subqueries, thus preserving the order by clauses.
OK, well, I'm not fully certain why you need it this way, but if Oracle won't allow you to do a UNION, or it screws up the ordering when you do, I would try creating a pipelined table function.
An example here
Basically, you'd create a procedure that ran both queries, first one, then the other, putting the results of each into the returned dataset.
It looks like you are looking for a MULTISET UNION. Which can only be used from version 10 upwards.
Regards,
Rob.
You could combine your queries as subqueries and do a single order by on the outer query:
select * from (
<query 1 with its order by>
UNION ALL
<query 2 with its order by>
)
order by column1, column2;
Alternatively, you can implement in PL/SQL the equivalent of a sort merge join with two cursors, but that's unnecessarily complicated.
this solution works perfectly:
select * from ( first query )
UNION ALL
select * from ( second query )
I appreciate everyone that have taken the time to answer.
regards.
For your example:
Select name, age from person where age in (10,20)
or
Select name, age from person where age = 10 or age = 20
However I'm guessing this is not what you need :)

Resources