Difference between views and SELECT queries - sql

If views are used to show selected columns to the user, and same can be done by using
SELECT col1, col2
FROM xyz
, what is the point of using views?

Using a view saves you copying and pasting your queries and adds code reusability, so you can change a single view instead of 10 queries in the different places of your code.
Different permissions can be granted on views and tables, so that you can show only a portion of data to a user
A view can be materialized, which means caching the results of the underlying query

As Quassnoi said, it's useful for granting permission to certain rows in a table.
For example, let's say a lecturer at a university needs access to information on their students. The lecturer shouldn't have access to the "students" table because they could look up or modify information for any student in the whole university. The database admin makes a view that only shows students from the lecturers classes, and gives the lecturer the appropriate permissions for the view. Now the lecturer has access to their own students' data but not the whole "students" table.

A view can be described as a virtual table, created from a SQL query stored in the database.
Therefore, the following are aspects to consider in using VIEWS
Performance: it can improve data access performance as queries involving several tables generate transactions already exchanged to generate the view.
Simplicity: most of the views I work with are data arrangements of columns from 4+ tables, a bunch of inner joins. Once the view is created, your application developers will have to deal with the SELECT statements using column in the same view, hence the term virtual table.
Security: or just called it access control. Most relational database management system allow properties in the view object that control the type of access. For instance, one can allow users to update a view but only the DBA can make modifications to the tables that compose the view.

A view can be more complicated than just showing certain columns. It is a stored query. Wikipedia has much more detail.

Views make SQL easier to write (and read).
You can also use views to control access permissions.

Views:
1. View will not store any data
2. Used for Security purpose
3. When the base table is dropped, then the view is no longer accessible
4. One can perform DML operations directly on the view
Materialized view:
1. Materialized view does not store data
2. It is used for better performance
3. When the base table is dropped, a materialized view is still accessible
4. One cannot perform DML operations on materialized view.
Reference: https://www.youtube.com/watch?v=8ySsyZlixuE

All answers above provide an excellent explanation for the difference between a view and a query.
The query in the question is simple to an extreme degree, and creating a view for it might be overkill.
However, most queries are more complex, for example:
;with Orders2016 as (
select Customers.CustomerID
, Customers.CompanyName
, TotalOrderAmount = sum(OD.Quantity * OD.UnitPrice)
from Customers
join Orders O on Customers.CustomerID = O.CustomerID
join OrderDetails OD on O.OrderID = OD.OrderID
where OrderDate >= '2016-01-01'
and OrderDate < '2017-01-01'
group by Customers.CustomerID, Customers.CompanyName
)
, CustomersGroups as
(
select CustomerID
, CompanyName
, TotalOrderAmount
, CustomerGroup =
(
case
when
TotalOrderAmount >= 0 and TotalOrderAmount < 1000
then 'low'
when TotalOrderAmount >= 1000 and TotalOrderAmount < 5000
then 'Medium'
when TotalOrderAmount >= 5000 and TotalOrderAmount < 10000
then 'High'
when TotalOrderAmount >= 10000 then 'VeryHigh'
end
)
from Orders2016
)
select CustomerGroup
, TotalInGroup = Count(*)
, PercentageInGroup = Count(*) * 1.0 / (select count(*) from CustomersGroups)
from CustomersGroups
group by CustomerGroup
order by TotalInGroup desc;
Imagine rewriting it each time you want to access data. (Or even searching through files, copy & paste). Poor time management.
Views also save us tons of time and are a way to be DRY.

Views are very useful for access permissions. There are multiple other advantages (as stated in those links provided above), but for me the main advantage is the reusability. as Quassnoi writes, you can have a single point where you can edit your query, instead of editing a list of methods.
Perfect!

Related

Can what I seek not exist, two different queries showing on the same report/header query?

