sql query to do specific matching of demands - php

so I have a small problem whilst working with SQL and PHP. I have a sql db which has 4 tables namely, customers, requests, products and sellers. Now, each table contains self explanatory data. Such as customers tables lists the customers, ids, names, adresses, emails etc., products table has product id and the name, the requests table shows the request of products made by customers with the request id[pk], custID[fk from customer table], productid[fk in products table], quantites_requested, price_requested. The sellers table contains data such as sellersid[pk], customerid[fk from customer table], productsid[fk in products table], quantites_advertised, price_advertised
Now what I wish to do, is say a customer has requested productid= 1(chocolate),customer id=1, 10kg has been requested for £10.00 So, this data is stored in the DB.
Now, there might be various sellers of chocolate and what I wish to do is fulfil the customers order i.e. 10kg of chocolates in the cheapest way possible. either by combining sellers or selecting one cheapest seller. So, for example, this is the sellers table. NOTE: the sellers table is structured by following: sellerid[pk],customerid[fk],productid[fk],quantity_advertised, price_advertised. so here are some example sellers...
1,2,1,4.00,2.00 -- This means customer id 2 is selling chocolates, for 4KG's #£2.00
2,3,1,5.00,2.50
3,4,1,1.00,1.00
4,5,1,10.00,6.00
Now we have our requests that state
1,1,1,10.00,5.00 -- i.e. customer1, wants chocolates of 10kg for £5.00...
Now I wish to fulfil the customers 10kg order. So what I need to do is select the cheapest price for the customer. This could be done by selecting sellers 2,3 and 4 with the kg's of 5,4 and 1kg=10kg which would cost a total of £2.00+£2.50+£1.00=£5.50 cheaper then seller 5 which can supply 10KG for 6.00. I believe I would be able to do something like this using an SQL query where it first matches the customer requests product id to the sellers product id i.e. SELECT c.Name, p.Name, s.quantity,s.price WHERE c.id=s.customerid AND p.id=s.productid AND s.quantity WHERE r.productid=s.productid FROM requests r, sellers s
however, how would I be able to select the cheapest option supplier either combined or a single large supplier to take to be the most cost effective? I believe I would need to use the MIN somewhere in the query?
Can someone guide me on how to structure a query as stated. i.e. the full customer request needs to be met in the cheapest way possible.

With your current database design, which I still suggest changing, your query would be something like this:
select s.name SellerName
, p.name ProductName
, s.price_advertised price
from sellers s join products p on s.productid = p.productid
join request r on r.productid = p.productid
join (
select sellerid sid
, min(price_advertised) LowestPrice
from sellers ss join request rr on ss.productid = rr.productid
group by sellerid
) sq on sid = s.sellerid and s.advertised_price = LowestPrice
This is a simple example. You'll have to modify it to incorporate requests with more than one product.

Related

Query to display products from user in a group

Here is my struggle.
I have 4 tables
1:Users
2:Groups
3:Usergroupsrelation
4:Products
Users role may be Seller/Users where only Seller can add products to product table.
Super admin has ability to create Groups, where in he adds Seller or Multiple sellers to a group along with users.
Now. i need a query where in with particular userid(say user_02) i want to display products related to all sellers which user_02 belongs.
In simple words, its like whatsapp groups. Where only admins can post products in a group and all the users in groups can see the post.
You can simply use join query to fetch data
SELECT product_id , product_name , price FROM product
INNER JOIN users ON product.userid = users.id WHERE user.type = 1 AND user_id = 'user_02';
Hear you haven't provide much details so I ahve assume that in users table you have type field and it has enum value 0 = user , and 1 = seller.

Optimize web calculating to speedup web

