Multiply kg and grams unit with price per kg - mysql

I'm currently have a task when I have to calculate the values for the cost of supplies which I have to multiply priceperweight with weight. But in weight there's also kg and grams. When I multiply it, it gives the results like $3000 for 500 grams of Spinach. Here's my scheme. Please help. All help would be appreciated :D Here's my code! Thank you so much
select PricePerWeight * Weight from Supplies;

Normalize the weight to grams or Kg (I'll use grams) using CASE x WHEN y:
SELECT
s.*,
CASE s.metric
WHEN 'Kilos' THEN ( s.weight * 1000 )
WHEN 'grams' THEN ( s.weight * 1 ) ELSE NULL
END AS weightInGrams
FROM
supplies AS s
Then adding additional units is straightforward:
SELECT
s.*,
CASE s.metric
WHEN 'tonnes' THEN ( s.weight * 1000 * 1000 )
WHEN 'Kilos' THEN ( s.weight * 1000 )
WHEN 'grams' THEN ( s.weight * 1 )
WHEN 'jupiter' THEN ( s.weight * 1.9 * POW( 10, 27 ) * 1000 )
WHEN 'lbs' THEN ( s.weight * 453.592 ) ELSE NULL
END AS weightInGrams
FROM
supplies AS s
Assuming you're using ISO-compliant SQL, you'll need to use an outer-query or a CTE to then multiply by pricePerWeight, which I assume is in Kg:
Note that the queries below still use grams as the base unit of mass to avoid problems caused by integer division (as SQL does not make it easy to make sure numeric literals are processed as floats or decimals instead of integers, as integer division truncates rather than rounds).
The final value is the thePrice column in the queries below:
Option 1: Using an outer-query:
SELECT
s2.*,
( s2.pricePerWeight * s2.weightInGrams ) / 1000.00 AS thePrice
FROM
(
SELECT
s.*,
CASE s.metric
WHEN 'tonnes' THEN ( s.weight * 1000 * 1000 )
WHEN 'Kilos' THEN ( s.weight * 1000 )
WHEN 'grams' THEN ( s.weight * 1 )
WHEN 'jupiter' THEN ( s.weight * 1.9 * POW( 10, 27 ) * 1000 )
WHEN 'lbs' THEN ( s.weight * 453.592 ) ELSE NULL
END AS weightInGrams
FROM
supplies AS s
)
Option 2: Using a CTE:
WITH s2 AS (
SELECT
s.*,
CASE s.metric
WHEN 'tonnes' THEN ( s.weight * 1000 * 1000 )
WHEN 'Kilos' THEN ( s.weight * 1000 )
WHEN 'grams' THEN ( s.weight * 1 )
WHEN 'jupiter' THEN ( s.weight * 1.9 * POW( 10, 27 ) * 1000 )
WHEN 'lbs' THEN ( s.weight * 453.592 ) ELSE NULL
END AS weightInGrams
FROM
supplies AS s
)
SELECT
s2.*,
( s2.pricePerWeight * s2.weightInGrams ) / 1000.00 AS thePrice
FROM
s2

Related

Using query result data for another query

The following query works for me. However, is there a way to speed it up (table1/2 contain each more than 300000 entries). I also would like to query more data in the subquery and use the distance just to filter results. The two tables have not much in common except the lat/lon.
SELECT `lat1`,
`lon1`,
(SELECT Sqrt(Pow( 69.1 * ( `lat1` - `lat2` ), 2 )
+ Pow( 69.1 * ( `lon2` - `lon1` ) * Cos( `lat` / 57.3 ), 2 )
) AS
distance
FROM table1
ORDER BY distance
LIMIT 0, 1) AS `test`
FROM `table2`
Thanks in advance

Relevancy MySQL query to replace stored procedure

I've taken over a project built by my predecessor. That project contains a stored procedure originally taken from here:
https://stackoverflow.com/a/9100182/439925
Currently this is preventing us from updating MySQL, so i have been attempting to remove it and replace the calls to subStringCount() with an adjustment to the top answer on that question.
(( Round (( Char_length(`title`) - Char_length(REPLACE(`title`, 'info', "")) ) / Char_length('info')) * 30 )) AS `title_score`,
The queries are used to count the number of times a search string occurs in a number of fields and then order by the total. Unfortunately i can't get the new query results to match the old one.
The 2 full queries are as follows:
Old WITH the stored Proc:
SELECT SQL_CALC_FOUND_ROWS `temp`.*,
( `title_score` + `source_score`
+ `abstract_score` + `authors_score`
+ `drugs_score` + `uploader_score`
+ `area_score`
+ Ifnull(`document_content_score`, 0) ) AS
`relevance`
FROM (SELECT `kb_uploads`.*,
(( Substringcount(`title`, 'info') * 30 )) AS `title_score`,
(( Substringcount(`source`, 'info') * 15 )) AS`source_score`,
(( Substringcount(`abstract`, 'info') * 20 ) AS`abstract_score`,
(( Substringcount(`authors`, 'info') * 30 )) AS `authors_score`,
(( Substringcount(`drugs`, 'info') * 20 )) AS `drugs_score`,
(( Substringcount(`kb_users`.`name`, 'info') * 20 )) AS `uploader_score`,
(( Substringcount(`kb_upload_areas`.`name`, 'info') * 20 )) AS `area_score`,
( `content_tbl`.`index_score` * 1 ) AS `document_content_score`
FROM `kb_uploads`
LEFT JOIN `kb_users`
ON `kb_users`.`id` = `kb_uploads`.`uploader`
LEFT JOIN `kb_upload_areas`
ON `kb_upload_areas`.`id` = `kb_uploads`.`area`
LEFT JOIN (SELECT `upload`,
Sum(`weighting`) AS `index_score`
FROM `kb_search_index`
WHERE `word` = 'info'
GROUP BY `upload`) AS `content_tbl`
ON `content_tbl`.`upload` = `kb_uploads`.`id`) AS `temp`
WHERE `is_deleted` = 0
HAVING `relevance` > 0
ORDER BY `relevance` DESC
LIMIT 10 OFFSET 0
New WITHOUT the stored Proc:
SELECT SQL_CALC_FOUND_ROWS `temp`.*,
( `title_score` + `source_score`
+ `abstract_score` + `authors_score`
+ `drugs_score` + `uploader_score`
+ `area_score`
+ Ifnull(`document_content_score`, 0) ) AS
`relevance`
FROM (SELECT `kb_uploads`.*,
(( Round (( Char_length(`title`) - Char_length(REPLACE(`title`, 'info', "")) ) / Char_length('info')) * 30 )) AS `title_score`,
(( Round (( Char_length(`source`) - Char_length(REPLACE(`source`,'info' , "")) ) / Char_length('info')) * 15 )) AS `source_score`,
(( Round (( Char_length(`abstract`) - Char_length(REPLACE(`abstract`, 'info', "" ) ) ) / Char_length('info')) * 20 )) AS `abstract_score`,
(( Round (( Char_length(`authors`) - Char_length(REPLACE(`authors`,'info', "")))/Char_length('info')) * 30 )) AS `authors_score`,
(( Round (( Char_length(`drugs`) - Char_length(REPLACE(`drugs`,'info',"")) ) / Char_length('info')) * 20 )) AS `drugs_score`,
(( Round (( Char_length(`kb_users`.`name`) - Char_length(REPLACE(`kb_users`.`name`,'info',""))) / Char_length('info')) * 20 )) AS `uploader_score`,
(( Round (( Char_length(`kb_upload_areas`.`name`) - Char_length(REPLACE(`kb_upload_areas`.`name`,'info', "")) ) / Char_length('info'))* 20 )) AS`area_score`,
( `content_tbl`.`index_score` * 1 ) AS `document_content_score`
FROM `kb_uploads`
LEFT JOIN `kb_users`
ON `kb_users`.`id` = `kb_uploads`.`uploader`
LEFT JOIN `kb_upload_areas`
ON `kb_upload_areas`.`id` = `kb_uploads`.`area`
LEFT JOIN (SELECT `upload`,
Sum(`weighting`) AS `index_score`
FROM `kb_search_index`
WHERE `word` = 'info'
GROUP BY `upload`) AS `content_tbl`
ON `content_tbl`.`upload` = `kb_uploads`.`id`) AS `temp`
WHERE `is_deleted` = 0
HAVING `relevance` > 0
ORDER BY `relevance` DESC
LIMIT 10 OFFSET 0
There are 2 main issues.
1) Ifnull is not working in the NEW query. The table column contains mostly null instead of 0
2) The relevancy numbers in the new query don't match the numbers in the old one, possibly something to do with IFNULL not working.
The full queries are constructed in PHP, i have left the code out as the logic hasnt changed, only the string concats to replace the Stored Proc.

