Getting a daily summary of figures from shop database - php

I have the following tables, in a standard shop:
(id is always primary key, auto-increment, ts is always type TIMESTAMP, updated ON_UPDATE CURRENT_TIMESTAMP)
table sales:
id | total | tendered | flag | userID | ts
1 0.6 0.6 0 4 2013-11-21 08:12:23
Sales is the parent table, userID is related to the user that made the sale. total and tendered are both of type FLOAT. flag is of type VARCHAR and could be Free Order.
table receipts:
id | oID | pID | quantity | ts
1 1 26 1 2013-11-21 08:11:25
Receipts holds a line for each unique type of product sold. oID is type INT and relates to the id of table sales. pID is of type INT and relates to the id of table products.
table products:
id | name | price | cID | display | ts
1 Mars 0.6 3 1 2014-01-17 07:55:25
Products is the central data for each product in the database. Here is a line for mars bars. cID relates to the id in table categories.
table categories
id | name | display | ts
3 Snacks 1 2013-11-14 12:06:44
Categories is the table holding all the data about each category, and can have multiple products relating to a single row. display is of type INT and dictates when the category is enabled or disabled (1 = 'true')
My question is, I want to output information like this:
**Snacks**
(name) (quantity) (price) (total)
Fruit 3 50p £1.50
Twix 1 60p 60p
Boost 1 60 60p
**Hot Drinks**
(name) (quantity) (price) (total)
English Tea 15 60p £9.00
Speciality Teas 2 60p £1.20
Which I have the following SQL for:
SELECT categories.name AS category, products.name, pID,
(SELECT SUM(quantity) FROM receipts WHERE pID=r.pID AND DATE(ts) = CURDATE()) AS quantity,
products.price,r.ts
FROM receipts r
LEFT JOIN products ON r.pID = products.id
LEFT JOIN categories ON products.cID = categories.id
WHERE DATE(r.ts) = CURDATE()
GROUP BY r.pID
ORDER BY categories.name;
Which seems to give me the correct information, but I am not 100% certain. If anyone could verify that this works, I would be most grateful. But when I want to see a particular day, I get unusual figures with the following SQL:
$postfrom = $_POST['from_mm']."/".$_POST['from_dd']."/20".$_POST['from_yy'];
$postto = $_POST['to_mm']."/".$_POST['to_dd']."/20".$_POST['to_yy'];
$from = strtotime($postfrom . " 6:00");
$to = strtotime($postto . " 23:59");
$itemised = select("SELECT categories.name AS category, products.name, pID,
(SELECT SUM(quantity) FROM receipts WHERE pID = r.pID AND UNIX_TIMESTAMP(r.ts) > '{$from}' AND UNIX_TIMESTAMP(r.ts) < '{$to}')
AS quantity, products.price
FROM receipts r
LEFT JOIN products ON r.pID = products.id
LEFT JOIN categories ON products.cID = categories.id
WHERE UNIX_TIMESTAMP(r.ts) > '{$from}'
AND UNIX_TIMESTAMP(r.ts) < '{$to}'
GROUP BY r.pID
ORDER BY categories.name;");
(function 'select' simply returns an array of the SQL table). The thing is, I could find the results easily by looping through in PHP and adding it up that way. But I know this is possible with SQL, I just don't know why It isnt working. Can somebody please help?
Edit SQL sample fiddle is here: http://sqlfiddle.com/#!2/23af4 although I couldn't do more than half a day of data due to 8000 character restrictions.

Try this:
SELECT categories.name AS category, products.name AS name,
receipts.quantity AS quantity, products.price AS price,
(receipts.quantity * products.price) AS total
FROM categories
JOIN products
ON categories.id = products.cID
JOIN receipts
ON receipts.pID = products.ID
WHERE DATE(receipts.ts) = CURDATE()
ORDER BY categories.name
SQLFiddle demo
With regard to the date restriction, you could use BETWEEN ... AND ... to specify the date and time. Using an absolute date and time moment or relative to the current day and time, for example WHERE DATE(receipts.ts) BETWEEN concat(curdate() -5,' 6:00:00 AM') AND curdate() -4

Related

Performing a query on the basis of the results of another SQL query

I have two tables with the name of customers and installments.i.e.
Customer Table:
id | name |contact |address
1 | xyz |33333333|abc
2 | xrz |33322333|abcd
Installments Table:
id | customer_id |amount_paid |amount_left | date
1 | 1 |2000 |3000 | 13/05/2017
2 | 1 |2000 |1000 | 13/06/2017
Now, I want to fetch the latest installment row from installments table for every user, I can use that with the following query,
SELECT * FROM installments WHERE customer_id=1 ORDER BY `id` DESC LIMIT 1
Now, the issue is that I want to do it for all the customer ids. I tried sub query thing but that doesn't supports multiple rows. I tried to store all customer IDs in an array in PHP and used "IN" but because the number of customers is more than 3000, it takes too long and returns an error of execution time exceeded.
Any kind of help or tip will be really appreciated. Thanks
SELECT
Customers.CustomerId,
Customers.Name,
Customers.Contact,
Customers.Address,
Installments.InstallmentId,
Installments.AmountPaid,
Installments.AmountLeft,
Installments.Date
FROM
Customers
INNER JOIN
(
SELECT
MAX( InstallmentId ) AS MaxInstallmentId,
CustomerId
FROM
Installments
GROUP BY
CustomerId
) AS LatestInstallments ON Customers.CustomerId = LatestInstallments.CustomerId
INNER JOIN Installments ON LatestInstallments.MaxInstallmentId = Installments.InstallmentId
you can do something like this
SELECT c.*,I.* FROM Customer_Table c LEFT JOIN Installments_Table I ON c.id=I.customer_id ORDER BY c.id DESC LIMIT 1
If You wants to add limit of list then only set limit else leave limit part. Untill I got Your Question this will be help you. else your problem can be something else.
SELECT cust.*,inst_disp.* FROM Customer AS cust
LEFT JOIN (
SELECT MAX(id) AS in_id, customer_id
FROM installments
GROUP BY customer_id
) inst
ON inst.customer_id = cust.id
LEFT JOIN installments as inst_disp ON inst_disp.id = inst.in_id

Min() with INNER JOIN and Full-text-search

So Ive got the following Query to work just fine, searching for 'test*' in 'products_desc' column and fetching all its prices in the 'prices' table.
SELECT products.id, prices.price, products.product_desc FROM products
INNER JOIN prices
ON prices.product_id = products.id
WHERE
MATCH (products.product_desc) AGAINST ('test*' IN BOOLEAN MODE)
Although the 'prices' table consists of multiple prices per product and I only want to fetch the lowest one to each product. I've previously filtered the prices using
INNER JOIN (
SELECT min(price) as price, prices.product_number as product_number FROM prices
WHERE prices.product_number LIKE'".$q."%'
GROUP BY prices.product_number
) min_prices
on prices.price = min_prices.price
and prices.product_number = min_prices.product_number
but this was when I used products_numbers within the prices table (now there is just a product_id-column.
Products
id | product_desc
----------------------------------------
1 | product1
2 | product2
Prices
id | product_id | price
------------------------------------------------
1 | 1 | 312
2 | 1 | 219
3 | 2 | 312
4 | 2 | 111
Also, the table consists of 10+ million rows so, efficiency matters a lot :)
EDIT
What if I need to access value of columns on the min(prices.price) row?
SELECT products.id, MIN(prices.price) as prices_price, prices.id as prices_id, products.product_desc, products.product_number, prices.supplier_id, suppliers.name FROM products
INNER JOIN prices
ON prices.product_id = products.id
INNER JOIN suppliers
ON prices.supplier_id = suppliers.id
WHERE
MATCH (products.product_desc) AGAINST ('test*' IN BOOLEAN MODE)
GROUP BY prices.product_id
The above returns the lowest price per product but also the wrong value in the other columns?
You can use GROUP BY for this, with MIN() group by function.
GROUP BY is used to group values from a column, and perform calculations on column.
In our case we want to group the result by product_id as it's repeating in second table and perform calculation (min()) on price column of second table.
This is how your Query would look like:
SELECT products.id, MIN(prices.price), products.product_desc FROM products
INNER JOIN prices
ON prices.product_id = products.id
WHERE
MATCH (products.product_desc) AGAINST ('test*' IN BOOLEAN MODE)
GROUP BY prices.product_id

SQL select all using JOIN

I'm using this query to collate two sets of results but I now need to use JOIN instead of UNION to get the second part of the data from another table.
However I need quite a lot of fields and can't seem to find a way to maintain the use of SELECT * when using JOIN.
mysql_query("SELECT * FROM table.products WHERE category='$cat' GROUP BY product_id ORDER BY id UNION ALL SELECT * FROM table.products WHERE type='red' GROUP BY product_id ");
Table - products
product_id | title | category | id
0 one home 10
1 two home 11
1 two - a home 12
2 three work 13
Table - product_details
product_id | type | size |
0 blue S
1 blue M
1 red L
Ultimately I need to list every product in the first table for a given category e.g home,
as there is sometimes two entries or more for a single product id, I need to only select one row for each product id value. I also need to join the second table so I can get the size info, however I must be able to get the size info by preferring a type e.g red.
So for this example I would get a list like:
product_id | title | category | type | size
0 one home blue S
1 two home red L
This excludes product_id 2 as it's not in the home category, the first entry for product_id equaling 1 is selected because of the GROUP BY and ORDER BY and the information on size for product_id 1 is L because it is of type red not blue.
Assuming you are using MySQL, you want a join with an aggregation or aggressive filtering. Here is an example using join and aggregation:
select p.product_id, p.title, p.category,
substring_index(group_concat(pd.type order by pd.type = 'red' desc, pd.type), ',', 1) as type,
substring_index(group_concat(pd.size order by pd.type = 'red' desc, pd.type), ',', 1) as size
from products p join
product_details pd
on p.product_id = qpd.product_id
where p.category = 'home'
group by p.product_id;
The expression substring_index(group_concat(. . .)) is choosing one type (and one size) with precedence given to the red type.
Your query can be simplified like below since you are using the same table table.products. Not sure why you need to UNION them.
SELECT * FROM table.products
WHERE category='$cat'
and type='red'
GROUP BY product_id
EDIT:
With your edited post, the query should look like
select p.product_id,p.title,p.category,q.type,q.size
from products p join product_details q
on p.product_id = q.product_id
where p.category = 'home'
and q.type = 'red'

Getting Sum of db field using join active record in codeigniter

I have a table name products with all product details and another whs_products with quantity details of the products for each warehouse.
i want select id, code and name from products table and sum of quantity where products.id = whs_products.product_id
I am trying this
$this->db->select("id, code, name");
$this->db->from("products");
$this->db->join('whs_products', 'products.id = whs_products.product_id');
$this->db->select("quantity");
I getting the list products that exists in whs_products not the sum. Some products are listed twice as they have 2 entries in whs_products.
I want list all the products once only where no quantity I want put 0 in quantity and where its is more than 1 in whs_products I want display sum of all the quantity
Help will be much appreciated!
Table Structure
Products
id, code, name, unit, price
whs_products
id, product_id, warehouse_id, quantity
I have whs table too for warehouse
id, name, address
I tried this Sir,
$this->db->select("products.id as productid, products.code, products.name, products.unit, products.cost, products.price, sum(whs_products.quantity) as 'totalQuantity'")
->from('products')
->join('whs_products', 'whs_products.product_id=products.id', 'left')
->group_by("products.id");
$this->db->get();
Every thing is fine. But the total number of products are calculated wrongly. I think system add 1 to total products, each time gets quantity from whs_products. For some products quantity is 2 or 3 time depending on each warehouse.
Any solutions for this. I am very thankful for your support.
Please try out the following query and comment.
SQLFIDDLE DEMO
Sample data:-
Products
PID PNAME
1 j
2 k
3 m
whs_Products
WID PID QUANTITY
11 2 300
11 2 200
14 2 500
11 1 300
15 3 100
14 3 800
Query to get total by pid in whs_products
select pid, wid, sum(quantity)
from whs_products
group by pid, wid
;
Results:
PID WID SUM(QUANTITY)
1 11 300
2 11 500
2 14 500
3 14 800
3 15 100
query using a variable to get user input for pid and by pid, wid
-- group by pid and wid
set #var:='2'
;
select a.pid, b.pname, a.wid, sum(a.quantity)
from whs_products a
join products b
on b.pid = a.pid
where a.pid = #var
group by a.pid, wid
;
Results:
PID PNAME WID SUM(A.QUANTITY)
2 k 11 500
2 k 14 500
final query to show quantity by user input pid only
Query:
-- by pid only
set #var:='2'
;
select a.pid, b.pname, sum(a.quantity)
from whs_products a
join products b
on b.pid = a.pid
where a.pid = #var
group by a.pid
;
Results:
PID PNAME SUM(A.QUANTITY)
2 k 1000
Since OP wants in CodeIgniter
Here is a headstart for you to try. At first I had the impression you already know the syntax of codeigniter and you are looking for SQL logic, so you could convert it into the desired format you need.
$this->db->select("a.pid, b.pname, count(a.quantity) as 'toalQuantity'");
$this->db->from('wsh_products a');
$this->db->join('products b', 'a.pid=b.pid', 'inner');
$this->db->group_by("a.pid");
$where = "a.pid = 2";
$this->db->get();
$query->results_array();
Or write a funciton :) :
function getQuantity($prodid = false)
{
$this->db->select(a.pid, b.pname, count(a.quantity) as 'toalQuantity');
$this->db->join('wsh_products a', 'a.pid=b.pid');
if ($prodid !== false)
$this->db->where('a.pid', $prodid);
$query = $this->db->get('products b');
if($query->result() == TRUE)
{
foreach($query->result_array() as $row)
{
$result[] = $row;
}
return $result;
}
}
Edit as OP requested for LEFT JOIN in comments
SQLFIDDLE
To show all products in Products table, do the following:
In select show pid from Products table.
Use from Products Left Join Whs_Products
Group by pid from Products table