I'm astonished that I can't find this, unless it does not exist.
I've been using SQL to write queries in my PMS for about five years-
I wanted to do something new.
Is there no way to put two (or more) queries into the same output statement,
all to the same output?
Imagine I'm a bank, I have an SQL table with customer information,
and the bank account # is primary key---
I have a second table with ALL transaction data, primary key is sequential, one of the other columns includes of course, the account number.
Is there really no way to have output that is a combination a select statement that produces the equal of a checking statement.
It shows ONCE at the top the records I choose from the customer information table. It then proceeds with the line items. A simple header query.
then the long data query. Then goes to the page break?
i.e.
Select customer.account, customer.firstname, customer.lastname, customer.everything else from customer table
then--
select transaction.number, transaction.date, transaction.type, transaction.debitamt, transaction.creditamt, transaction.whatever
where transaction.account equals customer.account and dates are between x&y
order by transaction.number
pagebreak on customer.account
I want to show the output of two different queries on the same report
then I want a new page for the next customer
really? there is no provision for two different tables to be produced one after the other in this fashion? they have to match as to content? (union all)
as I don't need the customers name on every line of a transaction.
I've been searching for hours and can't find that this functionality exists....
SQL can be used to provide the data needed for your report, e.g. the query might look something like this:
select
c.account
, c.firstname
, c.lastname
, c.all_other
, t.number
, t.date
, t.type
, t.debitamt
, t.creditamt
, t.whatever
from customer_table c
inner join transaction_table t on c.account = t.account
where c.account = 'abcd'
and t.date >= '2018-04-01' and t.date < '2018-05-01'
order by
c.account
, t.date
;
But SQL is not designed as a report writer. It will supply the results of that query with information REPEATED for each customer in the columns coming from the customer table. This is NOT an accident or an error, it is by design and expected behaviour.
To "format" your report you need another tool e.g. you might use PHP and HTML to "format" the data into a "report". This extra tool is often referred to as a "presentation layer" and while the presentation layer may source the needed data using SQL it is up to that layer to meet your presentation needs.

SQL Multiple Joins - How do they work exactly?

I'm pretty sure this works universally across various SQL implementations. Suppose I have many-to-many relationship between 2 tables:
Customer: id, name
has many:
Order: id, description, total_price
and this relationship is in a junction table:
Customer_Order: order_date, customer_id, order_id
Now I want to write SQL query to join all of these together, mentioning the customer's name, the order's description and total price and the order date:
SELECT name, description, total_price FROM Customer
JOIN Customer_Order ON Customer_Order.customer_id = Customer.id
JOIN Order = Order.id = Customer_Order.order_id
This is all well and good. This query will also work if we change the order so it's FROM Customer_Order JOIN Customer or put the Order table first. Why is this the case? Somewhere I've read that JOIN works like an arithmetic operator (+, * etc.) taking 2 operands and you can chain operator together so you can have: 2+3+5, for example. Following this logic, first we have to calculate 2+3 and then take that result and add 5 to it. Is it the same with JOINs?
Is it that behind the hood, the first JOIN must first be completed in order for the second JOIN to take place? So basically, the first JOIN will create a table out of the 2 operands left and right of it. Then, the second JOIN will take that resulting table as its left operand and perform the usual joining. Basically, I want to understand how multiple JOINs work behind the hood.
In many ways I think ORMs are the bane of modern programming. Unleashing a barrage of underprepared coders. Oh well diatribe out of the way, You're asking a question about set theory. THere are potentially other options that center on relational algebra but SQL is fundamentally set theory based. here are a couple of links to get you started
Using set theory to understand SQL
A visual explanation of SQL

SQL query join different tables based on value in a given column?

