I am looking for customer names of customers who have an interest in all artists.
I understand that in relational algebra, I can use the division operator, however I do not understand the SQL format in doing so.
I have these tables with columns:
customer (customerID, firstname, lastname)
artist (artistID)
customer_interest_in_artists (artistID, customerID)
How would I go about doing this?
You could do this using a simple MIN() construct:
SELECT c.firstname, c.lastname, MIN(ci.customerID IS NOT NULL) AS interest_all
FROM artist
LEFT JOIN customer_interest_in_artists ci USING (artistID)
LEFT JOIN customer c USING (customerID)
GROUP BY c.customerID
HAVING interest_all = 1
You could either:
Identify the customers for whom the number of rows in the customer_interest_in_artists table is equal to the number of rows in the artists table.
or
Identify the customers for whom there does not exist a row in the customer_interest_in_artists table for one or more artists.
The first option os probably easiest to implement, as you can already probably get the number of rows per customer (hint: join, count(*), and group) and compare the number per customer with the number of rows in artists -- hint: having count(*) = (a subquery)
for ORACLE, I use this...
but i don't think mine is the most elegant of all answers, anyway, here it is!
SELECT c.FIRSTNAME, c.LASTNAME, c.CUSTOMERID
FROM DTOOHEY.CUSTOMER c, DTOOHEY.CUSTOMER_ARTIST_INT cai
WHERE c.CUSTOMERID = cai.CUSTOMERID
AND c.CUSTOMERID IN
(SELECT cai.CUSTOMERID
FROM DTOOHEY.CUSTOMER_ARTIST_INT cai
GROUP BY cai.CUSTOMERID
HAVING COUNT (*) = (SELECT COUNT (*) FROM DTOOHEY.ARTIST)
)
GROUP BY c.FIRSTNAME, c.LASTNAME, c.CUSTOMERID;
based on my limited knowledge, the flow of command is:
1) I am trying to get the customer ID, first name and last name of customer
2) I am getting it from the 2 tables (cai and c)
3) trying to join the 2 tables to give me a single data set
4) where the c.customerid is to be gathered in...
this is where the magic begins!!!
5) select the customerID (the single CustomerID)
6) from this table cai
7) group the result based on customerID, this is what gives the single CustomerID Value that you need...
8) having COUNT (*) - having the count of customerID value, to that of equal of the number of count of artists in the dtoohey.artist table.
the main logic is that the number of artist in the artist table (which is 11), exist in the CUSTOMER_ARTIST_INT in the same quantity. As such, we can tally the result of count from the ARTIST Table into the CUSTOMER_ARTIST_INT table.
I think these will useful to you
SELECT a.customerID, c.artistID from customer a
join customer_interest_in_artists b on a.customerID = b. customerID
join artist c on c.artistID = b.artistID
Thank you.
Related
based on the DB schema I am trying to get for each customer the Id, date, customer name and the customer. Can anyone help?
I am struggling with adding the name of the customer. This is what I have tried so far:
SELECT customer,name,date
from table
You need two joins to the customers table. That said, you really need to learn to use meaningful table aliases rather than arbitrary letters. Table aliases are your friend, and arbitrary letters aren't so friendly.
So:
SELECT i.Id, i.BillingDate, c.Name as CustomerName,
cr.Name as ReferredByName
FROM Invoices i LEFT JOIN
Customers c
ON i.CustomerId = c.Id LEFT JOIN
Customers cr
ON i.ReferredBy = cr.Id;
I am trying to get the data for the best 5 customers in a railway reservation system. To get that, I tried getting the max value by summing up their fare every time they make a reservation. Here is the code.
SELECT c. firstName, c.lastName,MAX(r.totalFare) as Fare
FROM customer c, Reservation r, books b
WHERE r.resID = b.resID
AND c.username = b.username
AND r.totalfare < (SELECT sum(r1.totalfare) Revenue
from Reservation r1, for_res f1, customer c1,books b1
where r1.resID = f1.resID
and c1.username = b1.username
and r1.resID = b1.resID
group by c1.username
)
GROUP BY c.firstName, c.lastName, r.totalfare
ORDER BY r.totalfare desc
LIMIT 5;
this throws the error:[21000][1242] Subquery returns more than 1 row
If I remove the group by from the subquery the result is:(its a tabular form)
Jade,Smith,1450
Jade,Smith,725
Jade,Smith,25.5
Monica,Geller,20.1
Rach,Jones,10.53
But that's not what I want, as you can see, I want to add the name 'Jade' with the total fare.
I just don't see the point for the subquery. It seems like you can get the result you want with a sum()
select c.firstname, c.lastname, sum(totalfare) as totalfare
from customer c
inner join books b on b.username = c.username
inner join reservation r on r.resid = b.resid
group by c.username
order by totalfare desc
limit 5
This sums all reservations of each client, and use that information to sort the resulstet. This guarantees one row per customer.
The query assumes that username is the primary key of table customer. If that's not the case, you need to add columns firstname and lastname to the group by clause.
Note that this uses standard joins (with the inner join ... on keywords) rather than old-school, implicit joins (with commas in the from clause: these are legacy syntax, that should not be used in new code.
I have two tables, one is departments and the other is employees. The department id is a foreign key in the employees table. The employee table has a name and a flag saying if the person is part-time. I can have zero or more employees in a department. I'm trying to figure out out to get a list of all departments where a department has at least one employee and if it does have at least one employee, that all the employees are part time. I think this has to be some kind of subquery to get this. Here's what I have so far:
SELECT dept.name
,dept.id
,employee.deptid
,count(employee.is_parttime)
FROM employee
,dept
WHERE dept.id = employee.deptid
AND employee.is_parttime = 1
GROUP BY employee.is_parttime
I would really appreciate any help at this point.
You must join (properly) the tables and group by department with a condition in the HAVING clause:
select d.name, d.id, count(e.id) total
from dept d inner join employee e
on d.id = e.deptid
group by d.name, d.id
having total = sum(e.is_parttime)
The inner join returns only departments with at least 1 employee.
The column is_parttime (I guess) is a flag with values 0 or 1 so by summing it the result is the number of employees that are part time in the department and this number is compared to the total number of employees of the department.
As a preliminary aside, I recommend expressing joins with the JOIN keyword, and segregating join conditions from filter conditions. Doing so would make the original query look like so:
select dept.name, dept.id, employee.deptid, count(employee.is_parttime)
from employee
join dept on dept.id = employee.deptid
where employee.is_parttime = 1
group by employee.is_parttime
It doesn't make much practical difference for inner joins, but it does make the structure of the data and the logic of the query a bit clearer. On the other hand, it does make a difference for outer joins, and there is value in consistency.
As for the actual question, yes, one can rewrite the original query using a subquery or an inline view to produce the requested result. (An "inline view" is technically what one should call an embedded query used as a table in the FROM clause, but some people lump these in with subqueries.)
Example using a subquery
select dept.name, dept.id
from dept
where dept.id in (
select deptid
from employee
group by deptid
having count(*) == sum(is_parttime)
)
Example using an inline view
select dept.name, dept.id
from dept
join (
select deptid
from employee
group by deptid
having count(*) == sum(is_parttime)
) pt_dept
on dept.id = pt_dept.deptid
In each case, the subquery / inline view does most of the work. It aggregates employees by department, then filters the groups (HAVING clause) to select only those in which the part-time employee count is the same as the total count. Naturally, departments without any employees will not be represented. If a list of department IDs would suffice for a list of departments, then that's actually all you need. To get the department names too, however, you need to combine that with data from the dept table, as demonstrated in the two example queries.
in this cust_id is a foreign key and ords returns the number of orders for every customers
SELECT cust_name, (
SELECT COUNT(*)
FROM Orders
WHERE Orders.cust_id = Customers.cust_id
) AS ords
FROM Customers
The output is correct but i want to filter it to retrieve only the customers with less than a given amount of orders, i don't know how to filter the subquery ords, i tried WHERE ords < 2 at the end of the code but it doesn't work and i've tried adding AND COUNT(*)<2 after the cust_id comparison but it doesn't work. I am using MySQL
Use the HAVING clause (and use a join instead of a subquery).....
SELECT Customers.cust_id, Customers.cust_name, COUNT(*) ords
FROM Orders, Customers
WHERE Orders.cust_id = Customers.cust_id
GROUP BY 1,2
HAVING COUNT(*)<2
If you want to include people with zero orders you change the join to an outer join.
There is no need for a correlated subquery here, because it calculates the value for each row which doesn't give a "good" performance. A better approach would be to use a regular query with joins, group by and having clause to apply your condition to groups.
Since your condition is to return only customers that have less than 2 orders, left join instead of inner join would be appropriate. It would return customers that have no orders as well (with 0 count).
select
cust_name, count(*)
from
customers c
left join orders o on c.cust_id = o.cust_id
group by cust_name
having count(*) < 2
What's the best way to query a total price?
I want to multiply several rows of data by a certain amount and display their individual totals in a new column in £'s in my database?
What syntax do I need?
Edit:
I have loads of customers. Some have only one order, some multiple orders. I want to start charging them £1.50 per order, therefore, I need x(times) the order amount by £1.50 and display it in a new column in £. E.g customers with 4 order would need to be x £1.50 which would display £6.00 in column 3 and so on... 1.st column is name, second column is order amount. 3rd column needs to be total price. Hope that makes sense
Update from comments:
It's counted the orders, however it's returning BLOB values in the 3rd column where I want to display £ values for the * calculation of orders:
SELECT CONCAT_WS(" "
, c.customer_title
, c.customer_fname
, c.customer_sname
) AS Customer
, COUNT(O.order_name) AS Ordertotal
, concat('£' * 1.5) TotalPrice
FROM Order O, Friend F, Customer C, FriendOrder
WHERE C.customer_id = F.Customer_id
AND F.Friend_id = FriendOrder.friend_id
AND O.order_id = FriendOrder.order_id
GROUP BY Customer
ORDER BY C.customer_sname, C.customer_fname
It is a best practice to separate tasks, leaving computation to the SQL programming, and presentation to whatever programming language you use for the front end.
So your SQL should use it's native * operator. Your query might look like:
SELECT `column_1` * `column_2` as `product`;
this would return the product of two columns in a column named 'product'.
The £ sign is formatting. You should leave that to whatever architecture you have written for presenting the information. (PHP or java for example)
Applying a lot of imagination because of the lack of description of your data and fields, this should do the trick:
select c.name, count(*) orderAmount, concat('£', count(*) * 1.5) totalPrice
from customers c
join orders o on c.customerId = o.customerId
group by c.customerId, c.name
You shouldn't add the answer to the original question, since this makes finding out the question confusing.
It looks like everything was answered except the blob part -- here is the final result:
SELECT
CONCAT_WS(
" ",
c.customer_title,
c.customer_fname,
c.customer_sname
) AS Customer,
COUNT(*) AS Ordertotal,
CONCAT('£', cast(count(*) * 1.5 as char)) AS TotalPrice
FROM Order O
INNER JOIN FriendOrder fo
ON O.order_id = fo.order_id
INNER JOIN Friend F
ON fo.friend_id = F.Friend_id
INNER JOIN Customer C
ON F.Customer_id = C.customer_id
GROUP BY Customer
ORDER BY C.customer_sname, C.customer_fname
To avoid the 'blobs', cast to char since you are creating a display string. Here is the snippet from the query:
cast(count(*) * 1.5 as char)