Using MIN() in SET statement MySQL - mysql

I am using MySQL. Lets call a table that I have as Inventory which looks is below:
+----+--------+--------+-------------+----------+
| ID | Price1 | Price2 | TargetPrice | Quantity |
+----+--------+--------+-------------+----------+
| 1 | 12 | 1 | | 0 |
| 2 | 3 | 3 | 3 | 2 |
| 3 | | 4 | | 0 |
| 4 | 2 | 2 | 2 | 2 |
| 5 | 5 | 45 | 5 | 1 |
+----+--------+--------+-------------+----------+
Now, I need to update the TargetPrice to minimum of Price1 and Price2 for any row whose Quantity is 0
I have tried:
UPDATE Inventory SET
TargetPrice= MIN(Price1,Price2)
WHERE Quantity >0
However, MySQL complains about the usage of MIN() function. I know it is expecting MIN() to work on the data contained inside column, rather than taking MIN() of two columns of a specified row.
Anyway to achieve this other than cursors?
EDIT:
Price1 and Price2 can be null or 0 and in all these cases, it should be treated as infinity so that the other price gets to be minimum when compared against it.

Use LEAST instead of MIN:
UPDATE Inventory
SET TargetPrice = LEAST(Price1,Price2)
WHERE Quantity = 0
MIN is an aggregate function operating on a rowset, whereas LEAST operates on the list of arguments passed.
EDIT:
UPDATE Inventory
SET TargetPrice = LEAST(COALESCE(Price1, Price2), COALESCE(Price2, Price1))
WHERE Quantity = 0
You can use COALESCE to handle NULL values.
EDIT2:
You can use NULLIF to handle 0 values:
UPDATE Inventory
SET TargetPrice = LEAST(COALESCE(NULLIF(Price1,0), Price2),
COALESCE(NULLIF(Price2,0), Price1))
WHERE Quantity = 0

Related

How to sum alias fields with date range

I need to show SUM value of alias table that has value of the result from multiplying 2 fields.
Here is asset table:
+----------+-----+------------+
| price | qty | tanggal |
+----------+-----+------------+
| 6775000 | 1 | 2019-03-30 |
| 4760000 | 2 | 2019-03-25 |
| 7800000 | 2 | 2019-04-01 |
| 13599000 | 1 | 2019-03-30 |
+----------+-----+------------+
I've already tried:
SELECT
SUM((price*qty))
AS worth
FROM asset
WHERE DATE(tanggal) >= 2019-03-25 AND DATE(tanggal) <= 2019-03-30
Also using BETWEEN clause like this:
SELECT
SUM((price*qty))
AS worth
FROM asset
WHERE DATE(tanggal) BETWEEN 2019-03-25 AND 2019-03-30
It keeps giving me NULL value, but if I remove the WHERE clause it
works fine and give me value of 45494000. Any ideas?
What about adding single quotes, right know you are only doing a subtraction
SELECT SUM((price*qty)) AS worth
FROM asset
WHERE tanggal >= '2019-03-25' AND tanggal <= '2019-03-30'

Flag the row with the max value in field B based on name field in Field A

I am able to find the row with the maximum value for a Value field in an given set of records with the same name using
Select Name, Max(Value) from table group by Name, Value
which returns to me the record with the highest value but I am looking to turn this into an update so I can
Flag the record with the highest value in a IsMaxValue
For each record in the Name, Value group store the highest value found in a 'MaxValue' field
Simple select version is here:
http://sqlfiddle.com/#!9/ccd32/5
with fields ready for updates as per above if it is possible.
I believe this statement is what you might be looking for:
update maxvalues
join (
Select Color, Max(`Value`) max_value
from MaxValues
group by Color
) a on maxvalues.color = a.color and value = a.max_value
set ismaxrecord = '1', maxrecordid = a.max_value;
Sample SQL Fiddle
Given your sample data the table would look like below after the update:
| Color | Value | IsMaxRecord | MaxRecordID |
|--------|-------|-------------|-------------|
| Orange | 1 | | 0 |
| Orange | 2 | | 0 |
| Orange | 3 | 1 | 3 |
| Black | 30 | 1 | 30 |
| Black | 20 | | 0 |
| Black | 10 | | 0 |

MySQL: optimize query for scoring calculation