Well I am designing a domain model and data mapper system for my site. The system has different kind of user domain objects, with the base class for users with child classes for admins, mods and banned users. Every domain object uses data from a table called 'users', while the child classes have an additional table to store admin/mod/banned information. The user type is determined by a column in the table 'users' called 'userlevel', its value is 3 for admins, 2 for mods, 1 for registered users and -1 for banned users.
Now it comes a problem when I work on a members list feature for my site, since the members list is supposed to load all users from the database(with pagination, but lets not worry about this now). The issue is that I want to load the data from both the base user table and additional admin/mod/banned table. As you see, the registered users do not have additional table to store extra data, while for admin/mod/banned users the table is different. Moreover, the columns in these tables are also different.
So How am I supposed to handle this situation using SQL queries? I know I can simply just select from the base user table and then use multiple queries to load additional data if the user level is found to be a given value, but this is a bad idea since it will results in n+1 queries for n admins/mods/banned users, a very expensive trip to database. What else am I supposed to do? Please help.
If you want to query all usertypes with one query you will have to have the columns from all tables in your result-table, several of them filled with null-values.
To get them filled with data use a left-join like this:
SELECT *
FROM userdata u
LEFT OUTER JOIN admindata a
ON ( u.userid = a.userid
AND u.usertype = 3 )
LEFT OUTER JOIN moddata m
ON ( u.userid = m.userid
AND u.usertype = 2 )
LEFT OUTER JOIN banneddata b
ON ( u.userid = b.userid
AND u.usertype = -1 )
WHERE...
You could probably drop the usertype-condition, since there should only be data in one of the joined tables, but you never know...
Then your program-code will have the job to pick the correct columns based on the usertype.
P.S.: Not that select * is only for sake of simplicity, in real code better list all of the column-names...
While is totally fine having this hierarchy in your domain classes, I would suggest changing the approach in your database. Otherwise your queries are going to be very complex and slow.
You can have just another table called e.g. users_additional_info with the mix of the columns that you need for all your user types. Then you can do
SELECT * FROM users
LEFT JOIN users_additional_info ON users.id = users_additional_info.user_id
to get all the information in a single simple query. Believe me or not, this approach will save you a lots of headaches in the future when your tables start to grow or you decide to add another type of user.

How do I join 2 columns together from 2 different views?

Using oracle SQL developer,
I have two views that have different columns. How can I join column 1 from view A into view B? I want to join AR_INVOICE_INQ_V.CLI_NAME CLI_NAME from view B into view A.
View A
CREATE OR REPLACE FORCE VIEW "KPRD"."AC_INPUT_AUDIT" ("CLIENT", "SEQUENCE_CODE", "EMPLOYEE", "ORIGINAL_DATE", "HOURS_SPENT", "LONG_DESCRIPTION", "TIME_AT_ACTUAL", "MANAGER")
AS
SELECT CLIENT,
SEQUENCE_CODE,
EMPLOYEE,
ORIGINAL_DATE,
HOURS_SPENT,
LONG_DESCRIPTION,
TIME_AT_ACTUAL,
MANAGER
FROM TIME_DETAILS
WHERE MANAGER BETWEEN 'AAGG' AND 'AZJE'
AND ORIGINAL_DATE > '28/SEP/2012'
AND TIME_AT_ACTUAL ! = 0;
View B
CREATE OR REPLACE FORCE VIEW "KPRD"."AC_AR_INV_BAL" ("CLIENT", "CLI_NAME", "PARTNER", "PAR_NAME", "MANAGER", "REFERENCE", "STATUS_CODE", "INVOICE_DATE", "TIME_BILLED", "GROUP_CLIENT_CODE", "GRPCLI_NAME", "INVOICE_BALANCE")
AS
SELECT AR_INVOICE_INQ_V.CLIENT CLIENT,
AR_INVOICE_INQ_V.CLI_NAME CLI_NAME,
AR_INVOICE_INQ_V.PARTNER PARTNER,
AR_INVOICE_INQ_V.PAR_NAME PAR_NAME,
AR_INVOICE_INQ_V.MANAGER MANAGER,
AR_INVOICE_INQ_V.REFERENCE REFERENCE,
AR_INVOICE_INQ_V.STATUS_CODE STATUS_CODE,
AR_INVOICE_INQ_V.INVOICE_DATE INVOICE_DATE,
AR_INVOICE_INQ_V.TIME_BILLED TIME_BILLED,
AR_INVOICE_INQ_V.GROUP_CLIENT_CODE GROUP_CLIENT_CODE,
AR_INVOICE_INQ_V.GRPCLI_NAME GRPCLI_NAME,
AR_INVOICE_INQ_V.INVOICE_BALANCE
FROM AR_INVOICE_INQ_V
WHERE MANAGER BETWEEN 'AAGG' AND 'AZGG';
The syntax for joining views is the same as for tables. I'm not entirely sure what you're trying to achieve, but I think you want all the columns from view A and one additional column from view B. Assuming CLIENT has a common value on both the syntax would be something like:
SELECT AIA.CLIENT,
AIA.SEQUENCE_CODE,
AIA.EMPLOYEE,
AIA.ORIGINAL_DATE,
AIA.HOURS_SPENT,
AIA.LONG_DESCRIPTION,
AIA.TIME_AT_ACTUAL,
AIA.MANAGER,
AAIB.CLI_NAME
FROM AC_INPUT_AUDIT AIA
JOIN AC_AR_INV_BAL AAIB ON AAIB.CLIENT = AIA.CLIENT;
This seems to assume there will be a one-to-one relationship between the records in both views, which seems unlikely, particularly since the MANAGER filters are different. So you might get a different set of results back to what you expect, possibly with duplicates and/or missing records. An outer join might address that but might also make it worse, so you'll need to be clearer how the views are related and what you're trying to achieve.
If you have access to the underlying tables, you might find it more performant to join those, but you'd probably need to test it both ways.
In order to join column 1 from view A into view B, both tables or views have to have the column 1. If you want to join AR_INVOICE_INQ_V.CLI_NAME CLI_NAME from view B into view A, View A has to have the column CLI_NAME. Otherwise you cannot do a join based on CLI_NAME column.

