I have two tables, Customers and Products. A customer can have more than one product.
I am trying to retrieve customers that do not have a specific product.
For example, 10 customers bought products A and B, another 10 customers bought A, B, and C. How can I retrieve those customers that do not have the C product?
For your current DB structure, this is what you are looking for:
select c.id, c.name, c.phone, c.address
from Customers c
where not exists (select * from products p
where p.customer_id = c.id and p.id = 'c')
However, you should consider creating a third table to store the individual purchases.
select *
FROM customer c
WHERE NOT EXISTS (SELECT 1 from products p
WHERE p.customer_id = c.id)
You should really (as suggested already by #Tony andrews and #Adrian) have a third table to store details of which customers bought which product.
Somthing like:
**Customer**
Id
Name
Address
Phone
**Product**
Id
Name
Price
**Customer_Product**
customer_id
product_id
This means you're removing redundancy from your product table. Consider what you'd need to do if a product name changed slightly - instead of updating multiple rows (as you'd have to do now), you'd only have to update 1 row, and you wouldn't need to touch your transaction history at all..
Related
I need to identify products that have purchased more than 1 time.
ERD diagram looks like this:
I wrote this query
SELECT DISTINCT good_name
FROM Goods
JOIN Payments
on Payments.good = Goods.good_id
WHERE good in (SELECT good
FROM (SELECT good
, COUNT(good) as c
FROM Payments
GROUP
BY good) as a
WHERE c > 1)
It works, but is this code great?
Grouping would work better:
SELECT good_name
FROM Goods
JOIN Payments on Payments.good = Goods.good_id
GROUP BY Goods.good_id
HAVING COUNT(Payments.good) > 1
Probably you also need an index over Payments.good column.
It is also better to create another column in the table Goods which will hold success payments count and update it after each payment.
three tables:
Customers (id_cus, cli_name, ...)
Products (id_pro, pro_name, ...)
Orders (id_cus, id_pro)
Table Orders is relation between Customers and Products.
Question is: How to get Customers (id_cus) who choose only specific product.
Example: Product A (id_pro= 100) and want all Clients customers who only bought this Product A, not Product A and Product B. Only Product A (id_pro = 100).
SELECT `id_cus` from `Orders` where `id_pro=100;
This give me all Customers who have ever bought Product A (and maybe Product B, C too).
Sorry, no idea.
Take a look to EXISTS
Simply:
SELECT o.id_cus
FROM orders o
WHERE o.id_pro = 100
AND NOT EXISTS (SELECT * from orders o2 where o2.id_cus = o.id_cus AND o2.id_pro != 100)
You can use aggregation for this:
select o.id_cus
from orders o
group by o.id_cus
having min(o.id_pro) = max(o.id_pro) and min(o.id_pro) = 100;
I have a mysql table Products.
It contains the Columns "id,product_name,product_seller,price"
I am trying to create a PHP script to Insert/Update data in the table Products using the seller name (product_seller).
The issue
I don't know what mysql query to use in order to get: A list with All the products NO matter if the seller has it or not and if the seller has the products to give me the details (id,product_name,product_seller,price).
EXAMPLE of what i want to get:
1 - apples - seller A - 12
2 - banana - -
3 - oil - -
4 - dvd - seller A - 25
The product_name must be DISTINCT
Thanks in advance!
* Query must be something like "SELECT DISTINCT product_name FROM Products and let me know where Seller A has the product, at what price, what id what product WHERE seller_name = 'seller A'...yet, show me all products, n matter if seller has it"
Seems to be a straight forward subquery to get a unique list of products then an outer join to get the seller info.
SELECT A.ID, A.Product_name, B.product_Seller, B.Price
FROM (SELECT DISTINCT ID, Product_Name FROM products) A
LEFT JOIN Products B
on A.ID = B.ID
and B.product_Seller = 'seller A'
The LEFT JOIN will ensure you return all the products and only seller information related to the items for 'SELLER A'
SQL generally operates best on data SETS. So I first generate a set of unique IDs and products and then LEFT JOIN this to the sellers product data you desire. The left join ensures we keep all the items. The filtering of the seller MUST be on the JOIN itself and not in the where clause. Otherwise the left join in essence becomes an inner as the NULLS generated from the outer join are removed.
SELECT A.ID, A.Product_name, B.product_Seller, B.Price
FROM (SELECT DISTINCT ID, Product_Name FROM products) A
LEFT JOIN Products B
on A.ID = B.ID
WHERE B.product_Seller = 'seller A'
Wouldn't get the desired result. This is because the where clause is applied after the join so the items that are not associated to the seller would be excluded. Since you want those records, you must use a left join and apply the limit on the JOIN so the items not associated to the seller are returned.
When I initially started with SQL I had trouble with this type of logic. It wasn't until I considered data in terms of "SETS" and how those sets related, that how to solve these questions became easier.
try to use the
SELECT * FROM Products_Table ;
this will obtain all the table values
The Select below summarizes the customer totals, but I need the customers first buy code to show where they first came from.
Select is:
SELECT h.buycode, Min(h.sdate) AS firstBuy, h.i_id,a.eid,count(*) AS orders,Sum(h.i_total) AS revenue,Max(h.sdate) AS LastBuy, a.eid, a.c_id
FROM mk_adr a
INNER JOIN oe_hdr h
ON h.c_id = a.c_id
WHERE h.sdate is not null
GROUP BY a.eid
eid is the enterprise ID that ties all of the c_id's(customer_id) together. A customer can have multiple c_id's, but only 1 eid. Eid is not part of the table oe_hdr.
I've tried using a sub-select with a left join and min(sdate) on oe_hdr, buycode, but it mostly returns null values for buycode.
This may not be the best way, but you can create a table that only holds the first purchase for the user. it places a foreign key to the user, and to the first item that they bought. Then you can just select from that table.
LOGIC:
IF -the user has no buys in the table- THEN
-Place the information in the first buy table-
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"