My system is as follow
right now, I developed website about monitoring sales. Manager will give sales a target each product.. Then sales can input realisation of selling and manager will approve. Web will calculate the achievement and display sales who get the best achiev. Case Preview like in picture.
If the sales about 10 or 20 person its not problem.. But if the sales more than 100 sales like my case in web the sales man about 130 person and 700 approve selling, the result is my web very slow to calculate the best sales and now the sale product still increase.
I use php and CI.
Please give me suggest the best way to solve the problem like this
You can create the Performance View in 1 query:
SELECT sales, (avg( percent_sold )*100) avg_percent_sold
FROM (
SELECT sales, product, SUM(selling) sum_sold, target, SUM(selling)/target as percent_sold
FROM (
SELECT tt.sales, tt.product, tt.target, IFNULL(ts.selling,0) as selling
FROM tbl_target tt
LEFT JOIN tbl_selling ts ON ( ts.sales=tt.sales AND ts.product=tt.product )
ORDER BY NULL
) tbl_sales
GROUP BY sales, product
ORDER BY NULL
) tbl_performance
GROUP BY sales
ORDER BY avg_percent_sold desc
Performance can be optimized by adding indexes on all columns of tbl_target and tbl_selling . Make sure to check using the EXPLAIN query command to find out where indexes are not optimal.

MySQL & PHP: Selecting buyer records by product purchased

I have a somewhat complex MySQL query I'm attempting to derive but I'm just confusing the hell out of myself.
I have several tables: products, stores, buyer, payment and buyer_purchase.
buyer_purchase is basically made up of foreign keys. This table more or less links all the other together. The tables are filled up with junk data. The actual records themselves are not as important as the methods used to retrieve them.
I need to be able to select buyers who have purchased a specific product, how many of that item they've purchased, what store they bought it from, and the payment method used.
It will all be displayed in a webpage using PHP in the following manner:
Product1
name of buyer1
Payment method
Number Purchased
Store purchased From
product2
Name of buyer1
Payment
Number Purchased
Store Purchased from
Name of buyer2
Payment
etc.
I have a query that somewhat works:
SELECT products.item, stores.seller_name, buyer.f_name, buyer.l_name, payment.company
FROM buyer_purchases
INNER JOIN products
ON products.id = buyer_purchases.product_listings_id
INNER JOIN payment
ON payment.id = buyer_purchases.buyer_id
INNER JOIN buyer
ON buyer.id = buyer_purchases.buyer_id
INNER JOIN stores
ON stores.id = buyer_purchases.product_listings_stores_id
ORDER BY products.item
This will return all the data I need in a joined table, but getting it formatted to display as I need is what is confusing me. Obviously, I need to invoke a COUNT to display how many of a given product someone bought, but I'm not sure how to implement it. Further, I think I need GROUP BY rather than ORDER BY, but GROUP BY eliminates all but one record for each product. I've not been able to implement a subquery that MySQL doesn't complain about.
Right now, I'm trying to pull all of the data from the tables in a single query, and store it as a PHP array I can iterate through. If this is not the best way to go about this process, I can find another way.
I guess you just need more experience with MySQL, the trick is in the way you group the elements. In this case you want to group by multiple fields.
SELECT
products.item as product,
concat(buyer.f_name,' ',buyer.l_name) as buyer,
payment.company as payment,
count(products.id) as number_purchased
stores.seller_name as store,
FROM buyer_purchases
INNER JOIN products
ON products.id = buyer_purchases.product_listings_id
INNER JOIN payment
ON payment.id = buyer_purchases.buyer_id
INNER JOIN buyer
ON buyer.id = buyer_purchases.buyer_id
INNER JOIN stores
ON stores.id = buyer_purchases.product_listings_stores_id
GROUP BY buyer.id,stores.id,payment.id
ORDER BY products.item
You can have multiple ORDER BY clauses which work in order, so looks like you want ORDER BY products.item, buyer.id which will list all records for item 1 first, ordered by customer, then all records for item 2 ordered by cutomer etc

MySQL sum up numbers in a relational database