I have a data table that I use to do some calculations. The resulting data set after calculations looks like:
+------------+-----------+------+----------+
| id_process | id_region | type | result |
+------------+-----------+------+----------+
| 1 | 4 | 1 | 65.2174 |
| 1 | 5 | 1 | 78.7419 |
| 1 | 6 | 1 | 95.2308 |
| 1 | 4 | 1 | 25.0000 |
| 1 | 7 | 1 | 100.0000 |
+------------+-----------+------+----------+
By other hand I have other table that contains a set of ranges that are used to classify the calculations results. The range tables looks like:
+----------+--------------+---------+
| id_level | start | end | status |
+----------+--------------+---------+
| 1 | 0 | 75 | Danger |
| 2 | 76 | 90 | Alert |
| 3 | 91 | 100 | Good |
+----------+--------------+---------+
I need to do a query that add the corresponding 'status' column to each value when do calculations. Currently, I can do that adding the following field to calculation query:
select
...,
...,
[math formula] as result,
(select status
from ranges r
where result between r.start and r.end) status
from ...
where ...
It works ok. But when I have a lot of rows (more than 200K), calculation query become slow.
My question is: there is some way to find that 'status' value without do that subquery?
Some one have worked on something similar before?
Thanks
Yes, you are looking for a subquery and join:
select s.*, r.status
from (select s.*
from <your query here>
) s left outer join
ranges r
on s.result between r.start and r.end
Explicit joins often optimize better than nested select. In this case, though, the ranges table seems pretty small, so this may not be the performance issue.

mysql - dynamic query depending on multiple grouped other values

In my application there are products and a product-variant-group which has a defined set of properties which a product of this group must declare and the combination of the properties is unique across that product-variant-group.
Example screen from amazon:
In the image the first select menu has all values obviously. The next select menu depends on the previously selected value, and so on.
Those defined group properties have a unique priority assigned to it which in the following derived table equals the property itself.
For a given property/priority and given list of of property/priority-value pairs. I want to retrieve its possible values.
The priorities of the value pairs must be smaller then the given priority.
public String[] getProductVariantGroupValues(int productVariantGroupId, int priority, Map<Integer, String> prevValues);
An example makes it much clearer:
I have an sql statement which lists all product-variant-group properties that related products have defined:
+---------+----------+-------- +
| product | priority | value |
+---------+----------+---------+
| 1 | 1 | Black |
| 1 | 2 | 38 |
| 1 | 3 | Dots |
| 2 | 1 | Black |
| 2 | 2 | 38 |
| 2 | 3 | Stripes |
| 3 | 1 | Yellow |
| 3 | 2 | 40 |
| 3 | 3 | Stripes |
+---------+----------+---------+
Other view for understanding *(priority is arbitrary just for understanding, with this view this would be trivial)*:
+---------+--------+--------+---------+
| product | value1 | value2 | value3 |
+---------+--------+--------+---------+
| 1 | Black | 38 | Dots |
| 2 | Black | 38 | Stripes |
| 3 | Yellow | 40 | Stripes |
+---------+---------------------------+
Call the above method with priority = 3 and prevValues = {(1, Black), (2, 38)} should result in following result array: {Dots, Stripes}.
If black is selected for property/priority 1 and 38 is selected for property/priority 2 the only possible following values for property/priority 3 are {Dots, Stripes}
The example is simplified and an arbitrary number of properties/priority should be supported. The query must be created dynamically to support arbitrary number of lower priority values.
Maybe I should just use the second table appraoch with a fixed set of properties which would make the unique constraint and this query very simple.
If I understand the question correctly, you have a value for priority 1 and for priority 2 and want to get all priority 3 values that match. The following query gets the products:
select product
from t
group by product
having max(case when priority = 1 and value = 'Black' then 1 else 0 end) = 1 and
max(case when priority = 2 and value = 40 then 1 else 0 end) = 1
To get the priority 3 values requires or a clever select statement (assuming priorities are not repeated for a product):
select product, max(case when priority = 3 then value end)
from t
group by product
having max(case when priority = 1 and value = 'Black' then 1 else 0 end) = 1 and
max(case when priority = 2 and value = 40 then 1 else 0 end) = 1
These queries are to give you an idea of how to construct the queries in your code. The generalization should be pretty straightforward.

need explanation for this MySQL query

