substract with phpspreedshet - php

I have a php front end for a database with expenses on a project.
I use phpspreadsheet to create reports from this database and until now everything worked great.
In the excel table I export three columns from the database table: type of expense, amount, date of expense.
The total amount for each type of expenses is entered in the table as a positive number and the quantities that are subtracted are entered as negative numbers - example: category of expense: travel costs, amount: 100, date | travel costs, amount: -10, date | travel costs, amount: -25, date, etc. In the excel template that I use with phpspreadsheet I created a fourth column 'balance'. In this column I substract the negative initial values from the starting amount that is positive and I end up with a excel table having four columns: travel costs, amount: 100, date, balance:100 | travel costs, amount: -10, date, balance:90 | travel costs, amount: -25, date, balance: 65 etc.
Until now it was simple because I knew the types of expenses - they were entered by me in the database so the users can only select between these predefined values and I got a sheet with multiple tables for each type of expense:
$sql="SELECT type_expense, , date, amount FROM expenses where acronym = '" . $_SESSION['idproject'] . "' ORDER BY type_expense";
$rsSql=db_query($sql,$conn);
$baseRow = 17;
$r=0;
$sum=0;
while ($data2 = db_fetch_array($rsSql)){
$row = $baseRow + $r;
$spreadsheet->getActiveSheet()->insertNewRowBefore($row, 1);
if($data2['type_expense']=='travel costs'){
$spreadsheet->getActiveSheet()->setCellValue('A' . $row, $r + 1)
->setCellValue('B' . $row, $data2['type_expense'])
->setCellValue('C' . $row, $data2['amount'])
->setCellValue('D' . $row, $data2['date']);
$sum=$sum+$data2['amount'];
$spreadsheet->getActiveSheet()->setCellValue('E'. $row , $sum);
$r= $r+1;
}
}
$spreadsheet->getActiveSheet()->removeRow($baseRow - 1, 1);
I use the same code for populating tables in the predefined sheet for the other two type of expenses: personnel cost and other expenses.
The problem is that now users need to define their own types of expenses so the code above could not work because I don't know how they define the type expense so I can use it in the if conditional inside the loop.
Also the sheet will be overcrowded with tables so I need to create a single table that define type of expense, date, amount and balance for all type of expenses - type of expense: travel costs, date, amount: 100, balance: 100 | type of expense: travel costs, date, amount: -10, balance: 90 | type of expense: personnel costs, amount: 10, date, balance:10 | type of expense: personnel costs, date, amount: -5, balance:5, etc
I tried with a conditional for all type of expenses as positive (this is the initial amount from where all the values are subtracted) but I get 0 in all the rows form the balance column.
I really need a suggestion where to go from here in order to have a single table with subtraction on each type of expenses.

Related

How to add column if 2 other field is same [duplicate]

Building an inventory system. I have lots of products and each product has three different variables. So for stock totals I want to group by the two columns (product & size) and sum quantity to get stock total.
product
Size
Quantity
Widget one
2
275
Widget one
2
100
Widget two
3
150
Widget two
2
150
What I want for output:
product
Size
Quantity
Widget one
2
375
Widget two
3
150
Widget two
2
150
I figured out how to group by one column and sum using the code below:
$query = "SELECT product, SUM(Quantity) FROM inventory GROUP BY product";
$result = mysql_query($query) or die(mysql_error());
// Print out result
while($row = mysql_fetch_array($result)){
echo "Total ". $row['product']. " = ". $row['SUM(Quantity)'];
echo "<br />";
}
?>
I am just stuck on grouping by both columns. Is it possible? or should I just create three different products for the of the three sizes and eliminate that column? Thanks.
Based on your example table, it appears you want to be grouping on product rather than id. You merely need to add the Size column to both the SELECT list and the GROUP BY
$query = "SELECT
product,
Size,
SUM(Quantity) AS TotalQuantity
FROM inventory
GROUP BY product, Size";
Note that I have added a column alias TotalQuantity, which will allow you to more easily retrieve the column from the fetched row via the more sensible $row['TotalQuantity'], rather than $row['SUM(Quantity)']