I'm making a web application to make customers order items for anything. For that I've made a MySQL database which has the following tables:
customers
orders
order-items
products
In the customers table is all the information about the person such as:
The customer ID, for the primary key and auto increment (id)
The first name (first_name)
The last name (last_name)
The email address (email_adress)
Information about the customer (customer_info)
Example:
In the orders table is all the specific information about it such as:
The order ID, for the primary key and auto increment (id)
Which customer ordered it, linked with id field from the customers table (customer_id)
Order information (order_info)
The location where the order needs to go to (location)
When the order was created (created)
Example:
In the order-items table are all the items which every customer ordered, this is being linked by the order-id from the previous table.
The ID, for primary key and auto increment, not used for any relation (id)
The order ID, used for which product is for which order. This is linked with the id field from the orders table (order_id)
The product ID, this is used for what product they ordered, this is linked with the id field from the products table. (product_id)
The amount of this product they ordered (quantity)
Example:
In the products table is all the information about the products:
The ID, for primary key and auto incrementing, This is linked with the product_id field from the order_items table (id)
The name of the product (name)
The description of the product (description)
The price of the product (price)
Example:
The problem
Bob ordered product_id 2, times 3. Which is the sandwich with beef with the price of 2.50, which we have to multiply by 3 because it has been ordered 3 times. Which is 7.50
Bob also ordered product_id 3, times 5. Which is the sandwich with chicken with the price of 3.00, which we have to multiply by 5 because it has been ordered 5 times. Which comes out on 15.00
Now I need to sum these up. Which is 15.00 + 7.50 = 22.50
The question
How do I get the product_id linked with the actual price of the product_id? which I can then multiply by the quantity.
And then sum up all those values with the same order_id
For the first order we get product 2 (Quantity 3) and product 3 (Quantity 5), which should add 2.503 + 3.005 = 22.50
You asked, "
How do i get the product_id linked with the actual price of the product_id? Which i can then multiply by the quantity... And then sum up all those values with the same order_id."
Like this:
SELECT OI.Order_ID, Sum(OI.Quantity * P.Price) Total_Price
FROM `order-items` OI
INNER JOIN Products P
on OI.Products_Id = P.ID
GROUP BY OI.Order_ID
Expected output for sample data in question:
ORDER_ID Total_price
1 22.50
This is why I asked about sample Output. I'm not sure what columns you were trying to return so I returned just the sum total for each order.
Now what this says
Return a row for each order showing the order ID and the total_price which is the sum of (quantity ordered * price all lines for that order.
This is accomplished by looking at the order-items table (in back tic's because I'm not sure if mySQL like's dashes (-) in names.). Joining these tables based on the product_Id between the ordered items table and the price table. and then group the results by the ordered item allowing the sum to aggregate all the rows for an order times the price of the item on that line of the order together.
You can build an intermediate table that has the totals for each order, then JOIN that with the orders table to get the customerID of that order, which you join with customers to get the customer name
SELECT C.FirstName, C.LastName, Totals.Order_ID, Totals.NetCost
FROM (SELECT OI.order_id, SUM(OI.quantity * P.price) as NetCost
FROM orderitems as OI INNER JOIN products as P ON OI.products_id = P.id
GROUP BY OI.order_id
) as Totals
INNER JOIN orders as O on O.ID = Totals.order_id
INNER JOIN customers as C on C.ID = O.customer_id
And the problem #xQbert is talking about is that if your customer places an order on Monday, you raise your price on Tuesday, and run this report on Wed, the report will show a total different from what the customer saw when he approved the order. A better design would be to store orderprice in orderitem, or at least the ordertotal in orders so subsequent price changes don't affect historic orders. The former is better in case a customer wants a refund on one item.
EDIT: I mean the problem #xQbert mentions in his comment, his answer came in ahead of mine but I missed it on the refresh
EDIT 2: More explanation, as requested by #Bas
It's easiest to think of this query from the inside and work outward, so let me start with getting the prices of items.
I want to link an item in orderitem with it's price, so JOIN orderitem (I give it an alias of OI) to products (I give an alias of P) on the product ID. Product ID is called products_id in OrderItem, but just ID in products.
Once I have that, I can multiply the price from Products by the quantity in OrderItems to get a cost for just that item
Because I want the total of everything for each order, I use a GROUP BY clause on this sub query, with the thing I'm grouping by being order_id. With a GROUP BY, you usually take the field or fields you are grouping by, and some "aggregate" fields where you take the sum, or max, or average, or whatever of them, and it's the sum or whatever for all rows that are in the same group.
So at this point we have defined the query inside the parenthesis. I named that Totals, and it acts just like a real table, but it goes away when your query is over.
The next step is to combine this "totals" table with your orders table so we can look up the customer ID, and then combine it with Customers so we can look up the customer name. I used aliases for Customer and Orders (C and O respectively), but they are not necessary. In fact, this could be rewritten most if not all of the aliases. I think it makes it more readable, but if they confuse you, you could use the following instead, it's the same. I think Totals is necessary, but maybe not even that.
SELECT FirstName, LastName, Totals.Order_ID, Totals.NetCost
FROM (SELECT order_id, SUM(quantity * price) as NetCost
FROM orderitems INNER JOIN products ON products_id = products.id
GROUP BY order_id
) as Totals
INNER JOIN orders on orders.ID = Totals.order_id
INNER JOIN customers on customers.ID = orders.customer_id
Hopefully this is clear, but if not, leave more comments and I'll further explain tonight or tomorrow.

Find New Buyers, and Returning Buyers from the Orders tables

I have an existing E-commerce database with the rather standard sales tables. The relevant tables are:
Orders table.
The fields are like:
OrderID, CustomerID, OrderDate, ...
Customers table.
CustoerID, CustomerFirstName, CustomerLastName, ...
I need to find two values, namely:
Total new buyers (within a certain time period *)
Basically, those are fist time buyers within a certain time period
Total returning buyers (within a certain time period *)
Basically, these are buyers who have bought before, prior to the time period
time period, we will provide as the inputs, such as within 1 week
My database is in MySQL.
Question:
What is the easiest and most efficient way to get the two totals?
1. Total new buyers
2. Total returning buyers
Do I need to write a program in PHP? Or I can simply use SQL statements to achieve this?
Thanks for any help.
This can be done purely in SQL:
Number of First time buyers:
SELECT
COUNT(DISTINCT CustomerID)
FROM Orders
WHERE OrderDate BETWEEN <startdate> AND <enddate>
/* Buyers with only one order record */
AND CustomerID IN (SELECT CustomerID FROM Orders GROUP BY CustomerID HAVING COUNT(*)=1)
Number of repeat buyers:
SELECT
COUNT(DISTINCT CustomerID)
FROM Orders
WHERE OrderDate BETWEEN <startdate> AND <enddate>
/* Buyers with more than one order record */
AND CustomerID IN (SELECT CustomerID FROM Orders GROUP BY CustomerID HAVING COUNT(*)>1)
Both! You have to write SQL statement that return data from the Database and call the statement from inside a PHP script to deal with it. The SQL statement make you able to retrive data and the PHP code make you able to menage and eventually presetn data on your web page (cenverting it into HTML language).
This is the common scenario, but if you need a more detailed procedure with code, use google and have a nice coding!
Total new buyers
SELECT c.*
FROM Customers c, Orders o
WHERE c.CustomerID = o.CustomerID
AND c.CustomerID not in(SELECT o1.CustomerID from Orders o1)
Total returning buyers
Total new buyers
SELECT c.*
FROM Customers c, Orders o
WHERE c.CustomerID = o.CustomerID
AND c.CustomerID in(SELECT o1.CustomerID from Orders o1)
you can add time frame to both queries

Categories