MYSQL find max value - mysql

Take a MYSQL table like this :
id:prod1, priceA:10, priceB:20, priceC:30,priceD:18,...
id:prod2, priceA:22, priceB:20, priceC:30,priceD:78,...
id:prod3, priceA:4, priceB:20, priceC:30,priceD:19,...
I'm trying to select all ids where priceA is the lowest of the 3 prices, in this case, prod1 and prod3
I have tried to use max() but it acts only on one field.
I was thinking of something along the lines of :
SELECT id from table WHERE priceA < priceB AND priceA < priceC..., but in real life, there's 20 prices columns so it's highly unpractical...
Could anyone tell me if there is a function I don't know about that would simplify my query?

You can consider using the LEAST function. Still, you would have to list all the price columns, as below:
SELECT id
FROM table
WHERE priceA = LEAST(priceA, priceB, priceC);
Please see the SQL Fiddle.

Related

MySQL Sum and Case Query

I create a ReportViewer with VB.NET connecting to a MySQL database. The data appears like below.
IdProduct Quantity TotalPrice OrderDate
0001 1 10 29/09/2014
0002 2 40 29/09/2014
0001 4 40 29/09/2014
0001 2 20 29/09/2014
0001 2 20 29/09/2014
Based on the records above, I'd like the result to appear like below
0001 0002
9 2
90 40
What is Query Sum Case the best use here? Thanks in advance.
NOTE: It's not possible for a query to "dynamically" alter the number or datatype of the columns returned, those must be specified at the time the SQL text is parsed.
To return the specified resultset with a query, you could do something like this:
SELECT SUM(IF(t.IdProduct='0001',t.Quantity,NULL)) AS `0001`
, SUM(IF(t.IdProduct='0002',t.Quantity,NULL)) AS `0002`
FROM mytable t
UNION ALL
SELECT SUM(IF(t.IdProduct='0001',t.TotalPrice,NULL)) AS `0001`
, SUM(IF(t.IdProduct='0002',t.TotalPrice,NULL)) AS `0002`
FROM mytable t
Note that the datatypes returned by the two queries will need to be compatible. This won't be a problem if Quantity and TotalPrice are both defined as integer.
Also, there's no specific guarantee that the "Quantity" row will be before the "TotalPrice" row; we observe that behavior, and it's unlikely that it will ever be different. But, to have a guarantee, we'd need an ORDER BY clause. So, including an additional discriminator column (a literal in the SELECT list of each query), that would give us something we could ORDER BY.
Note that it's not possible to have this single query dynamically create another column for IdProduct '0003'. We'd need to add that to the SELECT list of each query.
We could do this in two steps, using a query to get the list of distinct IdProduct, and then use that to dynamically create the query we need.
BUT... with all that said... we don't want to do that.
The normative pattern would be to return Quantity and TotalPrice as two separate columns, along with the IdProduct as another column. For example, the result returned by this statement:
SELECT t.IdProduct
, SUM(t.Quantity) AS `Quantity`
, SUM(t.TotalPrice) AS `TotalPrice`
FROM mytable t
GROUP BY t.IdProduct
And then the client application would be responsible for transforming that resultset into the desired display representation.
We don't want to push that job (of transforming the result into a display representation) into the SQL.
select idproduct, sum(quantity), sum(totalprice)
from your_table
group by idproduct

Order number and strings putting strings last

I am trying to make a SQL statement that selects and orders numbers in DESC but put all strings last
so mysql is:
"SELECT * FROM posts ORDER BY price DESC"
and that gives me something like
test
best offer
6000
100
10
what I want is:
6000
100
10
test
best offer
or (doesnt matter)
6000
100
10
best offer
test
SELECT * FROM posts
ORDER BY price * 1 DESC
SQLFiddle demo
I think want you actually want is:
SELECT * FROM t ORDER BY value ASC;
which returns:
10
100
6000
best offer
test
SQL Fiddle
If you generally do not care about performance, you can do something like this:
SELECT * FROM posts
ORDER BY
CASE CAST(price AS int) WHEN 0 THEN ' ' ELSE price END DESC,
price ASC;
You might need the casts to int depending on your database.
You can also fiddle with the first expression to get the results you want. The point is that you have to sort first by whether it's a number or not and then the actual content.
The problem is that this you can't use any indexes this way. If you are allowed to change the database structure, it would be better to split the data into two columns. An int column with the price and a varchar column with the price description (in which case the first column is NULL). Then you can do faster queries.

How to explode in MySQL and use it in the WHERE clause of the query - MySQL

