Creating a View SQL With Not Exists - sql

I need to create a view in SQL that I will use on my queries.
I am using the following tables:
customer (name:string,credit:integer)
loan (no:string,type:string,minCredit:integer)
borrower (cname:string,lno:string,due:date)
where borrower.cname and borrower.lno are foreign keys referencing customer, respectively loan, whose keys are name , respectively no (number). Attribute loan.minCredit indicates the minimum credit required of a
customer to qualify for that loan.
I am trying to create a view that shows customers and loans they haven't taken.
Create view LoansNotTaken AS
SELECT c.name, l.no
FROM customer c, loan l
WHERE NOT EXISTS(
SELECT c1.name,l1.no
FROM customer c1, loan l1, borrower b1
WHERE c1.name=b1.cname AND l1.no=b1.lno AND lno=l1.no AND c.name=c1.name)
My basic idea in the second select is get all the customer and loans they have taken pairs. Then I'm trying to use the not exists to give me all pairs excluding those. However my result only gives me pairs as long as the customer didn't take out any loans whatsoever, and I need the one they didn't take out even if they did take out some. Can anyone please help me to understand what I'm doing wrong in my query.

If you want the loans they haven't taken, then do this in two steps. First, create a list of all customers and all loans. Then remove the ones that are "taken".
So:
select c.name, l.no
from customers c cross join
loans l left join
borrowers b
on b.name = c.name and b.lno = l.no
where b.name is null;

I figured out what I did wrong in my query. But yeah I wrote my own tables to test these and kept editing it to test for different things. If I have any more questions I'll make sure to post tables and results to make it easier to answer.
This worked which is essentially what I had, I added type to have more data.
Create view LoansNotTaken AS
SELECT c.name, l.no, l.type
FROM customer c, loan l
WHERE NOT EXISTS(
SELECT c1.name,l1.no
FROM customer c1, loan l1, borrower b1
WHERE b1.cname=c1.name AND lno=l1.no AND c.name = c1.name AND l.no=l1.no)
;

Find pairs of names of customers who share the same loan. Avoid listing a customer with himself (e.g. do not list (Joe,Joe)). Also avoid repeating pairs which are equal modulo swapping the components (e.g. only one of (John,Jane), (Jane,John) should be listed).
I need a relational algebra and relational tuple calculus solution to this question, thanks!
Additional restraint: Do not use grouping or aggregation
I need answer for this question with same above the query

Related

SQL Server question - subqueries in column result with a join?

I have a distinct list of part numbers from one table. It is basically a table that contains a record of all the company's part numbers. I want to add columns that will pull data from different tables but only pertaining to the part number on that row of the distinct part list.
For example: if I have part A, B, C from the unique part list I want to add columns for Purchase quantity, repair quantity, loan quantity, etc... from three totally unique tables.
So it's almost like I need 3 subqueries that will sum of that data from the different tables for each part.
Can anybody steer me in the direction of how to do this? Please and thank you so much!
One method is correlated subqueries. Something like this:
select p.*,
(select count(*)
from purchases pu
where pu.part_id = p.part_id
) as num_purchases,
(select count(*)
from repairs r
where r.part_id = p.part_id
) as num_repairs,
(select count(*)
from loans l
where l.part_id = p.part_id
) as num_loans
from parts p;
Another option is joins with aggregation before the join. Or lateral joins (which are quite similar to correlated subqueries).

How do I use the . properly with sql?

I am new to sql and have a question about joining 2 tables. Why is there a . in between customers.custnum in this example. What is its significance and what does it do?
Ex.
Select
customers.custnum, state, qty
From
customers
Inner join
sales On customers.custnum = sales.custnum
The . is to specify a column of a table.
Let's use your customer table; we could do:
SELECT c.custnum, c.state, c.qty FROM customers as c INNER JOIN
sales as s ON c.custnum = s.custnum
You don't really need the . unless two tables have columns with the same name.
In the below query, there are two tables being referred. One is CUSTOMERS another is STATE. Since both has same column CUSTNUM, we need a way to tell the database which CUSTNUM are we referring to. Same as there may be many Bob's, if so their last name is used for disambiguation.
I would consider the below style as more clearer. That's opinionated.
Select
cust.custnum, cust.state, s.qty
From
customers cust -- use alias for meaningful referencing, you may be self-joining, during that time you can use cust1, cust2 as aliases.
Inner join
sales as s On cust.custnum = s.custnum
Think of it as a way to categorize the hierarchical nature of the database. Within a DB, there are tables, and within tables there are columns. It's just a way of keeping track, especially if you are working with multiple tables that may have the same column name.
For example, a table called Sales and a table called Customers might both have a column called Date. You may be writing a query where you only want the date from the Sales table, so you would specify that by writing:
Select *
From Sales
inner join Customers on Sales.ID = Customers.ID
where Sales.Date = '1/1/2019'

Relational division - SQL

