What is the difference between Views and With ... as clause in Oracle? - sql

My example is inspired by Oracle site
CREATE VIEW
-- ex1
with SAMP_V1 as (
AS SELECT COMM + BONUS as COL_SUM, COMM - BONUS as COL_DIFF
FROM SAMP.EMPLOYEE)
select * from SAMP_V1;
-- ex2
CREATE VIEW SAMP.V1 (COL_SUM, COL_DIFF)
AS SELECT COMM + BONUS, COMM - BONUS
FROM SAMP.EMPLOYEE;
select * from SAMP.V1;
The only difference I notice is that ex1 is written with one statement, while ex2 is split into two.
Also, I can use WITH to select subset of entire set, but I can do it with VIEW too.
Can it be that:
WITH does select work only once and
VIEW is an alias, hence it repeats SELECT every time it is mentioned
Thank you

A view and a with clause are certainly not the same thing.
A with clause generates an inline table (aka derived table) that exists only in the query within which it executes.
On the other hand, a view is a legitimate database object, that, in a sense, emulates a table. A view is defined by a sql query, so it is a virtual table, that can be queried just like any other database table. Under certain conditions, you can even run DML operations or views (update, delete, insert), that are applied to the underlying tables.
If you will repeativly need the same with clause, then a view is helpful to shorten your queries.

Related

Clarification about Select from (select...) statement