How to get SUM of a column with number of affected rows

How to get SUM of a column with number of affected rows
I am trying to get the sum of a column and I will also like to return the number of affected columns.
Example:
orders table
id customer_id name amount
----------------------------------------
1 2 burger 5.00
2 2 pizza 6.00
3 2 grape 1.00
4 1 sandwich 4.00
Now I want to SUM the amount column for a particular customer(customer_id) and also return number of items(count rows affected)
I am doing this but it only gets the sum of the amount, I would also like to get number number affected rows (count) from this single query:
SELECT SUM(amount) AS amount
FROM orders
WHERE customer_id = 2
Just do a COUNT as well:
SELECT SUM(amount) AS amount, COUNT(*) AS cnt
FROM orders
WHERE customer_id = 2
If amount is a nullable field and you want to only count NOT NULL rows, then do a COUNT(amount) instead of COUNT(*).
SELECT SUM(amount) AS amount, COUNT(1) AS cnt
FROM orders
WHERE customer_id = 2

MySQL/PHP - Need to be able to produce query results with certain columns having more weight than others

I have been tasked with creating a search function that when searched, certain fields will have more weight than others.
Here is an simplified example.
cars (table)
year, make, model, color, type (columns)
Let's say someone searches for the following:
Year: 1968
Make: Ford
Model: Mustang
Color: Red
Type: Sports Car
If the cars in the table have none of the correct fields they should not show up, but if record has some of the correct fields but not all they should still show up. But certain fields should be weighted higher than others.
For instance maybe they are weighted like this:
Column - Weight
Year - 30
Make - 100
Model - 85
Color - 10
Type - 50
So if a record matches the search in the "make" field and the "model" field, that record would be above a record that matched in the "year", "color" and "type" field, because of the weights we placed on each column.
So lets say that the query matches at least one field for two records in the database, they should be ordered by the most relevant based on the weight:
1971, Ford, Fairlane, Blue, Sports Car (weight = 185)
1968, Dodge, Charger, Red, Sports Car (weight = 90)
I have been racking my brain trying to figure out how to make this work. If anyone has done something like this please give me an idea of how to make it work.
I would like to do as much of the work in MySQL as possible via joins, I think this will be bring up the results faster than doing most of the work in PHP. But any solution to this problem would be much appreciated.
Thanks in advance
Bear with me, this is going to be a strange query, but it seems to work on my end.
SELECT SUM(
IF(year = "1968", 30, 0) +
IF(make = "Ford", 100, 0) +
IF(model = "Mustang", 85, 0) +
IF(color = "Red", 10, 0) +
IF(type = "Sports Car", 50, 0)
) AS `weight`, cars.* FROM cars
WHERE year = "1968"
OR make = "Ford"
OR model = "Mustang"
OR color = "Red"
OR type = "Sports Car"
GROUP BY cars.id
ORDER BY `weight` DESC;
Basically, this groups all results by their id (which is necessary for the SUM() function, does some calculations on the different fields and returns the weight as a total value, which is then sorted highest-lowest. Also, this will only return results where one of the columns matches a supplied value.
Since I don't have an exact copy of your database, run some tests with this on your end and let me know if there's anything that needs to be adjusted.
Expected Results:
+============================================================+
| weight | year | make | model | color | type |
|============================================================|
| 130 | 1968 | Ford | Fairlane | Blue | Roadster |
| 100 | 2014 | Ford | Taurus | Silver | Sedan |
| 60 | 2015 | Chevrolet | Corvette | Red | Sports Car |
+============================================================+
So, as you can see, the results would list the closest matches, which in this case are two Ford (+100) vehicles, one from 1968 (+30), and a Red Sports Car (10 + 50) as the closest matches (using your criteria)
One more thing, if you also want to display the rest of the results (ie results with a 0 weight match score) simply remove the WHERE ... OR ..., so it will check against all records. Cheers!
Further to the comments below, checking the weight after a LEFT JOIN on a pivot table:
SELECT SUM(
IF(cars.year = "1968", 30, 0) +
IF(cars.make = "Ford", 100, 0) +
IF(cars.model = "Mustang", 85, 0) +
IF(cars.color = "Red", 10, 0) +
IF(types.name = "Sports Car", 50, 0)
) AS `weight`, cars.*, types.* FROM cars
LEFT JOIN cars_types ON cars_types.car_id = cars.id
LEFT JOIN types ON cars_types.type_id = types.id
WHERE year = "1968"
OR cars.make = "Ford"
OR cars.model = "Mustang"
OR cars.color = "Red"
OR types.name = "Sports Car"
GROUP BY cars.id
ORDER BY `weight` DESC;
Here is a picture of the LEFT JOIN in practice:
As you can see, the Cobalt matches on color (silver) and model (Cobalt) (85 + 10) while the Caliber matches on type (Sports Car) (50). And yes, I know a Dodge Caliber isn't a Sports Car, this was for example's sake. Hope that helped!
If I understand your logic you can just do something like direct comparison in PHP between the value requested and the value returned.
The query will sound like:
SELECT Year,Make,Model,Color,Type
FROM table
WHERE year='$postedyear' OR make='$postedmake'
OR model='$postedmodel' OR color='$postedcolor'
Then in php looping between the results:
foreach($results as $result){
$score = 0;
if($result['year']==$postedyear{$score=$score+30;}
//continue with the other with the same logic.
}
After each foreach iteration $score will be the score of that selected row. If you push the score to the $result array you can also sort it by score before displaying the results.
Variation on #lelio-faieta
In php you can have a result array containing arrays of values for each item matching at least one of the search terms, the associative array of values to match and the associate array of weights, both with the same indexes. You would just get an array of matches for each index. (maybe use array_intersect_assoc()) Then you multiply by the weights and sum, add to the original data. Then you do have to sort the result array at that point.
There is a solution doing this via the mysql query directly, but that would end up with an overgrown resource thirsty query for every single search you perform.
Doing it in PHP is not much difference in resource usage, bounding to several loops in results and processing it.
I've had a very similar project and my best suggestion would be: "use SphinxSearch"
Very easy to install, needs a bit of a learning curve to setup afterwards, but very similar to mysql queries etc. With this you can apply weights to every column match and rank your results afterwards.
Also, it is a multitude of time faster that typical mysql queries.

Calculating tax correctly using Mysql and php

I am trying to re-calculate tax on a sale after it is entered into a database. I can calculate the information correctly before storing in the database, but calculating it from the database for reporting purposes has proved troublesome due to rounding errors.
The application displays an interface that allows one to add items and view the subtotal, taxes and totals.
Example input:
Item 1: 9.95
Item 2: 2.95
Subtotal: 12.90
Taxes (could be different for each item, but now they are all the same for each item)
2.900%: 0.37
1.000%: 0.13
1.100%: 0.14
3.000%: 0.39
Tax Total: 1.03
Total: 13.93
The way I calculate taxes before storing into database:
foreach Item as $price
{
foreach Tax as $percent
{
$taxes[$percent]+=$price*($percent/100);
}
}
foreach($taxes as $percent => $tax_amount)
{
$taxes[$percent] = ROUND_TO_2_DECIMALS($tax_amount);
}
After calculating all this information I store the information in a database that can be retrieved later for reporting purposes.
Example Schema:
phppos_sales_items
- sale_id
- item_id
- price
phppos_sales_items_taxes
- sale_id
- item_id
- tax_percent
Sample Data for phppos_sales_items table
sale_id: 1, item_id: 1, item_unit_price: 9.95
sale_id: 1, item_id: 2, item_unit_price: 2.95
Sample Data for phppos_sales_items_taxes table
sale_id: 1, item_id: 1, percent: 2.90
sale_id: 1, item_id: 1, percent: 1.00
sale_id: 1, item_id: 1, percent: 1.10
sale_id: 1, item_id: 1, percent: 3.00
sale_id: 1, item_id: 2, percent: 2.90
sale_id: 1, item_id: 2, percent: 1.00
sale_id: 1, item_id: 2, percent: 1.10
sale_id: 1, item_id: 2, percent: 3.00
Sample Query to calculate tax for a sale
(SELECT SUM(tax) FROM (SELECT ROUND((item_unit_price)*(SUM(percent)/100),2) as tax
FROM phppos_sales_items
INNER JOIN phppos_sales_items_taxes USING (sale_id, item_id)
WHERE sale_id = 1
GROUP BY sale_id, item_id) as tax)
Output is 1.04 when I need to get 1.03. This query works in most cases, but it fails a lot to when there are rounding problems.
I need to be able to generate summary informatation accuratly using sql. I am open to any suggestions on how to calculate information before the sale and in the database.
OK, so, your question, as I understand it has not much to do with programming.
So, you have an item which is worth $1. Now, you have two taxes on it, one is 1.4% and another one is 1.3%. Now, this is what you are doing
tax1 = round($1*0.014, 2) = $0.01
tax2 = round($1*0.013, 2) = $0.01
totaltax = $0.02
So far so good... OK, but now let's do it other way. If we add up the taxes, we should pay the total of 1.4 + 1.3 = 2.7%, which means:
totaltax = round($1*0.027, 2) = $0.03
See what happened here?
Now, which of these ways is right? If you physically need to pay tax1 separately from tax2, then each of them is quantified in cents and the first way is right. But, I feel like you most likely only pay the final total tax, that is you add up percents first, calculate your tax and then pay it to the nearest cent.
In relation to your code, you should get 1.03, that's right, but your query is doing a mistake similar to the first variant by rounding the result for each item before adding them up (it is doing round(price1*tax1, 2) + round(price2*tax2, 2)). (Actually, just to be complete, you have three places to round: individual tax level, item level and on the total level.)
To round at the end instead of for each item, move out your ROUND:
(SELECT ROUND(SUM(tax),2) FROM (SELECT (item_unit_price)*(SUM(percent)/100) as tax
FROM phppos_sales_items
INNER JOIN phppos_sales_items_taxes USING (sale_id, item_id)
WHERE sale_id = 1
GROUP BY sale_id, item_id) as tax)
Sorry to put as an answer, since the comment can not display code properly.
How about
(SELECT ROUND(SUM(tax)/100,2) FROM (SELECT item_unit_price*SUM(percent) as tax
FROM phppos_sales_items
INNER JOIN phppos_sales_items_taxes USING (sale_id, item_id)
WHERE sale_id = 1
GROUP BY sale_id, item_id) as tax)
Can you export the tables as sql, so I can try on my local? If nothing is too confidential.

MySQL: Group by two columns and sum

Building an inventory system. I have lots of products and each product has three different variables. So for stock totals I want to group by the two columns (product & size) and sum quantity to get stock total.
product
Size
Quantity
Widget one
2
275
Widget one
2
100
Widget two
3
150
Widget two
2
150
What I want for output:
product
Size
Quantity
Widget one
2
375
Widget two
3
150
Widget two
2
150
I figured out how to group by one column and sum using the code below:
$query = "SELECT product, SUM(Quantity) FROM inventory GROUP BY product";
$result = mysql_query($query) or die(mysql_error());
// Print out result
while($row = mysql_fetch_array($result)){
echo "Total ". $row['product']. " = ". $row['SUM(Quantity)'];
echo "<br />";
}
?>
I am just stuck on grouping by both columns. Is it possible? or should I just create three different products for the of the three sizes and eliminate that column? Thanks.
Based on your example table, it appears you want to be grouping on product rather than id. You merely need to add the Size column to both the SELECT list and the GROUP BY
$query = "SELECT
product,
Size,
SUM(Quantity) AS TotalQuantity
FROM inventory
GROUP BY product, Size";
Note that I have added a column alias TotalQuantity, which will allow you to more easily retrieve the column from the fetched row via the more sensible $row['TotalQuantity'], rather than $row['SUM(Quantity)']

Categories