MySQL: Standard deviation average within a table - php

Here's how one of my tables are structured:
id | group | val1 | val2 | val3
1 | 1 | 22 | 23 | 60
2 | 1 | 40 | 60 | 80
3 | 2 | 50 | 5 | 70
4 | 2 | ...
5 | 2 |
6 | 3 |
...
In my PHP-document I'm calculating the standard deviation by using val1+val2+val3 etc. per row WHERE group equals the one I'm displaying.
Now I want to know, by using MySQL, what the standard deviation is per row and the average across a group. (row1stddev+row2stddev+...)/n
I've tried using subqueries, but all I can achieve is getting a single value. I think I have a lack of understanding how the the built in standard deviation functions in MySQL actually works with multiple values.
EDIT.
This is the two things I'm looking for:
id | group | stddev
1 | 1 | 21,65641
2 | 1 | 20
3 | 2 | 33,29164
4 | 2 | ...
5 | 2 |
6 | 3 |
And average by group (average of all stddev):
group | avg_stddev
1 | 20,828205
2 | ...
3 | ...
The point of this is that I want to know in which group the difference is largest.

Since mysql native function STDDEV_POP accepts only column, you have to trick it by using temporary table, that will have one column with all values (that matters to standard deviation) in a row, for that use UNION ALL with 3 SELECTS, each for one meaningful column, and group it by row id.
SELECT
id,
STDDEV_POP(val) AS row_stddev
FROM (
SELECT id, val1 AS val FROM stdev_table
UNION ALL
SELECT id, val2 AS val FROM stdev_table
UNION ALL
SELECT id, val3 AS val FROM stdev_table
) tmp0
GROUP BY id
you can also select additional column - group and create another temporary table to select average from it:
SELECT
id_group,
AVG(row_stddev) AS group_avg
FROM (
SELECT
id,
id_group,
STDDEV_POP(val) AS row_stddev
FROM (
SELECT id, id_group, val1 AS val FROM stdev_table
UNION ALL
SELECT id, id_group, val2 AS val FROM stdev_table
UNION ALL
SELECT id, id_group, val3 AS val FROM stdev_table
) tmp0
GROUP BY id
) tmp1
GROUP BY id_group

If I understood you correctly you should create View
CREATE VIEW view_name AS SELECT val1, val2, val3, val1 + val2 + val 3 / 3 AS average FROM tablename;
and then just SELECT * FROM view_name to get you values.

Related

sum() by group sql

I have data in a row with same value and id example below:
table_name: test
id | amount
1 | 100
1 | 100
1 | 100
2 | 150
2 | 150
2 | 150
3 | 200
3 | 200
3 | 200
4 | 250
4 | 250
4 | 250
I want to sum only one row in each idusing sql below is not working it sum all the row.
"select *, sum(amount) as total from test group by id";
my question is that possible to sum() only one row each id?
desired output?(edit)
id | amount
1 | 100
2 | 150
3 | 200
4 | 250
total : 700
my question is that possible to sum() only one row each id?
I interpret this as your wanting one value, with a single row from each group. One method is two levels of aggregation:
select sum(amount)
from (select id, max(amount) as amount
from test
group by id
) t;
Looks like you need this
select *,sum(amount) from (select distinct * from test) as t group by id
Try:
select id, sum(amount)/count(*) as total
from test
group by id
Result:
| id | total |
|----|-------|
| 1 | 100 |
| 2 | 150 |
| 3 | 200 |
| 4 | 250 |
try this using subquery-
select sum(amount) from (select distinct id,amount from company7) as tempTable
Try this
create table #test
(id int, amount int)
insert into #test values (1,100),(1,100),(1,100),(2,150),(2,150),(3,200),(3,250)
;with cte
as
(
select sum(distinct amount) as damount,id
from #test
group by id
)
select sum(damount) as total from cte
For other DBMSs than SQL Server
select sum(damount) as total from (select sum(distinct amount) as damount,id
from test
group by id) as it

How to get unique result from below entry?