I have a database table as below.
Promotion_Table
id(INT), promotion_name(VARCHAR),......, bungalow_ids(VARCHAR)
We can add a promotion for a bungalow(23). So a row is added with the bungalow id as below.
1, My Promotion, ........, 23
But if I single a promotion is added for a multiple bungalows(23,42) all ids are saved in the bungalow_ids column as below.
2, My Promotion 2, ........, 23 | 42
If a user search for promotion which are for specific bungalow(23) All promotions for the bungalow should be shown in the result.
I have a query as below.
SELECT * FROM Promotion_Table WHERE bungalow_ids = '23'
It only gets 1 rows. But actually 2nd row should be shown too since there is a offer. I can nt use LIKE since it gets wrong records.
Given that I have already referred below links but I have no idea how to use them in the query.
Can you split/explode a field in a MySQL query?
Equivalent of explode() to work with strings in MySQL
How can I fix this? How can I explode the column data and use it in the query ?
Use , to separate the string and try this query
select * from promotion_table where FIND_IN_SET("23",bungalow_ids)
http://sqlfiddle.com/#!2/7bbcb/1
The previous Answer is the right decision but if you insist in your model.
Probably what you want to do is:
SELECT *
FROM Promotion_Table
WHERE bungalow_ids = '23'
OR bungalow_ids LIKE '23,*'
OR bungalow_ids LIKE '*,23'
OR bungalow_ids LIKE '*,23,*'
this assuming the numbers are separated by ",".
But this is the wrong way, make the changes to the DB as stated in the previous answer.
you need to reformat your DB schema.
you need to construct 2 tables one for promotions and one for bangalows.
like below:
promotions: Promotion_id(int), Promotion_desc
bangalows: Bangalow_id(int), Promotion_id(int)
tables example:
promotion :
1 myPromotion
2 secondPromotion
bangalows:
1 1
2 2
3 1
4 1
once you create above two tables, the following query will work and returns 1,3,4:
SELECT Bangalow_id FROM Promotion_Table WHERE bungalow_id = '1'

Can SQL query do this?

I have a table "audit" with a "description" column, a "record_id" column and a "record_date" column. I want to select only those records where the description matches one of two possible strings (say, LIKE "NEW%" OR LIKE "ARCH%") where the record_id in each of those two matches each other. I then need to calculate the difference in days between the record_date of each other.
For instance, my table may contain:
id description record_id record_date
1 New Sub 1000 04/14/13
2 Mod 1000 04/14/13
3 Archived 1000 04/15/13
4 New Sub 1001 04/13/13
I would want to select only rows 1 and 3 and then calculate the number of days between 4/15 and 4/14 to determine how long it took to go from New to Archived for that record (1000). Both a New and an Archived entry must be present for any record for it to be counted (I don't care about ones that haven't been archived). Does this make sense and is it possible to calculate this in a SQL query? I don't know much beyond basic SQL.
I am using MySQL Workbench to do this.
The following is untested, but it should work asuming that any given record_id can only show up once with "New Sub" and "Archived"
select n.id as new_id
,a.id as archive_id
,record_id
,n.record_date as new_date
,a.record_date as archive_date
,DateDiff(a.record_date, n.record_date) as days_between
from audit n
join audit a using(record_id)
where n.description = 'New Sub'
and a.description = 'Archieved';
I changed from OR to AND, because I thought you wanted only the nr of days between records that was actually archived.
My test was in SQL Server so the syntax might need to be tweaked slightly for your (especially the DATEDIFF function) but you can select from the same table twice, one side grabbing the 'new' and one grabbing the 'archived' then linking them by record_id...
SELECT
newsub.id,
newsub.description,
newsub.record_date,
arc.id,
arc.description,
arc.record_date,
DATEDIFF(day, newsub.record_date, arc.record_date) AS DaysBetween
FROM
foo1 arc
, foo1 newsub
WHERE
(newsub.description LIKE 'NEW%')
AND
(arc.description LIKE 'ARC%')
AND
(newsub.record_id = arc.record_id)

MySQL compare data from date ranges prior to the current row and count() them

This is in reference to the still-open question here - I want to try to approach it differently.
I have a MySQL table with two pieces of information: order_date and email_address. This is exhaustive and non-distinct, meaning that there are duplicates if someone happened to make more than one purchase per-day.
I need to get the following report in as few queries as possible, hopefully one:
YYYY-MM | number_emails_this_month | numer_emails_repeated_prior
Where some sample output from the query result would look like this:
YYYY-MM | number_emails_this_month | numer_emails_repeated_prior
2010-02 23423 1231
2010-03 4422 2234
2010-04 1424 650
Any help is greatly appreciated!
I am not sure I understand what is number_emails_repeated_prior. If you could post a short example of data and a corresponding example of wanted results it would be helpful.
Taking a guess about what you are aiming for, to get the number of emails from a specific user per month all you need is:
SELECT DATE_FORMAT(order_date, '%Y-%m') as `YYYY-MM`,
COUNT(email_address) as `number_emails_this_month `
FROM table_name
WHERE email_address = 'some#address'
GROUP BY 1
ORDER BY 1
This question was answered in a subsequent related question here:
MySQL Subquery with User-Defined Variables
Ultimately the solution was to create a table with the ranges as-requested and join on that instead of using a subquery to define the ranges in question. In retrospect, use of the user-defined vars in MySQL aided the search for the subquery-less solution.