I have this tables:
Sales(Product Code,No Customer, amount, Id sale)
Customer ( No Customer, Name, Adress, Phone, town)
Products (Product Code, Description, Price)
Well, my question is, how do I do this query in MySQL? :
Name of the customers who purchased all the products.
I have only this query that joins me the two tables that I have to use:
Select Name from Customer join Sales using(No Customer);
But I have the question, how do I separate the Customers that have all the products purchased?
Thanks for the help.
This is called relational division.It gets the result using contradiction.This is called classical method.
select c.name from customer c where not exists
(select * from products p where not exists
(select * from sales s where p.productcode=s.productcode and c.nocustomer=s.nocustomer))
There is one more way to do these type of queries.It was invented a few years back and published in a research paper which claimed that the new way was much more faster than the classical way.I will quote the source soon.The new method is using group by and count(*) like this:
select c.customername from customer c,sales s,product p
where p.productcode=s.productcode and c.nocustomer=s.nocustomer
group by s.nocustomer having count(*)=
(select count(distinct p1.productcode) from product p1)
The above query just compares the count of products bought by customer with the total count of distinct products in the products table and returns the name of the customers who matches the criteria.On a personal note I like the classical method more than this but the new method has a much more fast response then the classical method and I have checked it myself.Hope it helps.
Related
first time here. I'm a beginner
IM USING MYSQL.
I'm having trouble to get the ONLY SALESMAN who have SOLD a product to every CLIENT on the list
Compare the SALESMAN column with the CLIENT_KEY and return the value.
Could be only one salesman or two, I don't know.
This is a long list +8K transactions.
Below is a picture of the database
Thank you
Assuming you only have one table and all clients means all distinct client keys from your table.
SELECT SALESMAN
FROM YourTable
GROUP BY SALESMAN
HAVING count(DISTINCT CLIENT_KEY)=(SELECT COUNT(DISTINCT CLIENT_KEY) FROM YourTable)
The query sums all clients for each salesman, and checks if that number is equal to the sum of all distinct clients in the table.
if client list is a table then :
select salesman
from salesManTable s
group by salesman
having count(distinct clientid) = (select count(*) from clienttable)
I am working on a theatre booking system in MySql (My first SQL project). I have three tables:
Production (contains Title, BasicTicketPrice),
Performance (PerformanceDate, PerformanceTime, Title)
Booking (Email of person who booked, PerformanceDate, PerformanceTime, RowNumber).
Each person booked tickets for two or three performances (using their email to book).
I need to to write a query which will display the prices paid for all booked seats and I need to output the RowNumber, Email of person who booked and the Calculated Price.
I understand that I need to join these tables and make the query display a temporary column called Calculated Price but I don't know how to calculate the price.
I tried this:
SELECT DISTINCT b.RowNumber, b.Email, pr.BasicTicketPrice
FROM booking b, production pr performance p
WHERE p.Title=b.PerfDate*b.PerfTime*b.RowNumber;
SELECT CONCAT (PerfDate, PerfTime, RowNumber) AS BookingID FROM booking;
SELECT RowNumber, Email, CONCAT(PerfDate, PerfTime, RowNumber) AS BookingID FROM booking;
SELECT RowNumber, Email, CONCAT((CONCAT(PerfDate, PerfTime, RowNumber) AS BookingID
FROM booking)BasicTicketPrice*BookingID);
SELECT RowNumber, Email, CONCAT(PerfDate, PerfTime, RowNumber) AS BookingID INTEGER
FROM booking;
SELECT RowNumber FROM booking
LEFT JOIN (SELECT Title FROM performance WHERE '2017-11-01 19:00:00' Email IS NULL);
But it didn't work.
Any suggestions? I will be grateful for any ideas.
Assuming:
One row in Bookings per booked seat
Title to be a suitable primary key for Production
PerformanceDate, PerformanceTime to be a suitable primary composite key for Performance
You'll be looking to join the three tables together as per the keys assumed above. It seems you wish to group the bookings together per performance, by the person booking the tickets - if so, you'll need to use an aggregate to show the seat numbers (I've used GROUP_CONCAT to delimit them), as well as to COUNT the tickets purchased and multiply by the ticket cost.
SELECT
b.Email, prod.Title, per.PerformanceDate, per.PerformanceTime,
GROUP_CONCAT(RowNumber) AS BookedSeats,
COUNT(RowNumber) * prod.BasicTicketPrice AS TotalCost
FROM Booking b
INNER JOIN Performance per
ON b.PerformanceDate = per.PerformanceDate
AND b.PerformanceTime = per.PerformanceTime
INNER JOIN Production prod
ON per.Title = prod.Title
GROUP BY
b.Email, prod.Title, per.PerformanceDate, per.PerformanceTime, prod.BasicTicketPrice
ORDER BY prod.Title, per.PerformanceDate, per.PerformanceTime;
Technically, we should include all non-aggregated columns in the GROUP BY, hence prod.BasicTicketPrice is listed as well.
I have a table that tracks attendance in a course. The columns are the courseid, lesson, personid, and date. I have a query (below) that extracts the earliest date a person appears along with the associated course, lesson, and personid. This is used to determine when a person started a particular course and ensure they started with the first lesson. This works fine, but where I am stuck is running this query per course. For example, finding the first date each person in a particular course started it rather than for every course. Right now I am just running the more general query and filtering it in the biz layer.
I obfuscated this a bit so forgive any typos:
select a.courseid,
a.lesson,
a.personid,
a.thedate
from (select personid,
min(thedate) as earliestdate
from attendance
group by personid) as x
inner join attendance as a on (a.personid = x.personid and a.thedate = x.thedate)
Just group over person_id, course in the inner query:
select a.courseid, a.lesson, a.personid, a.thedate
from (
select personid, courseid, min(thedate) as earliestdate
from attendance
group by personid, courseid
) as x
inner join attendance as a
on (a.personid = x.personid and
a.thedate = x.thedate and
a.courseid=x.course_id)
I have a small doubt here. Currently all the information is maintained in single data object/table. How would it be if we have different data model like below...?
Objext1:
Course table: Course details having lession with a relation
Student table: Contains student details.
Will the querying would be simplified in this way....?
Sorry if anything sounds immatur...
Regards,
UDAY
I have the following query:
SELECT
DISTINCT sites.site_id,
sites.site_name,
sites.site_url,
earnings.cust_id
FROM
sites,
earnings
WHERE sites.site_id = earnings.site_id AND sites.site_id IN('8', '1666')
That query gives me very well the information asked. It returns two rows, one for site 8 and another for site 1666, with the information on them from those tables.
Now, I want that the cust_id number be used to select from another table (let's say table customers) where they are stored by id and where other info is such as name, last name, etc.
Basically what I need is to expand that query to extract customer name and last name from the table customers, using the ids obtained.
Same way you got the info from two tables. Add a comma, add the third table name, and add the relationship to your WHERE clause like you did with the first two tables.
SELECT
DISTINCT sites.site_id,
sites.site_name,
sites.site_url,
earnings.cust_id,
customers.name,
customers.last_name
FROM
sites,
earnings,
customers
WHERE sites.site_id = earnings.site_id AND sites.site_id IN('8', '1666') AND customers.id = earnings.cust_id
I think it's clearer to write out the JOINs though:
SELECT
sites.site_id,
sites.site_name,
sites.site_url,
earnings.cust_id,
customers.name,
customers.last_name
FROM
sites
INNER JOIN
earnings
ON
earnings.site_id = sites.site_id
INNER JOIN
customers
ON
customers.id = earnings.cust_id
WHERE
sites.site_id IN (8, 1666)
GROUP BY
sites.site_id
I have a MySQL database of 3 tables:
I. Person (id, name, purchases)
II. Purchase(id, product, date_purchased)
III. Catalog(id, product, cost-per-unit)
Person.purchases holds Purchase.id. That is, everytime a person buys something, the order id gets recorded in Person.purchases. For eg. Person.purchases has 1, 300, 292 stored in it.
Each Purchase entry records an instance of any item purchased. So, Purchase.id = 300 could be "foo".
And Catalog holds description about "foo".
What I want to find out is how to answer: "Who bought "foo"? I know how to answer this question in 2 steps as such:
Step 1: SELECT Purchases.id FROM Purchases INNER JOIN Catalog WHERE Purchases.product = Catalog.product;
I would store step 1's result in a variable tmp;
STEP 2: SELECT name FROM Person WHERE Person.orders LIKE "%tmp%";
I am using LIKE above because Person.orders stores multiple Purchase.id.
Is there a way to combine these two into one query?
The question can be answered using a single query:
Using EXISTS
SELECT a.name
FROM PERSON a
WHERE EXISTS(SELECT NULL
FROM PURCHASE b
JOIN CATALOG c ON c.product = b.product
WHERE FIND_IN_SET(b.id, a.purchases) > 0
AND c.product = 'foo')
Using a JOIN:
This requires DISTINCT (or GROUP BY) because duplicates are possible, if a person/customer has bought "foo" more than once.
SELECT DISTINCT a.name
FROM PERSON a
JOIN PURCHASE b ON FIND_IN_SET(b.id, a.purchases) > 0
JOIN CATALOG c ON c.product = b.product
WHERE c.product = 'foo'
Addendum
I agree with the other answers that the data model is poor - there should be a person/customer id in the PURCHASE table, not the PERSON table. But it doesn't change things drastically.
This is a poor database design and it's holding you back from answering a relatively simple question. I'd design your tables somewhat like this:
customers (id, name)
purchases (id, product_id, customer_id, date_purchased)
products (id, product_name, cost_per_unit)
Thus, your query to figure out 'Who bought foo?' is:
SELECT c.id, c.name
FROM products pr
LEFT JOIN purchases pu ON (pr.id = pu.product_id)
INNER JOIN customers c ON (pu.customer_id = c.id)
WHERE product_id = foo
-- could replace with product_name = 'foo' here, but you should know product_id
This has your database in a somewhat normal form (I don't remember which one exactly) so you can take advantage of the features that relational databases offer.
It might also be useful to make another table here, call it receipts, and rename purchases to line_items. This ensures that you can track customers who buy multiple items in one purchase, etc.
For MySQL this might be a better solutions:
SELECT person.*
FROM person
JOIN purchases
ON FIND_IN_SET(purchases.id,person.purchases) > 0
WHERE purchases.product = 'foo';
A much better structure of your tables would be:
I. Person (personid, name) ---purchases deleted from here
II. Purchase (purchaseid, buyerid, productid, date_purchased) ---buyerid added
III. Catalog (productid, product, cost-per-unit)
So, instead of storing purchaces of a person in Person table, store them in Purchase table.
This will have several benefits:
You can store as many purchases as you like. The way it is now, the "purchases" field will eventually be filled with purchases and what will you do then?
Easier to write your queries.
(If Person.purchases has ",1,300,292," stored in it, e.g. commas at start and end of field and no spaces), your question can be answered in one query like that:
If there are spaces and no commas at start and end the condition wili be more complex but surely it can be done.
SELECT p.id, p.name
FROM Person p
JOIN Purchase pur
ON p.purchases LIKE CONCAT("%,",CAST(pur.id AS CHAR),",%")
WHERE pur.product LIKE "foo"
And you don't need the join with Catalog since Product name is in Purchase table too.
If you do want to have info from Catalog, you could have the other join too:
SELECT p.id, p.name, cat.*
FROM Person p
JOIN Purchase pur
ON p.purchases LIKE CONCAT("%,",CAST(pur.id AS CHAR),",%")
JOIN Catalog cat
ON pur.product = cat.product
WHERE pur.product LIKE "foo" ---or cat.product LIKE "foo"