Oracle SQL MINUS on 3 tables - sql

I need to create an Oracle SQL query possibly using MINUS
Booking(BookID, MotelID, ClientID, Date)
Motel(MotelID, MotelName)
Client(ClientID, ClientName)
I can show the names of clients who have stayed at either motel (I think!!!)
SELECT DISTINCT ClientName
FROM (Client INNER JOIN Booking
ON Client.ClientID = Booking.ClientID)
INNER JOIN Motel
ON Booking.MotelID = Motel.MotelID
WHERE (MotelName = 'MotelOne' OR MotelName='MotelTwo');
But I now need to show the clients who have stayed at MotelOne but NOT MotelTwo.
Very new to this, and trying to get my head around it so any help will be gratefully accepted!

Oracle has a MINUS operator --> http://docs.oracle.com/cd/B19306_01/server.102/b14200/queries004.htm
It returns only unique rows returned by the first query but not by the second.
SELECT c.clientid, c.clientname
FROM booking b JOIN client c
ON b.clientid = c.clientid JOIN motel m
ON b.motelid = m.motelid
WHERE m.motelname = 'MotelOne'
MINUS
SELECT c.clientid, c.clientname
FROM booking b JOIN client c
ON b.clientid = c.clientid JOIN motel m
ON b.motelid = m.motelid
WHERE m.motelname = 'MotelTwo'
MINUS operator sorts rows and eliminates duplicates, so SELECT DISTINCT is not required.

Related

Finding multiple results in SQL Server 2012 (not duplicates)