How can I group objects retrieved from database tables that have the same properties?

I am working on an application that allows users to build a "book" from a number of "pages" and then place them in any order that they'd like. It's possible that multiple people can build the same book (the same pages in the same order). The books are built by the user prior to them being processed and printed, so I need to group books together that have the same exact layout (the same pages in the same order). I've written a million queries in my life, but for some reason I can't grasp how to do this.
I could simply write a big SELECT query, and then loop through the results and build arrays of objects that have the same pages in the same sequence, but I'm trying to figure out how to do this with one query.
Here is my data layout:
dbo.Books
BookId
Quantity
dbo.BookPages
BookId
PageId
Sequence
dbo.Pages
PageId
DocName
So, I need some clarification on a few things:
Once a user orders the pages the way they want, are they saved back down to a database?
If yes, then is the question to run a query to group book orders that have the same page-numbering, so that they are sent to the printers in an optimal way?
OR, does the user layout the pages, then send the order directly to the printer? And if so, it seems more complicated/less efficient to capture requested print jobs, and order them on-the-fly on the way out to the printers ...
What language/technology are you using to create this solution? .NET? Java?
With the answers to these questions, I can better gauge what you need.
With the answers to my questions, I also assume that:
You are using some type of many-to-many table to store customer page ordering. If so, then you'll need to write a query to select distinct page-orderings, and group by those page orderings. This is possible with a single SQL query.
However, if you feel you want more control over how this data is joined, then doing this programmatically may be the way to go, although you will lose performance by reading in all the data, and then outputting that data in a way that is consumable by your printers.
The books are identical only if the page count = match count.
It was tagged TSQL when I started. This may not be the same syntax on SQL.
;WITH BookPageCount
AS
(
select b1.bookID, COUNT(*) as [individualCount]
from book b1 with (nolock)
group by b1.bookID
),
BookCombinedCount
AS
(
select b1.bookID as [book1ID], b2.bookID as [book2ID], COUNT(*) as [combindCount]
from book b1 with (nolock)
join book b2 with (nolock)
on b1.bookID < b2.bookID
and b1.squence = b2.squence
and b1.page = b2.page
group by b1.bookID, b2.bookID
)
select BookCombinedCount.book1ID, BookCombinedCount.book2ID
from BookCombinedCount
join BookPageCount as book1 on book1.bookID = BookCombinedCount.book1ID
join BookPageCount as book2 on book2.bookID = BookCombinedCount.book2ID
where BookCombinedCount.combindCount = book1.individualCount
and BookCombinedCount.combindCount = book2.individualCount.PageCount