Mysql: subtracting does not let me go below 0 - mysql

So I have a query that looks like this:
select name_of_restaurant, diners - avg(diners)
from table
group by name_of_restaurant;
name_of_restaurant is a VARCHAR(50) and diners is an INT.
what I am expecting it to do is this:
name_of_restaurant diners - avg(diners)
merchant1 -140
merchant2 -200
merchant3 -2
but instead I get:
name_of_restaurant diners - avg(diners)
merchant1 0.0000
merchant2 0.0000
merchant3 0.0000
How can I make it so that I get negative values in my result? What is wrong here? Thanks in advance for any assistance.

The GROUP BY expression that you're using here is malformed. diners is neither part of the grouping nor an aggregate function, so it's technically invalid to refer to it in the SELECT statement, as there may be multiple different values for that column in a single group. MySQL silently ignores this and uses an arbitrary value from the group.
(It's an unfortunate quirk of MySQL that this is even allowed. See "Why does MySQL allow "group by" queries WITHOUT aggregate functions?" for some discussion.)
In any case, from what you're describing here, I don't think you actually want a GROUP BY at all; what it sounds like you're trying to do is compare each row's diners with the overall average, not the average for that row or group. If that's the case, what you'd have to do is something along the lines of:
SELECT
name_of_restaurant,
diners - (SELECT AVG(diners) FROM table)
FROM table

Related

MYSQL subquery count

I have a q MySQL query that finds part numbers and returns the count; I need to figure out how to get the query to output by part number counts
this my query now
select count(partnumber)
from db1
where part number REGEXP '6270|6269|6266'
output part number 30
what I would like is the output to look like this,
part numbers count
6270 | 20
6269 | 10
6266 | 5
If I understand correctly, this is a better way to write the query:
select partnumber, count(*)
from db1 where partnumber in (6270, 6269, 6266)
group by partnumber;
This in expression is not exactly the same as your regular expression (the equivalent regular expression would be '^6270|6269|6266$'). If you really want partial matches, then you should use the regular expression.
For exact matches, in is better because (1) it is standard SQL; (2) the types are correct in the comparison; and (3) it optimizes better.

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

MYSQL find max value

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.

Mysql subquery with sum causing problems

This is a summary version of the problems I am encountering, but hits the nub of my problem. The real problem involves huge UNION groups of monthly data tables, but the SQL would be huge and add nothing. So:
SELECT entity_id,
sum(day_call_time) as day_call_time
from (
SELECT entity_id,
sum(answered_day_call_time) as day_call_time
FROM XCDRDNCSum201108
where (day_of_the_month >= 10 AND day_of_the_month<=24)
and LPAD(core_range,4,"0")="0987"
and LPAD(subrange,3,"0")="654"
and SUBSTR(LPAD(core_number,7,"0"),4,7)="3210"
) as summary
is the problem: when the table in the subquery XCDRDNCSum201108 returns no rows, because it is a sum, the column values contain null. And entity_id is part of the primary key, and cannot be null.
If I take out the sum, and just query entity_id, the subquery contains no rows, and thus the outer query does not fail, but when I use sum, I get error 1048 Column 'entity_id' cannot be null
how do I work around this problem ? Sometimes there is no data.
You are completely overworking the query... pre-summing inside, then summing again outside. In addition, I understand you are not a DBA, but if you are ever doing an aggregation, you TYPICALLY need the criteria that its grouped by. In the case presented here, you are getting sum of calls for all entity IDs. So you must have a group by any non-aggregates. However, if all you care about is the Grand total WITHOUT respect to the entity_ID, then you could skip the group by, but would also NOT include the actual entity ID...
If you want inclusive to show actual time per specific entity ID...
SELECT
entity_id,
sum(answered_day_call_time) as day_call_time,
count(*) number_of_calls
FROM
XCDRDNCSum201108
where
(day_of_the_month >= 10 AND day_of_the_month<=24)
and LPAD(core_range,4,"0")="0987"
and LPAD(subrange,3,"0")="654"
and SUBSTR(LPAD(core_number,7,"0"),4,7)="3210"
group by
entity_id
This would result in something like (fictitious data)
Entity_ID Day_Call_Time Number_Of_Calls
1 10 3
2 45 4
3 27 2
If all you cared about were the total call times
SELECT
sum(answered_day_call_time) as day_call_time,
count(*) number_of_calls
FROM
XCDRDNCSum201108
where
(day_of_the_month >= 10 AND day_of_the_month<=24)
and LPAD(core_range,4,"0")="0987"
and LPAD(subrange,3,"0")="654"
and SUBSTR(LPAD(core_number,7,"0"),4,7)="3210"
This would result in something like (fictitious data)
Day_Call_Time Number_Of_Calls
82 9
Would:
sum(answered_day_call_time) as day_call_time
changed to
ifnull(sum(answered_day_call_time),0) as day_call_time
work? I'm assuming mysql here but the coalesce function would/should work too.

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.