I have 3 tables.
Owner(owner_id, name)
House(code, owner_id, price)
Buyer(buyer_id, name)
Bought(buyer_id, code, price_bought, date_bought)
I have the following query:
List the names of the buyers that bought all the houses from some owner?
I know how to find if someone bought all the houses from a particular owner (say owner with id = 1):
SELECT name
FROM buyer
WHERE NOT EXISTS (SELECT code
FROM house
WHERE owner_id = 1
AND code NOT IN (SELECT code
FROM bought
WHERE bought.buyer_id= buyer.buyer_id))
How can I make this work for all owners?
The sentence: "List the names of the buyers that bought all the houses from some owner?". This can be interpreted two ways. (1) All the houses the buyer bought are from one owner. Or (2) All the houses sold by one owner when to the same buyer.
The following answers (1):
select b.buyer_id
from bought b join
house h
on b.code = h.code
group by b.buyer_id
having min(h.owner_id) = max(h.owner_id);
The answer to the second question is similar. However, the focus is on owners rather than buyers.
select min(b.buyer_id)
from bought b join
house h
on b.code = h.code
group by h.owner_id
having min(b.buyer_id) = max(b.buyer_id);
EDIT:
In both cases, the logic is quite similar, but let's look at the second query. The join is just combining the buyer and owner ids together (not really interesting).
The group by is creating a single row for each owner_id. The having clause then adds the condition that the query only returns the owner id when the minimum buyer and the maximum buyer are the same -- meaning there is only one value. You can also express this condition as count(distinct buyer_id) = 1, but min() and max() generally perform a bit better than count(distinct).
The select clause then returns those buyers. You could also include the owner to see whose house(s) they bought.

Retrieve different row from same table

i hava a set of following tables
customer(cus_id,cus_name);
jointAccount(cus_id,acc_number,relationship);
account(acc_number,cus_id)
now i want to create a select statement to list all the jointAccounts,
it should included the both customer name, and relationship.
I have no idea how to retrieve both different user name, is that possible to do this?
Generally speaking, yes. I'm assuming you mean you want to get customer info for both sides of the joint account per your jointAccount table. Not sure what database you're using so this answer is assuming MySQL.
You can join on the same table twice in a single SQL query. I'm assuming you have not yet created your tables, as you have cus_id listed twice in the jointAccount table. Typically these would be something like cus_id1 and cus_id2, which I've used in my sample query below.
Example:
SELECT c1.cus_id AS cust1_id, c1.cus_name AS cust1_name
, c2.cus_id AS cust2_id, c2.cus_name AS cust2_name, j.relationship
FROM customer c1
INNER JOIN jointAccount j
ON c1.cus_id = j.cus_id1
, customer c2
INNER JOIN jointAccount j
ON c2.cus_id = j.cus_id2
I haven't tested this but that's the general idea.
try this query:
SELECT * FROM jointAccount a LEFT JOIN customer c ON a.cus_id = c.cus_id;
just replace the * with the name of the columns you need.

Select based on the number of appearances of an id in another table

I have a table B with cids and cities. I also have a table C that has these cids with extra information. I want to list all the cids in table C that are associated with ALL appearances of a given city in Table B.
My current solution relies on counting the number of times the given city appears in Table B and selecting only the cids that appear that many times. I don't know all the SQL syntax yet, but is there a way to select for this kind of pattern?
My current solution:
SELECT Agents.aid
FROM Agents, Customers, Orders
WHERE (Customers.city='Duluth')
AND (Agents.aid = Orders.aid)
AND (Customers.cid = Orders.cid)
GROUP BY Agents.aid
HAVING count(Agents.aid) > 1
It only works because I know right now with the HAVING statement.
Thanks for the help. I wasn't sure how to google this problem, since it's pretty specific.
EDIT: I'm pinpointing my problem a bit. I need to know how to determine if EVERY row in a table has a certain value for a field. Declaring a variable and counting the rows in a sub-selection and filtering out my results by IDs that appear that many times works, but It's really ugly.
There HAS to be a way to do this without explicitly count()ing rows. I hope.
Not an answer to your question, but a general improvement.
I'd recommend using JOIN syntax to join your tables together.
This would change your query to be:
SELECT Agents.aid
FROM Agents
INNER JOIN Orders
ON Agents.aid = Orders.aid
INNER JOIN Customers
ON Customers.cid = Orders.cid
WHERE Customers.city='Duluth'
GROUP BY Agents.aid
HAVING count(Agents.aid) > 1
What variant of SQL are you using?
To start with, you can (and should) use JOIN instead of doing it in the WHERE clause, e.g.,
select Agents.aid
from Agents
join Orders on Agents.aid = Orders.aid
join Customers on Customers.cid = Orders.cid
where Customers.city = 'Duluth'
group by Agents.aid
having count(Agents.aid) > 1
After that, I'm afraid I might be a little lost. Using the table names in your example query, what (in English, not pseudocode) are you trying to retrieve? For example, I think your sample query is retrieving the PK for all Agents that have been involved in at least 2 Orders involving Customers in Duluth.
Also, some table definitions for Agents, Orders, and Customers might help (then again, they might be irrelevant).
I'm not sure if I understood you problem, but I think the following query is what you want:
SELECT *
FROM customers b
INNER JOIN orders c USING (cid)
WHERE b.city = 'Duluth'
AND NOT EXISTS (SELECT 1
FROM customers b2
WHERE b2.city = b.city
AND b2.cid <> cid);
Probably you will need some indexes on these columns.