Different calculation figure in arithmetic TSQL

I am getting diff. figures in my below equation written.
SELECT 9.36 + 9.36 / ( 284.36 ) * 15.64 = 9.8748065528 (CORRECT)
SELECT 18.72 / ( 284.36 ) * 15.64 = 1.0296131056 (INCORRECT)
I have total (9.36 * 2) Which I am putting in second select statement and gives incorrect amount.
What I am doing wrong?
The equations are not the same.
The second statement is the equivalent of:
SELECT (9.36 + 9.36) / ( 284.36 ) * 15.64
not
SELECT 9.36 + 9.36 / ( 284.36 ) * 15.64
Remember your Order of Operations.
THIS is what I want.
SELECT 9.36 + (9.36 / ( 284.36 ) * 15.64)

Slow location based search result query

I have a query that I use to find results that are ordered by location. Results also have to account for VAT so this is also in the query. The query can unfortunately take 4+ seconds to run when not cached. Can anyone spot any glaringly obvious issues or suggest anything I can do to improve it?
Just to clarify what is happening in the query:
The distance is calculation is euclidean distance using lat/long
The incvat fields are used to show the price when vat is included
The WHEN / THEN statement is used to put prices of 0 at the very bottom
The query:
SELECT * , ROUND( SQRT( POW( ( 69.1 * ( company_branch_lat - 52.4862 ) ) , 2 ) + POW( ( 53 * ( company_branch_lng - - 1.8905 ) ) , 2 ) ) , 1 ) AS distance,
hire_car_day + ( hire_car_day * 0.2 * ! hire_car_incvat ) AS hire_car_day_incvat,
hire_car_addday + ( hire_car_addday * 0.2 * ! hire_car_incvat ) AS hire_car_addday_incvat,
hire_car_week + ( hire_car_week * 0.2 * ! hire_car_incvat ) AS hire_car_week_incvat,
hire_car_weekend + ( hire_car_weekend * 0.2 * ! hire_car_incvat ) AS hire_car_weekend_incvat
FROM hire_car
LEFT JOIN company_branch ON company_branch_id = hire_car_branchid
LEFT JOIN hire_cartypelink ON hire_cartypelink_carhireid = hire_car_id
LEFT JOIN users ON company_branch_userid = user_id
WHERE 1
GROUP BY hire_car_id
HAVING distance <=30
ORDER BY CASE hire_car_day_incvat
WHEN 0
THEN 40000
ELSE hire_car_day_incvat
END , distance ASC
LIMIT 0 , 30
You can use the mysql spatial extension and save the latitude and longitude as a point datatype and make it a spatial index. That way you can reorder the coordinates along a curve and reduce the dimension and preserve spatial information. You can use the spatial index as a bounding box to filter the query and then use the harvesine formula to pick the optimal result. Your bounding box should be bigger then the radius of the great circle. Mysql uses a rtree with some spatial index and my example was about a z curve or a hilbert curve: https://softwareengineering.stackexchange.com/questions/113256/what-is-the-difference-between-btree-and-rtree-indexing.
Then you can insert a geocoordinate directly into a point column: http://dev.mysql.com/doc/refman/5.0/en/creating-spatial-values.html. Or you can use a geometry datatype: http://markmaunder.com/2009/10/10/mysql-gis-extensions-quick-start/. Then you can use MBRcontains function like so: http://dev.mysql.com/doc/refman/4.1/en/relations-on-geometry-mbr.html or any other functions: http://dev.mysql.com/doc/refman/5.5/en/functions-for-testing-spatial-relations-between-geometric-objects.html. Hence you need a bounding box.
Here are some examples:
Storing Lat Lng values in MySQL using Spatial Point Type
https://gis.stackexchange.com/questions/28333/how-to-speed-up-this-simple-mysql-points-in-the-box-query
Here is a simple example with point datatype:
CREATE SPATIAL INDEX sx_place_location ON place (location)
SELECT * FROM mytable
WHERE MBRContains
(
LineString
(
Point($x - $radius, $y - $radius),
Point($x + $radius, $y + $radius)
)
location
)
AND Distance(Point($x, $y), location) <= $radius
MySQL latitude and Longitude table setup.
I'm not sure if it works because it's uses a radius variable with a bounding-box function. It's seems to me MBRwithin is a bit simpler, because it doesn't need any argument: Mysql: Optimizing finding super node in nested set tree.
You are using GROUP BY statement together with HAVING, although I don't see anywhere in the query any aggregate functions. I recommend you to re-write the query like this and see if it makes any difference
SELECT * , ROUND( SQRT( POW( ( 69.1 * ( company_branch_lat - 52.4862 ) ) , 2 ) + POW( ( 53 * ( company_branch_lng - - 1.8905 ) ) , 2 ) ) , 1 ) AS distance,
hire_car_day + ( hire_car_day * 0.2 * ! hire_car_incvat ) AS hire_car_day_incvat,
hire_car_addday + ( hire_car_addday * 0.2 * ! hire_car_incvat ) AS hire_car_addday_incvat,
hire_car_week + ( hire_car_week * 0.2 * ! hire_car_incvat ) AS hire_car_week_incvat,
hire_car_weekend + ( hire_car_weekend * 0.2 * ! hire_car_incvat ) AS hire_car_weekend_incvat
FROM hire_car
LEFT JOIN company_branch ON company_branch_id = hire_car_branchid
LEFT JOIN hire_cartypelink ON hire_cartypelink_carhireid = hire_car_id
LEFT JOIN users ON company_branch_userid = user_id
WHERE ROUND( SQRT( POW( ( 69.1 * ( company_branch_lat - 52.4862 ) ) , 2 ) + POW( ( 53 * ( company_branch_lng - - 1.8905 ) ) , 2 ) ) , 1 ) <= 30
ORDER BY CASE hire_car_day_incvat
WHEN 0
THEN 40000
ELSE hire_car_day_incvat
END , distance ASC
LIMIT 0 , 30

