Optimize web calculating to speedup web - php

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.

Related

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

Most efficient way of getting first payment method used by all users

Lets say I have a table in a MSSQL database called "Customers". I also have a table called "Orders", each of which contains a "CustomerID". What I want to do, is to generate a summary of what payment method (let's call that "PaymentMethod") was used for the first "Order" of every "Customer".
The method I have been using for this is to conduct my customer selection query...
SELECT <Columns> FROM Customers <WHERE>
...and then for each result, conduct a separate query to obtain the customer's first order's payment method:
SELECT TOP 1 PaymentMethod FROM Orders ORDER BY Timestamp ASC
This process has the benefit of obtaining the data I want in a very simple way that's easy to modify, but the huge disadvantage of meaning a query is carried out for every customer, which could mean tens-of-thousands of extra queries every single time!
Is there a more efficient way of doing this that I'm not thinking of? I'm racking my brain to think of a way of selecting directly from the "Orders" table to begin with, but the requirement for the query to not only group by "CustomerID" but also fetch the MIN() of "Timestamp" and then return "PaymentMethod" of the MIN() record doesn't seem to work?
You can use ROW_NUMBER for this:
SELECT PaymentMethod
FROM (
SELECT PaymentMethod,
ROW_NUMBER() OVER (PARTITION BY CustomerID
ORDER BY Timestamp ASC) AS rn
FROM Orders ) AS t
WHERE t.rn = 1
The above query picks the earliest-per-group record.
I guess this helps you.
SELECT C.* , O.PAYMENTMETHOD FROM Customers C
INNER JOIN Orders O ON O.CustomerID = C.CustomerID
WHERE O.OrderTime =
(SELECT TOP 1 OrderTime FROM Customers WHERE CustomerID = C.CustomerID) -- selects customer first order based on min time

Ad weight, giving advertisers a fair piece of the cake

For the project I am currently involved in we have a select number of 'advertiser' groups that can add 'Offers' to our site that are displayed around other products and sometimes are related to the page the customer/buyer is viewing.
The current Ad system is completely random, and gives no preference except when trying to target a specific product. So, if supplier1 has 9 adverts, and supplier2 has 1 advert then supplier1 gets much better value for their money as they get shown 9 out of 10 times.
How we are wanting to change this system is so that supplier1 and supplier2 should technically get the same exposure as each other regardless of the amount of ads they have in the system.
How would you suggest I try and approach this? I have looked at ad weight systems on StackOverflow; however, they don't seem to relate to groups.
SELECT *
FROM advertisments a
INNER JOIN
(
SELECT * FROM suppliers ORDER BY RAND() LIMIT 1
) s ON a.suplplier_id = s.suplplier_id
ORDER BY RAND()
This query first selects one supplier by random (eg, every supplier have the same chance) (oh but if there are suppliers without any advertisement, you should filter them out), then it gets only advertisements of this user (that is how this INNER JOIN works) and orders them by random

sql query to do specific matching of demands

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.

php mysql inventory

I'm creating an app for a trading card game called Magic: the Gathering and I have made a query that checks all user-submitted decks and gives you the percentage of cards you have in your inventory over the cards in the deck. But my problem is, it does this for all the decks on the database. What I want to do is only return the decks which I already have 50% of the cards for.
Here is the query:
SELECT
SUM(t.qty_inv) / t.deck_cards completed,
t.deck_id
FROM (
SELECT
CASE WHEN m.qty_inv IS NULL THEN 0 WHEN m.qty_inv > dc.card_qty THEN dc.card_qty ELSE m.qty_inv END qty_inv,
dc.deck_id,
d.deck_cards
FROM mtgb_test.decks d
INNER JOIN mtgb_test.decks_cards dc ON (d.deck_id = dc.deck_id)
LEFT OUTER JOIN (
SELECT
COUNT(*) qty_inv, item_print_id print_id
FROM mtgb_test.inventories_items
WHERE item_user_id = 1
GROUP BY item_print_id
) m ON (m.print_id = dc.card_print_id)
) t
GROUP BY deck_id
ORDER BY completed DESC;
The problem with this query is that I can't use the derived completed field in the where clause like so:
WHERE completed > 0.5
I don't know if variables can solve this problem, I tried a bit but it got mished mashed as I'm very new to user-defined variables.
Edit: Some good people answered below that I needed to have the HAVING syntax, and that is the correct and obvious answer. I'd just probably choose the best answer to the postscript question then.
Another thing, if I had 200,000 decks in my database and I had 2,000 cards in my inventory, I'm fine with this query looping through all those and finding which decks I already had half of the cards for. But my problem is with the LEFT OUTER JOIN. I don't know about how MySQL really works inside but maybe someone who does can point it out. When looping through all the 200,000 decks, would it do the left join for every deck there is or will it be smart enough to cache this so that it only queries my inventory items once?
Thanks in advance,
Ramon
You can use HAVING completed > 0.5 to further reduce the amount of rows returned. You can read more about HAVING clause at http://dev.mysql.com/doc/refman/5.5/en/select.html.

Categories