I need some help. I've got a list of customers and services that they've used, but I need to narrow that list to customers that have used more than one service (excluding those who've only used one service). They have sometimes used the same service more than once, but I need a list of unique services.
The below brings back the main list of customers.
SELECT
DISTINCT M.CustID
,S.ServiceID
,R.ReceivedDate
,S.ServiceRequestID
FROM Customers AS M
LEFT OUTER JOIN CustomerDates AS R ON M.CustID = R.CustID
LEFT OUTER JOIN Service1 AS S ON R.ServiceRequestID = S.ServiceRequestID
WHERE S.CloseDate IS NULL
What I need is a list that excludes the first three lines as they have only used one service, whereas the next seven I need as they've used more than one service.
It is quite likely that you can just use NOT EXISTS. This is likely to do what you want:
SELECT M.CustID, S.ServiceID, R.ReceivedDate, S.ServiceRequestID
FROM Customers M JOIN
CustomerDates R
ON M.CustID = R.CustID JOIN
Service1 S
ON R.ServiceRequestID = S.ServiceRequestID
WHERE S.CloseDate IS NULL AND
EXISTS (SELECT 1
FROM CustomerDates cd2
WHERE cd2.CustId = m.custId AND cd2.ServiceRequestID <> r.ServiceRequestID
);
I'm not 100% sure this is equivalent to your query. The SELECT DISTINCT should not be needed, unless you have duplicates in your tables. Also, you seem to require matches between the tables, so LEFT JOIN is not appropriate. It it is not clear if the WHERE condition is relevant for finding duplicates.
Try the following, it should work
SELECT
CustID
,ServiceID
,ReceivedDate
,ServiceRequestID
FROM
(SELECT
DISTINCT M.CustID
,S.ServiceID
,R.ReceivedDate
,S.ServiceRequestID
,count(*) over (partition by M.CustID) as total
FROM Customers AS M
LEFT OUTER JOIN CustomerDates AS R ON M.CustID = R.CustID
LEFT OUTER JOIN Service1 AS S ON R.ServiceRequestID = S.ServiceRequestID
WHERE S.CloseDate IS NULL
) vals
where total > 1

SQL - How do I select rows from one table depending on data from two other tables?

I have an SQL question. It's a simple problem, but I'm not an SQL guy at all.
Here is the situation, I have three tables:
CUSTOMER(
PK(customer_id)
)
LOAN(
PK(loan_id),
customer_it,
behavior_id
)
BEHAVIOR(
PK(behavior_id),
unpaid_number
)
// PK(x): x is a primary key.
I would like to select all of the CUSTOMERs who have an unpaid_number >= 1.
Can anybody show me a way to work this around?
Thanks
You are looking for INNER JOIN. Use like:
SELECT * FROM CUSTOMER c
INNER JOIN LOAN l ON c.customer_id = l.customer_it
INNER JOIN BEHAVIOR b ON b.behavior_id = l.behavior_id
WHERE b.unpaid_number>=1
Use inner join
SELECT c.* FROM CUSTOMER c INNER JOIN LOAN l ON l.customer_id = c.Customer_id INNER JOIN BEHAVIOR b ON b.behavior_id = l.behavior_id WHERE unpaid_number >=1
Actually, if you want all customers, you presumably want one row per customer, regardless of the number of matching rows in behavior.
That would suggest using exists or in:
select c.*
from customer c
where exists (select 1
from loan l join
behavior b
on b.behavior_id = l.behavior_id
where b.unpaid_number >= 1 and
l.customer_id = c.customer_id
);
This is particularly important if you are considering using select distinct.
Please, try below code
SELECT c.*
FROM CUSTOMER c
INNER JOIN LOAN l
ON l.customer_id = c.Customer_id
INNER JOIN BEHAVIOR b
ON b.behavior_id = l.behavior_id
WHERE unpaid_number >=1
try this?
SELECT LOAN.customer_it FROM LOAN
WHERE LOAN.behavior_id IN
(SELECT BEHAVIOR.behavior_id
from BEHAVIOR where BEHAVIOR.unpaid_number>=1)

SQL Query + Join

I have 2 tables - Client, Jobs,
Client - clientID,clientName,clientCity
Bricklayers - jobNum, clientID, startDate
Now I need to query the database to list me all clients in 3 cities (Charlotte, Raleigh, Wilmington) and if they have a job on the Bricklayers table also list their jobNum(s) and startDate
I'm completely unsure what approach to take to this problem as I've never needed a query like this. I know I need a join and tried an inner join on the clientID in both columns but kept receiving syntax errors.
Try this
SELECT c.clientID, c.clientName, b.jobNum, b.startDate
FROM Client c
INNER JOIN Bricklayers b ON c.clientID = b.clientID
WHERE c.clientCity IN ('Charlotte','Raleigh','Wilmington');

Filtering query with join statement

I am using ColdFusion 8 to develop my company's website and would like to return a list of records (just the clientname field) from a table (dbo.clients) that has no match in a different table (dbo.fees) for the purpose of prompting the end-user to add a fee schedule for those companies. An example:
dbo.clients
CLIENT_ID CLIENT_NAME
1 Joe's Diner
2 Save-a-Lot
3 Family Meds
4 DiFazio's
dbo.fees
CID CLIENT_NAME FEE
1 Joe's Diner 25.000
2 Save-a-Lot 35.000
4 DiFazio's 30.000
What I desire is a resultset that, in the case of the above tables/data, would return only clientid/clientname 3/Family Meds because they do not have a fee listed/record in the table dbo.fees. My DB is MSSQL 2005. My query is:
SELECT clientid
FROM clients
INNER JOIN fees
ON clients.clientid <> fees.cid;
Which returns a Cartesian product of 50,000+ results. Using LEFT/RIGHT OUTER JOIN still gives me a Cartesian product and DISTINCT simply returns every record from dbo.clients regardless of whether or not they have a dbo.fees entry or not. What am I doing wrong?
p.s. Also of note: The admin before me apparently did not set up a PK/FK relationship between the clients/fees tables and so any query syntax that might be reliant on that may not work in this situation. It would probably have to work based solely on the values of the relevant fields.
You can use a LEFT JOIN with a WHERE clause that will return only those records that do not appear in the fees table:
select c.CLIENT_ID, c.CLIENT_NAME
from clients c
left join fees f
on c.CLIENT_ID = f.CLIENT_ID
where f.CLIENT_ID is null
If you need help learning JOIN syntax, here is a great reference:
A Visual Explanation of SQL Joins
This can also be written using a NOT EXISTS:
select *
from clients c
where not exists (select CLIENT_ID
from fees f
where c.CLIENT_ID = f.CLIENT_ID)
See SQL Fiddle Demo with both queries
Simplest, you could just use a NOT IN;
SELECT clientid FROM clients WHERE clientid NOT IN
(SELECT clientid FROM fees)
...or you can use a LEFT JOIN to do the same thing a bit more verbosely; f.clientid will be NULL if a fee does not exist for the client.
SELECT c.clientid
FROM clients c
LEFT JOIN fees f
ON c.clientid = f.clientid
WHERE f.clientid IS NULL

How to optimize a TSQL query?

"activity" is a bit field. I need to set it to true if one of the rows with this client_id has value true
SELECT c.client_id, u.branch_id, a.account_id, activity
FROM Clients c INNER JOIN
accounts a ON c.id=a.client_id INNER JOIN uso u ON a.uso_id = u.uso_id,
(SELECT MAX(CONVERT(int,accounts.activity)) as activity, client_id
FROM accounts GROUP BY client_id) activ
WHERE activ.client_id = c.id
This query executes about 2 minutes. Please help me to optimize it.
Seems activity field is a BIT and you cannot do a MIN or MAX on it.
Instead of this, use TOP:
SELECT c.client_id, u.branch_id, a.account_id,
(
SELECT TOP 1 activity
FROM accounts ai
WHERE ai.client_id = c.id
ORDER BY
activity DESC
)
FROM clients c
JOIN accounts a
ON c.id = a.client_id
JOIN uso u
ON a.uso_id = u.uso_id
Create an index on accounts (client_id, activity) for this to work fast.
You may want to read this article:
Minimum and maximum on bit fields: SQL Server
Join is expensive. Instead of Join, use memcache and make separate requests.