Grab most recent values from table using php and mysql

Im having the below sql table structure and im trying to grab values from 2 tables using codeigniter.
table: salesman
id sales_name ref_id
1 kevin 174
2 mike 574
3 nick 777
table: sales_report
id salesman_id product purchased_date dispatched
1 2 BF0214 04-November-2011 Yes
2 2 CF0474 09-November-2011 No
3 2 BF0111 10-November-2011 No
4 3 BF0714 15-November-2011 Yes
5 3 BF0435 15-November-2011 Yes
6 2 BF0335 18-November-2011 Yes
7 1 BF0714 22-November-2011 Yes
8 1 BF0335 25-November-2011 Yes
im passing the salesman_id to the model to grab and display the values in my view.
my html table is as below
Ref ID | Salesman Name | Last product Sold | Sold Date | Dispatched Status
the problem that im having how can query to get the sales_name and ref_id from the salesman table and get the most recent product name, dispatched and purchase_date from from the sales_report table?
eg:
Ref ID | Salesman Name | Last product Sold | Sold Date | Dispatched Status
174 kevin BF0335 25-November-2011 Yes
574 mike BF0335 18-November-2011 Yes
777 nick BF0435 15-November-2011 Yes
Use
GROUP BY
ORDER BY
for getting this done
You need to use SELECT values from the sales_report, LEFT JOIN salesman to get in the sales_name and ref_id, ORDER BY the purchased_date (DESC to get the most recent one first instead of the oldest first), and GROUP BY the salesman.id to get it to only return one row per salesman.
SELECT * FROM sales_report LEFT JOIN salesman ON sales_report.salesman_id = salesman.id ORDER BY purchased_date DESC GROUP BY salesman.id
You should find last product by two criteras: its sold date and by its id; because some products may be sold in one day. So, try this one -
SELECT s.ref_id, s.sales_name, sr.product, sr.purchased_date, sr.dispatched FROM salesman s
JOIN (
SELECT salesman_id, product, purchased_date, dispatched FROM (
SELECT salesman_id, product, purchased_date, dispatched, IF(#salesman_id = salesman_id, #i := #i + 1, #i := 1) n, #salesman_id := salesman_id
FROM sales_report, (SELECT #i:= 0, #salesman_id = NULL) vars
ORDER BY salesman_id ASC, purchased_date DESC, id DESC) t
WHERE t.n = 1
) sr
ON s.id = sr.salesman_id;

Categories