Group by with diff percentage MySQL

I have been trying to query the increase percentage of a product grouped in certain range depending on the actual increase for each run. So for example I have the following table schema
Now, if I query the increase percent I would get something like:
SELECT *, (((newPrice - price)/price) * 100 ) as PERCENTAGE FROM Product
What Im trying to obtain is to group the values within a particular range depending on the calculated increase. So for this run something like this:
| Range | #COUNT |
| 0-10% | 3 |
| 30-40% | 1 |
and more ranges and products if existing
I have tried:
Select *, COUNT(idProduct) AS COUNT FROM Product
where (((newPrice - price)/price) * 100 ) BETWEEN 0 AND 10
which gives me:
But I need to configure the query in a way it can determine a reasonable percent range (i.e Without hard coding the values BETWEEN 0 AND 10) and group the values in there for different runs. Any ideas?
Thank you!
product table
CREATE TABLE `product` (
`idproduct` INT NOT NULL ,
`description` VARCHAR(45) NULL ,
`price` INT NULL ,
`newPrice` INT NULL ,
PRIMARY KEY (`idproduct`) );
You could group by 10% percentage bands:
SELECT floor((newPrice - price) / price * 10) * 10 as LowerBound
, floor((newPrice - price) / price * 10) * 10 + 10 as HigherBound
, count(*) as Count
FROM Product
GROUP BY
floor((newPrice - price) / price * 10)
Multiplying by 10 and rounding down should create one group per 10 percentage points.
SELECT
r.RangeValue,
COUNT(*) AS CountofProducts
FROM (SELECT
CASE WHEN (((newPrice - price)/newPrice) * 100 ) <= 10 THEN
'0-10%'
WHEN (((newPrice - price)/newPrice) * 100 ) <= 20 THEN
'10-20%'
WHEN (((newPrice - price)/newPrice) * 100 ) <= 30 THEN
'20-30%'
WHEN (((newPrice - price)/newPrice) * 100 ) <= 40 THEN
'30-40%'
ELSE
'40+%'
END AS RangeValue
FROM Product) r
GROUP BY r.RangeValue
Its simple
SELECT count(*) as items, (((newPrice - price)/newPrice) * 100 ) as PERCENTAGE ,
IF (
((newPrice - price)/newPrice* 100) >=0 &&
((newPrice - price)/newPrice* 100) <=10 ,
"0 - 10%" ,
IF (
((newPrice - price)/newPrice* 100) >=11 &&
((newPrice - price)/newPrice* 100) <=30 ,
"10 - 30%",
so on....
)
) AS 'range'
FROM Product
group by range
Basically, you have to use nested if() statements and inside them you put the ranges.
Then give it a meaningful alias. You can then group by the alias.