plan_id | elementclass | table_no | ress_id | UserID | Status
1 | elementclass1 | 1 | 0 | 0006100022 | N
1 | elementclass1 | 1 | 2 | 0006100022 | N
1 | elementclass2 | 2 | 0 | 0006100021 | N
1 | elementclass4 | 3 | 0 | 0006100023 | N
in above row I am expecting as this
if row is having same elementclass,table_no but different ress_id in that condition only take that row which is non zero.If with above condition tow rows having 0 it can take any row .if both rows have non zero then also it can take any one.
Now
for rest of others it can take values with 0.We can use group by to plan_id as there may be multiple plans.
Desired result
plan_id | elementclass | table_no | ress_id | UserID | Status
1 | elementclass1 | 1 | 2 | 0006100022 | N
1 | elementclass2 | 2 | 0 | 0006100021 | N
1 | elementclass4 | 3 | 0 | 0006100023 | N
Please help.
thanks
SELECT * FROM TableName a
WHERE a.ress_id = (SELECT MAX(b.ress_id) FROM TableName b WHERE b.table_no = a.table_no)
GROUP BY a.plan_id,a.table_no
This gives you:
1 result per plai_id and table_no
each result has biggest ress_id in it
First get the maximum ress id per element class. Then select the related records. There may be duplicates. Hence group by element class and ress id.
The following statement does not precisely do what you asked for, but maybe it suffices. In case of a tie you won't get one of the records, but one of the records' plan ids, one of the records' table nos, one of the records' user ids and one of the records' statusses. So the user id may be taken from one record and the status from another when elementclass and ress_id are equal.
select plan_id, mytable.elementclass, table_no, mytable.ress_id, userid, status
from mytable
join
(
select elementclass, max(ress_id) as max_ress_id
from mytable
group by elementclass
) agg on agg.elementclass = mytable.elementclass and agg.max_ress_id = mytable.res_id
group by mytable.elementclass, mytable.ress_id;
(It is possible to write a statement to access complete records in case of ties, but this is much more complicated - at least in MySQL.)
Try this:
SELECT T1.*
FROM TableName T1 JOIN
(SELECT elementclass,table_no,MAX(ress_id) as ress_id
FROM TableName
GROUP BY elementclass,table_no
)T2 ON T1.elementclass=T2.elementclass AND T1.table_no=T2.table_no AND T1.ress_id=T2.ress_id
Explanation:
Here, we are creating a temporary table T2 with maximum of ress_id for each elementclass and table_no. Then we join this table with the original table with these 3 fields and select all records from the original table T1.
Result:
PLAN_ID ELEMENTCLASS TABLE_NO RESS_ID USERID STATUS
-------------------------------------------------------------------
1 elementclass1 1 2 0006100022 N
1 elementclass2 2 0 0006100021 N
1 elementclass4 3 0 0006100023 N
See result in SQL Fiddle.

select the database, getting all the maximum values of a column

I have the following table:
id | value | data | v
1 | val1 | dat1 | 1
2 | val1 | dat2 | 2
3 | val1 | dat3 | 3
4 | val2 | dat4 | 1
What I do is grab the data, each value, which has higher v.
No what I mean ..
Sql output I would like:
id | value | data | v
3 | val1 | dat3 | 3
4 | val2 | dat4 | 1
You need to identify the max value in a subquery and then join against the constant element
Fiddle
select *
from
Table1
join
(select max(v) MAXV, value from Table1 group by value) T
on T.MAXV = Table1.v and T.value=Table1.value
As gillyspy already commented, what you need is a subquery that returns the correct values. Check this code:
SELECT id, table1.value, data, v
FROM Table1
JOIN (SELECT MAX(v) MAXV, value
FROM Table1
GROUP BY value
) T ON T.MAXV = Table1.v
AND T.value = Table1.value;

how to implement a query so that i get the result as required

