Increment Variable/Counter in PL/SQL Select result - oracle

A rather silly question. I have a Oracle Db with Products and now read out the first 10 Products.
I now want the following display
1 Product A
2 Product XY
3 Product B
Stupid questions, but how to get the counter in front? I obviously have to increment, but I don't understand how that works. I also thought to work with WITH and tmp table, but can not figure out how that needs to be set up.
SELECT POS ???, PRODUCTNAME FROM TBLPRODUCT
I am not very familiar with PL/SQL. Can someone give me a hint? Thanks so much.

ROWNUM is one approach as shown by Bob, but if you are using more complicated queries -- especially if you are ordering the rows explicitly -- it may not give the results you want.
Nowadays, analytic functions are generally a better approach as you have explicit control over the ordering:
SELECT ROW_NUMBER() OVER (ORDER BY productname), productname
FROM tableproduct
ORDER BY productname
Note that the ordering of the rows which determines the row numbers is separate from the ordering of the overall result set. In this example I've used the same ordering as that's what you're likely to want, but it's worth noting that this gives you more flexibility.
(And apologies for being a little pedantic, but this has nothing to do with PL/SQL, which is the procedural language embedded in Oracle. This is simply about Oracle's implementation of SQL.)

Use ROWNUM, as in
SELECT ROWNUM, PRODUCTNAME FROM TBLPRODUCT
Share and enjoy.

Related

Combining 2 tables with the number of users on a different table ORACLE SQl

Is this considered good practice?
Been trying to merge data from 2 different tables (dsb_nb_users_option & dsb_nb_default_options) for the number of users existing on dsb_nb_users table.
Would a JOIN statement be the best option?
Or a sub-query would work better for me to access the data laying on dsb_nb_users table?
This might be an operation i will have to perform a few times so i want to understand the mechanics of it.
INSERT INTO dsb_nb_users_option(dsb_nb_users_option.code, dsb_nb_users_option.code_value, dsb_nb_users_option.status)
SELECT dsb_nb_default_option.code, dsb_nb_default_option.code_value, dsb_nb_default_option.status
FROM dsb_nb_default_options
WHERE dsb_nb_users.user_id IS NOT NULL;
Thank you for your time!!
On the face of it, I see nothing wrong with your query to achieve your goal. That said, I see several things worth pointing out.
First, please learn to format your code - for your own sanity as well as that of others who have to read it. At the very least, put each column name on a line of its own, indented. A good IDE tool like SQL Developer will do this for you. Like this:
INSERT INTO dsb_nb_users_option (
dsb_nb_users_option.code,
dsb_nb_users_option.code_value,
dsb_nb_users_option.status
)
SELECT
dsb_nb_default_option.code,
dsb_nb_default_option.code_value,
dsb_nb_default_option.status
FROM
dsb_nb_default_options
WHERE
dsb_nb_users.user_id IS NOT NULL;
Now that I've made your code more easily readable, a couple of other things jump out at me. First, it is not necessary to prefix every column name with the table name. So your code gets even easier to read.
INSERT INTO dsb_nb_users_option (
code,
code_value,
status
)
SELECT
code,
code_value,
status
FROM
dsb_nb_default_options
WHERE
dsb_nb_users.user_id IS NOT NULL;
Note that there are times you need to qualify a column name, either because oracle requires it to avoid ambiguity to the parser, or because the developer needs it to avoid ambiguity to himself and those that follow. In this case we usually use table name aliasing to shorten the code.
select a.userid,
a.username,
b.user_mobile_phone
from users a,
join user_telephones b on a.userid=b.userid;
Finally, and more critical your your overall design, It appears that you are unnecessarily duplicating data across multiple tables. This goes against all the rules of data design. Have you read up on 'data normalization'? It's the foundation of relational database theory.

Oracle - select statement alias one column and wildcard to get all remaining columns

New to SQL. Pardon me if this question is a basic one. Is there a way for me to do this below
SELECT COLUMN1 as CUSTOM_NAME, <wildcard for remaining columns as is> from TABLE;
I only want COLUMN1 appear once in the final result
There is no way to make that kind of dynamic SELECT list with regular SQL*.
This is a good thing. Programming gets more difficult the more dynamic it is. Even the simple * syntax, while useful in many contexts, causes problems in production code. The Oracle SQL grammar is already more complicated than most traditional programming languages, adding a little meta language to describe what the queries return could be a nightmare.
*Well, you could create something using Oracle data cartridge, or DBMS_XMLGEN, or a trick with the PIVOT clause. But each of those solutions would be incredibly complicated and certainly not as simple as just typing the columns.
This is about as close as you will get.
It is very handy for putting the important columns up front,
while being able to scroll to the others if needed. COLUMN1 will end up being there twice.
SELECT COLUMN1 as CUSTOM_NAME,
aliasName.*
FROM TABLE aliasName;
In case you have many columns it might be worth to generate a full column list automatically instead of relying on the * selector.
So a two step approach would be to generate the column list with custom first N columns and unspecified order of the other columns, then use this generated list in your actual select statement.
-- select comma separated column names from table with the first columns being in specified order
select
LISTAGG(column_name, ', ') WITHIN GROUP (
ORDER BY decode(column_name,
'FIRST_COLUMN_NAME', 1,
'SECOND_COLUMN_NAME', 2) asc) "Columns"
from user_tab_columns
where table_name = 'TABLE_NAME';
Replace TABLE_NAME, FIRST_COLUMN_NAME and SECOND_COLUMN_NAME by your actual names, adjust the list of explicit columns as needed.
Then execute the query and use the result, which should look like
FIRST_COLUMN_NAME, SECOND_COLUMN_NAME, OTHER_COLUMN_NAMES
Ofcourse this is overhead for 5-ish columns, but if you ever run into a company database with 3 digit number of columns, this can be interesting.

AM I on the right path

I'm taking a database intro master's class. We are working on SQL. The professor likes to be ambiguous with certain explains.
Here's my question. Certain questions we are required to find out the opposite of a query something like if a supplier ships parts that are red and blue what colors don't the ship.
here is how I figured out a solution
SELECT distinct PARTS.COLOR
FROM PARTS, SHIPMENTS
WHERE PARTS.COLOR NOT IN(
SELECT distinct PARTS.COLOR
FROM SHIPMENTS, PARTS
WHERE PARTS.PARTNO IN(
SELECT distinct SHIPMENTS.PARTNO
FROM SHIPMENTS
WHERE SHIPMENTS.SUPPLIERNO='S1'))
AND SHIPMENTS.PARTNO = PARTS.PARTNO;
What I was wondering is, is this best approach to this question. This works but I'm not sure it is how it should be done.
I should also mention he does not want us to use all available operations. He did not show us JOIN, EXISTS,
he showed us SELECT, IN, ALL/ANY, Aggregates so MAX, MIN, SUM, GROUP BY, and HAVING
Thanks
If you learn now to use "EXPLAIN PLAN" to view the query plan, you'll find that Oracle often uses the same execution plan for "WHERE .. IN()" and "WHERE EXISTS". Depending on if there are indexes on the columns, it comes down to several aspects, mainly if you are using statistics gathering, Oracle will look at the number of rows for each table / index and decide which is the best way to execute it. So unless you find that IN() vs EXISTS() runs drastically differently than each other, just use whichever one makes most sense to you at the time, but always check the execution plan.
As far as your question, since you are prohibited from using joins or exists, I see nothing wrong with your solution.
The easy options I can come up with to simplify either use a join or an exists. You could do it with group and outer join, probably, but I see no point.
Without the restrictions, I could simplify it down to:
SELECT distinct P.COLOR
FROM PARTS P WHERE NOT EXISTS
(SELECT 1 FROM SHIPMENTS S WHERE S.PARTNO = P.PARTNO AND S.SUPPLIERNO = 'S1')
though I am not certain about your schema, and where color is. I assumed a part has a distinct color. If not, this is not adequate and you'd need to correlate the subquery on color, not partno.
Your question is: "if a supplier ships parts that are red and blue what colors don't they ship."
Interesting question. I think the easiest method uses analytic functions, which you probably haven't covered:
select sp.supplierno, color, count(*)
from (select s.*, p.color
max(case when p.color = 'red' then 1 else 0 end) over (partition by partno) as HasRed,
max(case when p.color = 'blue' then 1 else 0 end) over (partition by partno) as HasBlue
from shipments s join
parts p
on s.partno = p.partno
) sp
where hasRed > 0 and hasBlue > 0
group by sp.supplierno, color;

SELECT * FROM TABLE(pipelined function): can I be sure of the order of the rows in the result?

In the following example, will I always get “1, 2”, or is it possible to get “2, 1” and can you tell me where in the documentation you see that guarantee if it exists?
If the answer is yes, it means that without ORDER BY nor ORDER SIBLINGS there is a way to be sure of the result set order in a SELECT statement.
CREATE TYPE temp_row IS OBJECT(x number);
/
CREATE TYPE temp_table IS TABLE OF temp_row;
/
CREATE FUNCTION temp_func
RETURN temp_table PIPELINED
IS
BEGIN
PIPE ROW(temp_row(1));
PIPE ROW(temp_row(2));
END;
/
SELECT * FROM table(temp_func());
Thank you.
I don't think that there's anywhere in the documentation that guarantees the order that data will be returned in.
There's an old Tom Kyte thread from 2003 (so might be out of date) which states that relying on the implicit order would not be advisable, for the same reasons as you would not rely on the order in ordinary SQL.
1st: is the order of rows returned from the table function within a
SQL statement the exact same order in which the entries were "piped"
into the internal collection (so that no order by clause is needed)?
...
Followup May 18, 2003 - 10am UTC:
1) maybe, maybe not, I would not count on it. You should not count
on the order of rows in a result set without having an order by. If
you join or do something more complex then simply "select * from
table( f(x) )", the rows could well come back in some other order.
empirically -- they appear to come back as they are piped. I do not
believe it is documented that this is so.
In fact, collections of type NESTED TABLE are documented to explicitly
not have the ability to preserve order.
To be safe, you should do as you always would in a query, state an explicit ORDER BY, if you want the query results ordered.
Having said that I've taken your function and run 10 million iterations, to check whether the implicit order was ever broken; it wasn't.
SQL> begin
2 for i in 1 .. 10000000 loop
3 for j in ( SELECT a.*, rownum as rnum FROM table(temp_func()) a ) loop
4
5 if j.x <> j.rnum then
6 raise_application_error(-20000,'It broke');
7 end if;
8 end loop;
9 end loop;
10 end;
11 /
PL/SQL procedure successfully completed.
This procedural logic works differently to table-based queries. The reason that you cannot rely on orders in a select from a table is that you cannot rely on the order in which the RDBMS will identify rows as part of the required set. This is partly because of execution plans changing, and partly because there are very few situations in which the physical order of rows in a table is predictable.
However here you are selecting from a function that does guarantee the order in which the rows are emitted from the function. In the absence of joins, aggregations, or just about anything else (ie. for a straight "select ... from table(function)") I would be pretty certain that the row order is deterministic.
That advice does not apply where there is a table involved unless there is an explicit order-by, so if you load your pl/sql collection from a query that does not use an order-by then of course the order of rows in the collection is not deterministic.
The AskTom link in accepted answer is broken at this time but I found newer yet very similar question. After some "misunderstanding ping-pong", Connor McDonald finally admits the ordering is stable under certain conditions involving parallelism and ref cursors and related only to current releases. Citation:
Parallelism is the (potential) risk here.
As it currently stands, a pipelined function can be run in parallel only if it takes a ref cursor as input. There is of course no guarantee that this will not change in future.
So you could run on the assumption that in current releases you will get the rows back in order, but you could never 100% rely on it being the case now and forever more.
So no guarantee is given for future releases.
The function in question would pass this criterion hence it should provide stable ordering. However, I wouldn't personally trust it. My case (when I found this question) was even simpler: selecting from collection specified literally - select column_value from table(my_collection(5,3,7,2)) and I preferred explicit pairing between data and index anyway. It's not so hard and not much more longer.
Oracle should learn from Postgres where this situation is solved by unnest(array) with ordinality which is clearly understandable, trustworthy and well-documented feature.

