Suppose I have INT column, and I am using -1 to signify that no data was available at the time of the INSERT. I'd like to get an AVG of all values of this column that are 0 or larger.
Is this possible?
Thanks.
I forgot to mention that I'm doing this alongside other AVG's, so it's select avg(a), avg(b), avg(d) from tab; ... so I can't use b>0... because the others need to use the row data regardless of this one column's data being -1.
It occurs to me though that I could augment the AVG result e.g. if it would normally be (4 + 5 + -1 + -1 + 6) / 5. But if I know how many -1's there are I could "fix" the result to exclude them.
This might help:
If you want to ignore the -1 values from the average:
SELECT AVG(`a`), AVG(IF(`b` > -1, `b`, NULL)), AVG(`c`) FROM `t`;
If you want to consider the -1 values in the average:
SELECT AVG(`a`), AVG(IF(`b` > -1, `b`, 0)), AVG(`c`) FROM `t`;
I've assumed dummy column- and table- names and assumed column b as the one for which you want to consider only values >= 0. Please feel free to put in names as per your schema.
SELECT AVG(`field`) FROM `table` WHERE `field` >= 0
Please use this:
SELECT AVG(Column),
SUM(IF(Column>0))/COUNT(IF(Column>0))
FROM Table
Could you do something as such
SUM(column) / COUNT(*) as Average FROM 'table' WHERE 'column' >= 0
Related
This is my input table
but i want to get this table
Explaination:
I want to subtract value of segmeted 14/10/22 - 7/10/22 that means (28930-28799)
how could i get this kindly help me to figure it out. I cant format it properly.
This is my table
and i want to subtract value column subtraction by SEGMENTED_DATE wise
like (14th october value - 7th october value) that means (28930-28799)
the segment table is created by bellow query
select segment ,count(distinct user_id)as value,SEGMENTED_DATE from weekly_customer_RFM_TABLE
where segment in('About to sleep','Promising','champion','Loyal_customer',
'Potential_Loyalist','At_Risk','Need_Attention','New_customer',
'Hibernating','Cant_loose')
and SEGMENTED_DATE between '2022-10-07' and '2022-10-28'
Group by segment,SEGMENTED_DATE
I want this table as output
This is only value difference only Segment_date wise
The sample data of results table is not correct.
You said that
"I want to subtract value of segmeted 14/10/22 - 7/10/22 that means (28930-28799) " but this gives 131 not 233.
You said that "while in you example and value 21/10/22 -14/10/22 that means(29137-28930)" but this gives 207 not 190.
How did you calculate the value 344 in the first row?
The following query will produce the format you want but without the first row as it is not clear to me how did you calculate it. I put xxx AS your table name. The query is based on using variables.
SET #Prev = 0;
SET #i = 0;
SELECT CONCAT('Week', C, '-', 'Week', C-1) AS Change_Time, Segment, Prev AS Value FROM (
SELECT `Value`- #Prev AS Prev, Segment, #Prev :=`Value` AS V, #i:=#i+1 AS C, Segmentd FROM xxx
) AS t WHERE C> 1;
The results will be :
This query is suitable for MySQL engine and will not run on SQL server.
Edit1:
Here is some explanation:
In inner query I used variables for two reasons:
I need a counter (#i) so I can know week index like (week1, week2, ...). This counter will increase with each record by (#i:=#i+1).
I need to know value of previous record so I used (#Prev :=Value) to save that value then I can subtract it from Value in current record (Value- #Prev) AS Prev.
I started with initial values (SET #Prev = 0;) Assuming no previous values and (SET #i = 0;) because #i will increased to (1) at first record.
In outer query I converted (#i named C) to (week(i)-week(i-1)) week1-week0, week2-week1, ....... and removed first record because it will display wrong data.
I can help improving the query if you show me some real data.
Edit2:
According to you last modification at 2022/10/07 the query will be :
SET #Prev = 0;
SET #S = 0;
SELECT Segment, Diffirence, SEGMENTED_DATE FROM (
SELECT
`Value`- #Prev AS Diffirence,
POSITION(#S IN Segment) AS NotFirst,
#Prev := IF(#S=Segment, `Value`, 0) AS `Value`,
#S := Segment AS Segment,
SEGMENTED_DATE
FROM test
) AS t WHERE NotFirst> 0;
You may perform a self join as the following:
SET #rn=1;
SELECT T.segment,
D.value-T.value AS Difference,
D.segmented_date,
FROM table_name T JOIN table_name D
ON D.segmented_date=T.segmented_date + INTERVAL 7 DAY
AND D.segment=T.segment
ORDER BY T.segment, D.segmented_date
See a demo.
Hello I am looking to add a column called MMV that will identify the first row before and after the current row I’d that is greater than the value. If there is no applicable row use max and mins of table size. The result will be the MINIMUM of the two calculations.
The picture below shows orders 19 - 31 but notes based on table having a table of 50 entries. Just a quick example on excel.
Hopefully somebody can help.
Thanks in advance.
One idea is to use correlated subqueries.
Either with two of them and then taking the lesser value with LEAST:
select
idorder,
ordervalue,
least(
idorder -
(
select count(*)
from mytable m1
where m1.ordervalue > m.ordervalue
and m1.idorder < m.idorder
),
(
select count(*)
from mytable m1
where m1.ordervalue > m.ordervalue
and m1.idorder > m.idorder
) -
idorder
) as mmv
from mytable m;
Or in one subquery with conditional aggregation (i.e. counting / adding up based on conditions):
select
idorder,
ordervalue,
(
select least(m.idorder - sum(m1.idorder < m.idorder),
sum(m1.idorder > m.idorder) - m.idorder)
from mytable m1
where m1.ordervalue > m.ordervalue
) as mmv
from mytable m;
This second query makes use of MySQL's true = 1, false = 0.
I Have a Table which has a Column of Type 'varchar' of size 255 char. The sample values look like this
Test/16-17/1
Test/16-17/2
test/16-17/10
Test/16-17/11
Test/16-17/20
Test/16-17/22
However on Using ORDER BY clause in the Select the Result is in following order
Test/16-17/1
Test/16-17/10
Test/16-17/11
Test/16-17/2
Test/16-17/20
Test/16-17/22
How Do I get the Result in the Chronolgical Order of Numerical Values in the End of the values?
If it follows the same / and have 2 digits in the column, you can use
order by right(vtest,2)
ORDER BY CONVERT( RIGHT( test_column_name,
LENGTH(test_column_name) - LOCATE('/', REVERSE(test_column_name))
), UNSIGNED INTEGER);
OR
ORDER BY CONVERT(substring_index(id, '/', -1), UNSIGNED INTEGER);
For your particular examples, you can order by length and then the value:
order by length(vtest), vtest
I don't know if this will work for other rows not in the question.
This will work no matter what the first 10 characters are:
ORDER BY CONCAT(LEFT(vtest, 10), CASE WHEN LENGTH(vtest) = 12
THEN CONCAT(0,RIGHT(vtest,1))
ELSE RIGHT(vtest,2) END)
Select the end part after the last "/", and then multiply it by 1 to convert it to a number:
ORDER BY RIGHT(test_column, LENGTH(test_column) - LOCATE('/', REVERSE(test_column))) * 1;
OR
ORDER BY substring_index(id, '/', -1) * 1;
This is basically the same as the answer by Keyur Panchal, but it uses implicit conversion which has several advantages: 1) Easier to read/write, 2) You don't need to worry about the type to convert to, 3) It ignores characters if they happen to exist in some values.
i have payment table fields
update reason and amount & total field are change negative
UPDATE payment
SET reason = 'refund'
WHERE uid =5 AND date = '2012-05-01' AND accid =2
update single query is it possible?
If I understand you correctly, you also want to set amount column to positive value along with the above statement.
You can use something like this
UPDATE payment
SET reason = 'refund', amount = amount * -1, total = total * -1
WHERE uid =5 AND date = '2012-05-01' AND accid =2
Use ABS(amount) if you wish to always get the positive integer.
SELECT ABS(5);
will output 5
SELECT ABS(-5);
will also output 5
When I looked for the solution, the offered suggestion corrupted my result:
SELECT #TotalAmount:=( SELECT FORMAT(SUM(Amount), 4) FROM MPPayment WHERE PaymentBatchID = 6 and CompanyID=3);
Proper result:
After formatting:
SELECT #TotalAmount:=( SELECT FORMAT(SUM(Amount), 4) FROM MPPayment WHERE PaymentBatchID = 6 and CompanyID=3);
SELECT #TotalAmount * -1;
Probably doesn't work well with formatting.
Another solution is to subtract your digit from zero:
SELECT #TotalAmount:=( SELECT SUM(Amount) FROM MPPayment WHERE PaymentBatchID = 6 and CompanyID=3);
select FORMAT((0 - #TotalAmount), 4 );
To avoid the corruption of the the result I described above, I make formatting at the end of the operation. The result is fine then:
Works also with multiplication by -1:
SELECT #TotalAmount:=( SELECT SUM(Amount) FROM MPPayment WHERE PaymentBatchID = 6 and CompanyID=3);
select FORMAT(( #TotalAmount *-1), 4 );
I'm having trouble with calculating the median of a list of values, not the average.
I found this article
Simple way to calculate median with MySQL
It has a reference to the following query which I don't understand properly.
SELECT x.val from data x, data y
GROUP BY x.val
HAVING SUM(SIGN(1-SIGN(y.val-x.val))) = (COUNT(*)+1)/2
If I have a time column and I want to calculate the median value, what do the x and y columns refer to?
I propose a faster way.
Get the row count:
SELECT CEIL(COUNT(*)/2) FROM data;
Then take the middle value in a sorted subquery:
SELECT max(val) FROM (SELECT val FROM data ORDER BY val limit #middlevalue) x;
I tested this with a 5x10e6 dataset of random numbers and it will find the median in under 10 seconds.
This will find an arbitrary percentile by replacing the COUNT(*)/2 with COUNT(*)*n where n is the percentile (.5 for median, .75 for 75th percentile, etc).
val is your time column, x and y are two references to the data table (you can write data AS x, data AS y).
EDIT:
To avoid computing your sums twice, you can store the intermediate results.
CREATE TEMPORARY TABLE average_user_total_time
(SELECT SUM(time) AS time_taken
FROM scores
WHERE created_at >= '2010-10-10'
and created_at <= '2010-11-11'
GROUP BY user_id);
Then you can compute median over these values which are in a named table.
EDIT: Temporary table won't work here. You could try using a regular table with "MEMORY" table type. Or just have your subquery that computes the values for the median twice in your query. Apart from this, I don't see another solution. This doesn't mean there isn't a better way, maybe somebody else will come with an idea.
First try to understand what the median is: it is the middle value in the sorted list of values.
Once you understand that, the approach is two steps:
sort the values in either order
pick the middle value (if not an odd number of values, pick the average of the two middle values)
Example:
Median of 0 1 3 7 9 10: 5 (because (7+3)/2=5)
Median of 0 1 3 7 9 10 11: 7 (because 7 is the middle value)
So, to sort dates you need a numerical value; you can get their time stamp (as seconds elapsed from epoch) and use the definition of median.
Finding median in mysql using group_concat
Query:
SELECT
IF(count%2=1,
SUBSTRING_INDEX(substring_index(data_str,",",pos),",",-1),
(SUBSTRING_INDEX(substring_index(data_str,",",pos),",",-1)
+ SUBSTRING_INDEX(substring_index(data_str,",",pos+1),",",-1))/2)
as median
FROM (SELECT group_concat(val order by val) data_str,
CEILING(count(*)/2) pos,
count(*) as count from data)temp;
Explanation:
Sorting is done using order by inside group_concat function
Position(pos) and Total number of elements (count) is identified. CEILING to identify position helps us to use substring_index function in the below steps.
Based on count, even or odd number of values is decided.
Odd values: Directly choose the element belonging to the pos using substring_index.
Even values: Find the element belonging to the pos and pos+1, then add them and divide by 2 to get the median.
Finally the median is calculated.
If you have a table R with a column named A, and you want the median of A, you can do as follows:
SELECT A FROM R R1
WHERE ( SELECT COUNT(A) FROM R R2 WHERE R2.A < R1.A ) = ( SELECT COUNT(A) FROM R R3 WHERE R3.A > R1.A )
Note: This will only work if there are no duplicated values in A. Also, null values are not allowed.
Simplest ways me and my friend have found out... ENJOY!!
SELECT count(*) INTO #c from station;
select ROUND((#c+1)/2) into #final;
SELECT round(lat_n,4) from station a where #final-1=(select count(lat_n) from station b where b.lat_n > a.lat_n);
Here is a solution that is easy to understand. Just replace Your_Column and Your_Table as per your requirement.
SET #r = 0;
SELECT AVG(Your_Column)
FROM (SELECT (#r := #r + 1) AS r, Your_Column FROM Your_Table ORDER BY Your_Column) Temp
WHERE
r = (SELECT CEIL(COUNT(*) / 2) FROM Your_Table) OR
r = (SELECT FLOOR((COUNT(*) / 2) + 1) FROM Your_Table)
Originally adopted from this thread.