I have a table with these values.
I want to query this table with limit of 5 but i want total row always to be part of resultset.
Table Description:
id desc value
1 A 100
2 B 200
3 C 300
4 D 400
5 E 500
6 F 600
7 G 700
8 H 800
9 I 900
10 Total 1000
i want to know whether its possible.
Like this:
SELECT id, `desc`, value FROM table
UNION ALL
SELECT MAX(id), 'Total', SUM(value) FROM table;
However, If you need to limit the selection from the table to only 5, you have to use LIMIT inside two subqueries like so:
SELECT id, `desc`, value
FROM
(
SELECT id, `desc`, value FROM table1
ORDER BY id
LIMIT 5
) t
UNION ALL
SELECT MAX(id), 'Total', SUM(value)
FROM
(
SELECT id, `desc`, value FROM table1
ORDER BY id
LIMIT 5
) t;
For your sample data this will give you:
| ID | DESC | VALUE |
----------------------
| 1 | A | 100 |
| 2 | B | 200 |
| 3 | C | 300 |
| 4 | D | 400 |
| 5 | E | 500 |
| 5 | Total | 1500 |
SQL Fiddle Demo
Note that: The Total row will be the sum of all the previous value values, however, in your sample data it is not the total.
That's a little messy in a single query. Maybe you can use a UNION query:
SELECT `id`, `value` FROM `table` LIMIT 5
UNION
SELECT 'Total', SUM(`value`) AS `value` FROM `table`
This will yield 5 rows from the table and a 'Total' row under.
you can alternatively use WITH ROLLUP. but the downside is one column is missing: the ID.
SELECT COALESCE(`desc`, 'TOTAL') `desc`, SUM(`value`) Value
FROM Description
GROUP BY `desc`
WITH ROLLUP
SQLFiddle Demo

PHP mysql Distinct, only load 1 set of ids

I'm trying to get data where order doesn't matter with unique ids. So simply my query would be
SELECT DISTINCT id1, id2 FROM messages ORDER BY date
If i have a database with the following data:
id1 | id2 | date
5 | 6 | 1/2/2011
6 | 5 | 1/1/2011
I would only need to load the column with the newest date because the ids are the same 2 people. Really i have to load ids where one of the ids is yours so my real query right now is
SELECT DISTINCT userid_1, userid_2
FROM messages
WHERE userid_2=$dbid
OR userid_1=$dbid
ORDER BY date
and i get a result as [6 5] [5 9] [9 5] [5 15] [5 6] [5 17]
Results 2 and 3 are the same and 1 and 5 are the same. Really only 4 results should be queried. Thanks!
One option is:
SELECT DISTINCT
if(userid_1 >= userid_2,userid_1, userid_2) AS 'id1',
if(userid_1 >= userid_2,userid_2, userid_1) AS 'id2'
FROM messages
WHERE userid_2=$dbid OR userid_1=$dbid ORDER BY date
This query shows two fields for each record.
The first field will be userid1 if it is bigger or equal to userid2, else will show userid2
The second field has the opposite logic
This makes sure that two similar sets of results will alwas be ordered the same way, so the DISTINCT will regard it as same.
If your goal is to get distinct pairings, you could do the following to get the smaller of the pair always in the left column and the larger into the right, thus ensuring that distinct works:
SELECT DISTINCT
(id1 - ( (id1 - id2) + abs(id1 - id2) ) * .5) as first,
(id2 + ( (id1 - id2) + abs(id1 - id2) ) * .5) as second
FROM messages ORDER BY date;
Since the pairs are always arranged, no need for any pairing functions.
Example
+------+------+--------+------------+
| id1 | id2 | val | pair_date |
+------+------+--------+------------+
| 4 | 5 | test 1 | 2010-12-25 |
| 5 | 4 | test 2 | 2011-10-31 |
| 17 | 50 | test 3 | 2011-07-04 |
| 50 | 17 | test 4 | 2001-01-01 |
+------+------+--------+------------+
If I run this query:
SELECT DISTINCT
(id1 - ( (id1 - id2) + abs(id1 - id2) ) * .5) AS first,
(id2 + ( (id1 - id2) + abs(id1 - id2) ) * .5) AS second
FROM pairs ORDER BY pair_date;
I get:
+-------+--------+
| first | second |
+-------+--------+
| 4.0 | 5.0 |
| 17.0 | 50.0 |
+-------+--------+
2 rows in set (0.00 sec)
Obviously using a boolean has the same effect, is easier to read, and probably is faster, but the above algorithm is handy if you just need to swap two numbers so that one side is always the lesser.
I'm not sure why you would have gotten an error. I'm running my tests directly from the MySQL command line....

Categories