How does Inline view differ from Inline table in oracle?

Could anyone tell the difference between Inline view and Inline table ?
Explanation with SQL code might be good to understand the concept easily.
"this question has been asked to me in an interview."
We hear this a lot. The problem with these type of questions is you're asking the wrong people: you should have have the courage to say to your interviewer, "I'm sorry, I'm not familiar with the term 'inline table' could you please explain it?"
Instead you ask us, and the thing is, we don't know what the interview had in mind. I agree with Alex that the nearest thing to 'inline table' is the TABLE() function for querying nested table collections, but it's not a standard term.
I have been on the opposite side of the interviewing table many times. I always give credit to a candidate who asked me to clarify a question; I always mark down a candidate who blusters.
The world is struggling to optimize the database query, so am I. Well if I say I have something which can speed the application by factors to 80%, if used at right situations, what will you say...
Here I give you a problem, suppose you want to calculate the lowest and highest salary across the department with the name of employees with their respective manager.
One way to do it is to create a temp table which contain the aggregated salary for the employees.
create table tmp_emp_sal as select t.emp_id,max(t.sal) as maxsal,min(t.sal) as minsal,avg(t.sal) as avgsal from sal t group by t.emp_id
and then use it in query further.
select concat(e.last_nm, e.first_nm) as employee_name,concat(m.last_nm,m.first_nm) as manager_name,tt.maxsal,tt.minsal,tt.avgsal from emp e,emp m,dept d,tmp_test tt where e.dept_id = d.dept_id and s.emp_id = tt.emp_id and e.mgr_id = m.emp_id order by employee_name, manager_name
Now I will optimize the above code by merging the two DML and DDL operations in to a single DML query.
select concat(e.last_nm, e.first_nm) as employee_name,concat(m.last_nm, m.first_nm) as manager_name,tt.maxsal,tt.minsal,tt.avgsal from emp e,emp m, dept d,(select t.emp_id, max(t.sal) as maxsal, min(t.sal) as minsal, avg(t.sal) as avgsal from sal t group by emp_id) tt where e.dept_id = d.dept_id and s.emp_id = tt.emp_id and e.mgr_id = m.emp_id order by employee_name,manager_name
The above query saves user from the following shortcomings :-
Eliminates expensive DDL statements.
Eliminates a round trip to the database server.
Memory usage is much lighter because it only stores the final result rather than the intermediate steps as well.
So its preferable to use inline views in place of temp tables.

Resources