I came across a SQL practice question. The revealed answer is
SELECT ROUND(ABS(a - c) + ABS(b - d), 4) FROM (
SELECT MIN(lat_n) AS a, MIN(long_w) AS b, MAX(lat_n) AS c, MAX(long_w) AS d
FROM station);
Normally, I would enocunter
select[] from[] where [] (select...)
which to imply that the selected variable from the inner loop at the where clause will determine what is to be queried in the outer loop. As mentioned at the beginning, this time the select is after
FROM to me I'm curious the functionality of this. Is it creating an imaginary table?
The piece in parentheses:
(SELECT MIN(lat_n) AS a, MIN(long_w) AS b, MAX(lat_n) AS c, MAX(long_w) AS d FROM station)
is a subquery.
What's important here is that the result of a subquery looks like a regular table to the outer query. In some SQL flavors, an alias is necessary immediately following the closing parenthesis (i.e. a name by which to refer to the table-like result).
Whether this is technically a "temporary table" is a bit of a detail as its result isn't stored outside the scope of the query; and there is an also a thing called a temporary table which is stored.
Additionally (and this might be the source of confusion), subqueries can also be used in the WHERE clause with an operator (e.g. IN) like this:
SELECT student_name
FROM students
WHERE student_school IN (SEELCT school_name FROM schools WHERE location='Springfield')
This is, as discussed in the comments and the other answer a subquery.
Logically, such a subquery (when it appears in the FROM clause) is executed "first", and then the results treated as a table1. Importantly though, that is not required by the SQL language2. The entire query (including any subqueries) is optimized as a whole.
This can include the optimizer doing things like pushing a predicate from the outer WHERE clause (which, admittedly, your query doesn't have one) down into the subquery, if it's better to evaluate that predicate earlier rather than later.
Similarly, if you had two subqueries in your query that both access the same base table, that does not necessarily mean that the database system will actually query that base table exactly twice.
In any case, whether the database system chooses to materialize the results (store them somewhere) is also decided during the optimization phase. So without knowing your exact RDBMS and the decisions that the optimizer takes to optimize this particular query, it's impossible to say whether it will result in something actually being stored.
1Note that there is no standard terminology for this "result set as a table" produced by a subquery. Some people have mentioned "temporary tables" but since that is a term with a specific meaning in SQL, I shall not be using it here. I generally use the term "result set" to describe any set of data consisting of both columns and rows. This can be used both as a description of the result of the overall query and to describe smaller sections within a query.
2Provided that the final results are the same "as if" the query had been executed in its logical processing order, implementations are free to perform processing in any ordering they choose to.
As there are so many terms involved, I just thought I'll throw in another answer ...
In a relational database we deal with tables. A query reads from tables and its result again is a table (albeit not a stored one).
So in the FROM clause we can access query results just like any stored table:
select * from (select * from t) x;
This makes the inner query a subquery to our main query. We could also call this an ad-hoc view, because view is the word we use for queries we access data from. We can move it to the begin of our main query in order to enhance readability and possibly use it multiple times in it:
with x as (select * from t) select * from x;
We can even store such queries for later access:
create view v as select * from t;
select * from v;
In the SQL standard these terms are used:
BASE TABLE is a stored table we create with CREATE TABLE .... t in above examples is supposed to be a base table.
VIEWED TABLE is a view we create with CREATE VIEW .... v above examples is a viewed table.
DERIVED TABLE is an ad-hoc view, such as x in the examples above.
When using subqueries in other clauses than FROM (e.g. in the SELECT clause or the WHERE clause), we don't use the term "derived table". This is because in these clauses we don't access tables (i.e. something like WHERE mytable = ... does not exist), but columns and expression results. So the term "subquery" is more general than the term "derived table". In those clauses we still use various terms for subqueries, though. There are correlated and non-correlated subqueries and scalar and non-scalar ones.
And to make things even more complicated we can use correlated subqueries in the FROM clause in modern DBMS that feature lateral joins (sometimes implemented as CROSS APPLY and OUTER APPLY). The standard calls these LATERAL DERIVED TABLES.

Run two select statements in one view?

I have some SQL that is broken into two SELECT statements. The first SELECT statement inserts results INTO a temp table. The second SELECT statement is a COALESCE that reads data from the temp table the first one inserted data into. I need to be able to run these together (one after the other) and unfortunately cannot put these into a Stored Procedure due to the old reporting tool my company uses. The reporting tool must read from a VIEW or a TABLE. I wanted to put these into a VIEW, but have researched that a view cannot have more than one SELECT. Any ideas and examples on how to accomplish this? My original post/solution showing the SQL is in this post.
The temp table select could be converted to be a CTE (With clause), and the 2nd part the select query of the view.
Alternatively you could just inline it with sub-selects, but depending on complexity that might make it harder to maintain.
CREATE VIEW yourView AS
WITH myFirstSelect(someFields) AS
(
SELECT somefields FROM sometable
)
SELECT * from myFirstSelect
Docs : https://learn.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-2017

Does Oracle Query Optimizer apply top level where clauses to sub queries or views?

Oracle documentation says Oracle query engine executes sub-queries and views first and then executes top-level query. As a natural result of this, Oracle does not allow you to reference field values of top-level query in sub-queries (MSSQL allows this) You need to build a self sufficient sub-query and join the results to the top-level query.
After that comes my question: Does Oracle query optimizer apply top-level query's "where clauses" to sub-queries (where applicable) during execution?
Let's say I have a sub-query or view that returns a million rows when run alone but when joined with the top-level query only 1000 of those rows will be used, due to the join clause or where clause of the top-level query. Does Oracle try to bring all million rows from the sub-query and filter out unnecessary rows during joins or does Oracle query optimizer move join clauses or where clauses from the top-level query to sub-query so bring only a subset of rows?
Please do not give me the obvious answer saying: "Such a query is a poorly written one and I need to rewrite my query". Sometimes there are technical or non-technical limitations at play so I might not be able to do that.
I know that MSSQL query optimizer does this for sub-queries and views but since Oracle says sub-queries will be executed first, I needed to ask. Does Oracle query optimizer do this?
Edit: The following can be used as a sample query. The query might not be logically sound but it does represent a sample for my question. The sub-query returns all sales but the top-level query is using only the ones in this year. Does Oracle calculate sums of all sales or just the ones in this year?
select u.user_fullname, s.date, s.total
from users u
inner join ( select userID, date, sum(total) as total
from sales
group by userID, date
) s on s.userID = u.userID
where s.date > '2015-01-01'
Oracle frequently moves conditions between different levels of a query. This is called predicate pushing. Logical limitations may prevent subqueries and inline views from referencing top-level items, but that limitation does not apply to the transformed queries that Oracle executes.
This feature has been in Oracle for a long time. There are many references to it in the documentation, and even a few hints to help control it. (Although in general you won't need to use the hints.) As far as I know there are no sources that explain exactly when it can work but it should be able to work in your example. There are many cases where predicate pushing is possible, but not enabled, because the optimizer does not think it makes sense.
This simple example shows predicate pushing in action:
--Create a simple table.
drop table test1;
create table test1(a number primary key, b number);
insert into test1 select level, 1 from dual connect by level <= 100000;
commit;
begin
dbms_stats.gather_table_stats(user, 'TEST1');
end;
/
--Create a very slow function.
create or replace function very_slow(p number) return number authid current_user is
begin
execute immediate 'begin dbms_lock.sleep(1); end;';
return 1;
end;
/
--This query only takes 1 second.
--Without predicate pushing it would take hours.
select *
from
(
select *
from test1
where b = very_slow(b)
)
where a = 1;

minus vs delete where exist in oracle

I have a CREATE TABLE query which can be done using two methods (create as select statement for thousands/million records):
First method:
create table as select some data minus (select data from other table)
OR
first i should create the table as
create table as select .....
and then
delete from ..where exist.
I guess the second method is better.For which query the cost is less?Why is minus query not as fast as the second method?
EDIT:
I forgot to mention that the create statement has join from two tables as well.
The minus is slow probably because it needs to sort the tables on disk in order to compare them.
Try to rewrite the first query with NOT EXISTS instead of MINUS, it should be faster and will generate less REDO and UNDO (as a_horse_with_no_name mentioned). Of course, make sure that all the fields involved in the WHERE clauses are indexed!
The second one will write lots of records to disk and then remove them. This will in 9 of 10 cases take way longer then filtering what you write in to begin with.
So if the first one actually isn't faster we need more information about the tables and statements involved.

I would like to treat on the momentary table or inner table of oracle by making two or more values into a line.

Since I am a Japanese, I am poor at English.
Please understand the situation.
There is the following as indispensable requirements.
This requirement is unchangeable.
I know only ID of two or more values.
This number is over 500000.
It acquires early at low cost by 1 time of SQL.
The index is created by id and it is optimized.
The following SQL queries think of me by making these things into the method of taking as a search condition.
select *
from emp
where id in(1,5,7,8.....)
or id in(5000,5002....)
It divides 1000 affairs at a time by "in" after above where.
However, processing takes most time in case of this method.
As a result of investigating many things, it turned out that it is processing time earlier to specify conditions by "exists" rather than having specified conditions by "in".
In order to use "exists", you have to ask by a subquery.
However, it calls by a subquery well by what kind of method, or I cannot imagine.
Someone should teach a good method.
Thank you for your consideration.
If my understanding is correct, you are trying to do this:
select * from emp where emp in (list of several thousand values)
Because oracle only support lists of 1000 values in that construct your code uses a union.
Suggested solution:
Create a global temporary table with an id field the same size as emp.id
Insert the id:s you want to find in this table
Join against this table in your select
create global temporary table temp_id (id number) on commit delete rows;
Your select code can be replaced by:
<code to insert the emp.id:s you want to search for>
select * from emp inner join temp_id tmp on emp.id = temp_id.id;