Example: List in alphabetical order, the names of all sailors that reserved boat 103:
SELECT DISTINCT sname FROM Sailors S, Reserves R WHERE S.sid = R.sid AND R.bid = ‘103’ ORDER BY sname Result: sname Adams Byers Smith ..... can also write: ORDER BY sname DESC or ORDER BY sname ASC (default) like SELECT DISTINCT, very expensive... SELECT a, b FROM table1 ORDER BY a + b, c;
SELECT DISTINCT sname INTO SailorNames FROM Sailors SELECT DISTINCT sname FROM Sailors
Summary thus far Clause ---------- SELECT[DISTINCT] FROM WHERE INTO GROUP BY HAVING ORDER BY Evaluation Order ---------- 4 1 2 7 3 5 6 Semantics (RA/RA*) ---------- * (or ) X* * Can’t express * Can’t express
Review Kitchen sink query: SELECT S.sname, S.sid, count(*) AS totalres INTO SailorsRes FROM Sailors S, Reserves R WHERE S.sid=R.sid AND S.age >= 18 GROUP BY S.sid, S.sname HAVING totalres > 4 ORDER BY sname ASC
SELECT bname FROM branch WHERE assets > SOME ( SELECT assets FROM branch WHERE bcity=‘Boston’) Q: Can you rewrite this query to something that is equivalent, but more efficient to execute? 1) SELECT assets 2) SELECT bname INTO Temp FROM branch FROM branch WHERE assets > SOME (Temp) WHERE bcity=‘Boston’ Q: Why this is better ?
SELECT bname FROM account as A WHERE balance > (SELECT AVG(amt) FROM loan as L WHERE A.bname = L.bname) Returns the branch names where accounts are held whose balances are more than the average loan taken at the same branch Kim’s technique: (1) SELECT bname, AVG(amt) as avgloan INTO Temp FROM Loan GROUP BY bname (2) SELECT A. bname FROM account A, Temp L WHERE A.bname = L.bname AND A.balance > L.avgloan
Why is the rewrite better than the original query?
Ans: the rewrite computes the avg loans JUST ONCE per branch Is the rewrite always better than the nested query? Ans: NO: if Loan has branch names not in account
Kim’s Unnesting Technique SELECT bname FROM branch as B WHERE B.numloans = ( SELECT COUNT(*) FROM loan as L WHERE B.bname = L.bname) returns branches whose loan count agrees with that specified (1) SELECT bname, COUNT(*) as numloans INTO Temp FROM Loan GROUP BY bname (2) SELECT A. bname FROM branch as B, temp as L WHERE B.bname = L.bname AND B.numloans = L.numloans Q: What is the problem with this rewrite? branch ( bname , bcity, assets,numloans)
Ans: Suppose branch relation includes a branch (Kenmore) with numloans = 0 and the loan is the same.
Is Kenmore in the result of the nested query? Is kenmore in the result of the unnested query? Why??? Nested query: .......... WHERE A.x = (SELECT COUNT(*) FROM B WHERE A.y = B.z) If A.x = 0 and ... no such B, then WHERE clause true COUNT(empty) = 0 What about SUM? No problem because SUM returns NULL and comparing something to NULL is never true
example: create a view consisting of branches and customers.
CREATE VIEW all-customers AS (SELECT bname, cname FROM depositor as d, account as a WHERE d.acct_no = a.acct_no) UNION (SELECT bname, cname FROM borrower as b, loan as l WHERE b.lno=l.lno) Can treat that view like a table: Find all customers of Kenmore: SELECT cname FROM all-customers WHERE bname = ‘Kenmore’
Mechanism for hiding data from view of certain users
CREATE VIEW V AS <Query Expression> Example: show all branches and cities, but hide assets CREATE VIEW branch2 AS SELECT bname, bcity FROM branch branch ( bname , bcity, assets)
Views create view vs INTO (1) SELECT bname, bcity FROM branch INTO branch2 (2) CREATE VIEW branch2 AS SELECT bname, bcity FROM branch vs (1) creates new table that gets stored on disk (2) creates “virtual table” (materialized when needed) Therefore: changes in branch are seen in the view version of branch2 (2) but not for the (1) case.
DELETE FROM <relation> [WHERE <predicate>] Example: 1. DELETE FROM account -- deletes all tuples in account 2. DELETE FROM account WHERE bname in (SELECT bname FROM branch WHERE bcity = ‘Bkln’) -- deletes all accounts from Brooklyn branch
Insertion: INSERT INTO <relation> values (.., .., ...)
or INSERT INTO <relation>(att1, .., attn)
values( ..., ..., ...)
or INSERT INTO <relation> <query expression>
Examples: INSERT INTO account VALUES (“Perry”, A-768, 1200) or INSERT INTO account( bname, acct_no, balance) VALUES (“Perry”, A-768, 1200) INSERT INTO account SELECT bname, lno, 200 FROM loan WHERE bname = “Kenmore” gives free $200 savings account for each loan holder at Kenmore
Suppose we have a view: CREATE VIEW branch-loan AS SELECT bname, lno FROM loan And we insert: INSERT INTO branch-loan VALUES( “Perry”, L-308) Then, the system will insert a new tuple ( “Perry”, L-308, NULL) into loan
CREATE VIEW depos-account AS SELECT cname, bname, balance FROM depositor as d, account as a WHERE d.acct_no = a.acct_no INSERT INTO depos-account VALUES( “Smith”, “Perry”, 500) How many relations we need to update? What about delete? Many systems disallow; Updatable Views, insertable-into views
Specify the query in SQL and declare a cursor for it
declare c cursor for select customer-name, customer-city from depositor, customer, account where depositor.customer-name = customer.customer-name and depositor account-number = account.account-number and account.balance > :amount
From within a host language, find the names and cities of customers with more than the variable amount dollars in some account.
The open statement causes the query to be evaluated
EXEC SQL open c END-EXEC
The fetch statement causes the values of one tuple in the query result to be placed on host language variables.
EXEC SQL fetch c into : cn, :cc END-EXEC Repeated calls to fetch get successive tuples in the query result
A variable called SQLSTATE in the SQL communication area (SQLCA) gets set to ‘02000’ to indicate no more data is available
The close statement causes the database system to delete the temporary relation that holds the result of the query.
EXEC SQL close c END-EXEC
Note: above details vary with language. E.g. the Java embedding defines Java iterators to step through result tuples.
Cursor EXEC SQL open c END-EXEC c Every fetch call, will get the values of the current tuple and will advance the pointer A while loop to get all the tuples Also, you can move up/down, go to the start, go to end, etc.. Finally, you can update/modify a tuple through a cursor
Updates Through Cursors Can update tuples fetched by cursor by declaring that the cursor is for update declare c cursor for select * from account where branch-name = ‘Perryridge’ for update To update tuple at the current location of cursor update account set balance = balance + 100 where current of c