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;
Related
I am a junior in a sub-position to the company's DBA employee. (ORACLE, PL/SQL Developer IDE)
As part of my tasks, there is a need to sort a particular table by a certain value, then sort it again, and then sort it again, as in the following example:
SELECT *
FROM (SELECT *
FROM (SELECT * FROM CARS
ORDER BY BRAND)
ORDER BY COLOR)
ORDER BY YEAR)
While in my opinion, multi-values ORDER BY can be used, like the following:
SELECT * FROM CARS ORDER BY BRAND, COLOR, YEAR
Note that there is great importance to the runtime of the program in the current task, so even if the code is a little more complicated, but effective and takes less time, it is preferable.
Just for the record, the sort value at each step is created by ROW_NUMBER () OVER (PARTITION BY...
which relevant to each of the values. (e.g. ROW_NUMBER () OVER (PARTITION BY COLOR ORDER BY COLOR) AS C1, and then ORDER BY C1)
So which of the ways is preferable? We should expect to see similar results in both? Or is there another better option?
The code
SELECT *
FROM (SELECT *
FROM (SELECT * FROM CARS
ORDER BY BRAND)
ORDER BY COLOR)
ORDER BY YEAR)
is synonymous with
SELECT *
FROM CARS
ORDER BY YEAR
If you are seeing that the output looks to be sorted in a cascading fashion, ie, by year, brand, color etc then this is by pure good luck not by anything guaranteed by the SQL engine. The final ORDER BY is the only one that matters (in terms of sorting). [Some times you might see an embedded ORDER BY for reasons of doing pagination, but the final result only depends on the final ORDER BY]
So yes, changing the statement to
SELECT * FROM CARS
ORDER BY BRAND, COLOR, YEAR
is most probably what you want, because the former is not going the give the result you're after.
I'm having some difficulty with joining a view to another table. This is on an Oracle RAC system running 11.2
I'll try and give as much detail as possible without going into specific table structures as my company would not like that.
You all know how this works. "Hey, can you write some really ugly software to implement our crazy ideas?"
The idea of what they wanted me to do was to make a view where the end user wouldn't know if they were going after the new table or the old table so one of the tables is a parameter table that will return "ON" or "OFF" and is used in the case statements.
There are some not too difficult but nested case statements in the select clause
I have a view:
create view my_view as
select t1.a as a, t1.b as b, t1.c as c,
sum(case when t2.a = 'xx' then case when t3.a then ... ,
case when t2.a = 'xx' then case when t3.a then ... ,
from table1 t1
join table t2 on (t1.a = t2.a etc...)
full outer join t3 on (t1.a = t3.a etc...)
full outer join t4 on (t1.a = t4.a etc...)
group by t1.a, t1.b, t2.c, and all the ugly case statements...
Now, when I run the query
select * from my_view where a='xxx' and b='yyy' and c='zzz'
the query runs great and the cost is 10.
However, when I join this view with another table everything falls apart.
select * from my_table mt join my_view mv on (mt.a = mv.a and mt.b=mv.b and mt.c=mv.c) where ..."
everything falls apart with a cost though the roof.
What I think is happening is the predicates are not getting pushed to the view. As such, the view is now doing full tables scans and joining everything to everything and then finally removing all the rows.
Every hint, tweak, or anything I've done doesn't appear to help.
When looking at the plan it looks like it has the predicates.
But this happens after everything is joined.
Sorry if this is cryptic but any help would be greatly appreciated.
Since you have the view with a "GROUP BY", predicates could not be pushed to the inner query
Also, you have the group by functions in a case statement, which could also make it worse for the optimizer
Oracle introduces enhancements to Optimizer every version/release/patch. It is hard to say what is supported in the version you're running. However, you can try:
See if removing the case from the GROUP BY function will make any difference
Otherwise, you have to take the GROUP BY and GROUP BY functions from the view to the outer most query
After many keyboard indentations on my forehead I may have tricked Oracle into pushing the predicates. I don't know exactly why this works but simplifying things may have helped.
I changed all my ON clauses to USING clauses and in this way the column names now match the columns from which I'm joining to. On some other predicates that were constants I added in a where clause to the view.
The end result is I can now join this view with another table and the cost is reasonable and the plan shows that the predicates are being pushed.
Thank you to everybody who looked at this problem.
The problem I am facing is I am trying to query SAP HANA to bring back a list of unique codes that refer to one instance of a change being made to a database. For a bit of background to the below image, each change has a relevant Site ID and Product No. that I am using together as variables, in order to find out the TS Number for the most recent date.
However, when I use the SELECT MAX(DATAB) function, it forces me to use aGROUP BY clause. But, because I cannot omit the TS Number from the GROUP BY clause, it returns all three.
Is there a way to get the max date, for any given combination of Product No. and Site ID, and only return the TS Number for that date? In this example, it would be fine to use TOP 1 but this is just a scaled-down example from a query that will look at many combinations of Product No. and Site ID (with the desired outcome being a list of all of the TS Numbers that relate to the most recent change for that product/store combination, that I will use for a join to another query).
Any help would be appreciated. If full table design etc. is required so that people can attempt to replicate the problem I will happily provide this but am hoping there's a simple solution I have not thought of...
Many thanks
As in any other SQL-DB that supports window functions, you can use row_number() or rank() function to get the desired result. Which one to use depends on how you want to handle tie values.
If you just want exactly one TS-Number in case there are more than one TS-Number for the same MAXDATE, use the following SQL:
select dat, ts_nr, pr_nr, site
from
(select *, row_number() over ( partition by pr_nr, site order by dat desc ) rownum
from mytab
)
where rownum = 1;
Be aware, that the result is non-deterministic. However, you can (should in most cases!) make it deterministic by adding ts_nr to the order by in the window order by clause. Then you get either the highest or lowest TS-Number for the same MAXDATE, depending on the sort order.
If you want all TS-Numbers in case there are several TS-Numbers for the same MAXDATE, use rank() instead of row_number(), like this:
select dat, ts_nr, pr_nr, site
from
(select *, rank() over ( partition by pr_nr, site order by dat desc ) ranknum
from mytab
)
where ranknum = 1;
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.
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.