I just came across this database query and wonder what exactly this query does..Please clarify ..
select * from tablename order by priority='High' DESC, priority='Medium' DESC, priority='Low" DESC;
Looks like it'll order the priority by High, Medium then Low.
Because if the order by clause was just priority DESC then it would do it alphabetical, which would give
Medium
Low
High
It basically lists all fields from the table "tablename" and ordered by priority High, Medium, Low.
So High appears first in the list, then Medium, and then finally Low
i.e.
* High
* High
* High
* Medium
* Medium
* Low
Where * is the rest of the fields in the table
Others have already explained what id does (High comes first, then Medium, then Low). I'll just add a few words about WHY that is so.
The reason is that the result of a comparison in MySQL is an integer - 1 if it's true, 0 if it's false. And you can sort by integers, so this construct works. I'm not sure this would fly on other RDBMS though.
Added: OK, a more detailed explanation. First of all, let's start with how ORDER BY works.
ORDER BY takes a comma-separated list of arguments which it evalutes for every row. Then it sorts by these arguments. So, for example, let's take the classical example:
SELECT * from MyTable ORDER BY a, b, c desc
What ORDER BY does in this case, is that it gets the full result set in memory somewhere, and for every row it evaluates the values of a, b and c. Then it sorts it all using some standard sorting algorithm (such as quicksort). When it needs to compare two rows to find out which one comes first, it first compares the values of a for both rows; if those are equal, it compares the values of b; and, if those are equal too, it finally compares the values of c. Pretty simple, right? It's what you would do too.
OK, now let's consider something trickier. Take this:
SELECT * from MyTable ORDER BY a+b, c-d
This is basically the same thing, except that before all the sorting, ORDER BY takes every row and calculates a+b and c-d and stores the results in invisible columns that it creates just for sorting. Then it just compares those values like in the previous case. In essence, ORDER BY creates a table like this:
+-------------------+-----+-----+-----+-----+-------+-------+
| Some columns here | A | B | C | D | A+B | C-D |
+-------------------+-----+-----+-----+-----+-------+-------+
| | 1 | 2 | 3 | 4 | 3 | -1 |
| | 8 | 7 | 6 | 5 | 15 | 1 |
| | ... | ... | ... | ... | ... | ... |
+-------------------+-----+-----+-----+-----+-------+-------+
And then sorts the whole thing by the last two columns, which it discards afterwards. You don't even see them it your result set.
OK, something even weirder:
SELECT * from MyTable ORDER BY CASE WHEN a=b THEN c ELSE D END
Again - before sorting is performed, ORDER BY will go through each row, calculate the value of the expression CASE WHEN a=b THEN c ELSE D END and store it in an invisible column. This expression will always evaluate to some value, or you get an exception. Then it just sorts by that column which contains simple values, not just a fancy formula.
+-------------------+-----+-----+-----+-----+-----------------------------------+
| Some columns here | A | B | C | D | CASE WHEN a=b THEN c ELSE D END |
+-------------------+-----+-----+-----+-----+-----------------------------------+
| | 1 | 2 | 3 | 4 | 4 |
| | 3 | 3 | 6 | 5 | 6 |
| | ... | ... | ... | ... | ... |
+-------------------+-----+-----+-----+-----+-----------------------------------+
Hopefully you are now comfortable with this part. If not, re-read it or ask for more examples.
Next thing is the boolean expressions. Or rather the boolean type, which for MySQL happens to be an integer. In other words SELECT 2>3 will return 0 and SELECT 2<3 will return 1. That's just it. The boolean type is an integer. And you can do integer stuff with it too. Like SELECT (2<3)+5 will return 6.
OK, now let's put all this together. Let's take your query:
select * from tablename order by priority='High' DESC, priority='Medium' DESC, priority='Low" DESC;
What happens is that ORDER BY sees a table like this:
+-------------------+----------+-----------------+-------------------+----------------+
| Some columns here | priority | priority='High' | priority='Medium' | priority='Low' |
+-------------------+----------+-----------------+-------------------+----------------+
| | Low | 0 | 0 | 1 |
| | High | 1 | 0 | 0 |
| | Medium | 0 | 1 | 0 |
| | Low | 0 | 0 | 1 |
| | High | 1 | 0 | 0 |
| | Low | 0 | 0 | 1 |
| | Medium | 0 | 1 | 0 |
| | High | 1 | 0 | 0 |
| | Medium | 0 | 1 | 0 |
| | Low | 0 | 0 | 1 |
+-------------------+----------+-----------------+-------------------+----------------+
And it then sorts by the last three invisble columns which are discarded later.
Does it make sense now?
(P.S. In reality, of course, there are no invisible columns and the whole thing is made much trickier to get good speed, using indexes if possible and other stuff. However it is much easier to understand the process like this. It's not wrong either.)