Is it possible to create calculation rows from query results in MySQL? - mysql

I am trying to find a way to output a calculation row (or two) of an SQL search query, so I may see the raw results along with a calculation associated to them, either above or under the listing of raw results. For instance, I have the following data:
mysql> select * from data [where condition];
+----+--------+-----+--------+
| id | height | age | weight |
+----+--------+-----+--------+
| 1 | 65.2 | 45 | 45.23 |
| 2 | 63.1 | 47 | 0 |
| 3 | 59.2 | 37 | 38.1 |
| 4 | 59.8 | 39 | 36.4 |
| 5 | 63.4 | 37 | 38.1 |
| 6 | 72.1 | 34 | 2 |
| 7 | 100 | 50 | 20 |
+----+--------+-----+--------+
And what I want is to be able to perform any query to get all or a subset of this data, but have the resulting table give something like the following (with the summary/calculation output separate from the raw data, such as either above or below it):
mysql> query???
+--------+--------+------+--------+
| id | height | age | weight |
+--------+--------+------+--------+
| 1 | 65.2 | 45 | 45.23 |
| 2 | 63.1 | 47 | 0 |
| 3 | 59.2 | 37 | 38.1 |
| 4 | 59.8 | 39 | 36.4 |
| 5 | 63.4 | 37 | 38.1 |
| 6 | 72.1 | 34 | 2 |
| 7 | 100 | 50 | 20 |
+--------+--------+------+--------+
| STDDEV | 13.26 | 5.57 | 17.15 |
| COUNT | 7 | 7 | 7 |
| etc. | etc. | etc. | etc. |
+--------+--------+------+--------+
I've found some approaches such as this (http://www.sqlservercurry.com/2011/06/sql-server-row-summary-column-summary.html) that somewhat do it, but because the calculation acts on all rows it doesn't work well for some calculations (for instance, using stddev results in "0" for everything except the calculation row).
I can create a separate result of calculations such as the following, but it would be nice to have them somehow combined, such as shown above. In addition, the following only outputs one row of calculations, and it would be nice to have several rows of pertinent calculations.
select stddev(height), stddev(age), stddev(weight) from data [where condition];
The point here is to perform any search query and get an auto-generated preview of basic descriptive information from the results (deviations, counts, mean, etc.). Hopefully this can be done directly in SQL, without needing to use another language/API.

Combine your results with union. If you need the results in a particular order, then create a column containing the precedence and order by that column.
select id, height, age, weight, 0 sortorder
from data [where condition]
union all
select 'stdev count', stddev(height), stddev(age), stddev(weight), 1
from data [where condition]
order by sortorder

Related

Precalculate numbers of records for each possible combination

I have a mySQL database table containing cellphones information like this:
ID Brand Model Price Type Size
==== ===== ===== ===== ====== ====
1 Apple A71 3128 A 40
2 Samsung B7C 3128 B 20
3 Apple ZX5 3128 A 30
4 Huawei Q32 2574 B 40
5 Apple A21 2574 A 25
6 Apple A71 3369 A 30
7 Samsung A71 7413 C 40
Now I want to create another table, that would contain counts for every possible combination of the parameters.
Params Count
============================================== =======
ALL 1000000
Brand(Apple) 20000
Brand(Apple,Samsung) 40000
Brand(Apple),Model(A71) 7100
Brand(Apple),Type(A) 6000
Brand(Apple),Model(A71,B7C),Type(A,B) 7
Model(A71) 12514
Model(A71,B7C) 26584
Model(A71),Type(A) 6521
Model(A71),Type(A,B) 8958
Model(A71),Type(A,B),Size(40) 85
And so on for every possible combination. I was thinking about creating a stored procedure (that i would execute periodically), that would perform queries with every existing condition like that, but I am a little stuck on how exactly should it look like. Or is there a better way how to do this?
Edit: the reason why I want to store information like this is to be able to show number of results in filter in client application, like in the picture.
I would like to create index on the Params column to be able to get the Count number for given hash instantly, improving performance.
I also tried querying and caching the values dynamically, but I want to try this approach as well, so I can compare which one is more effective.
This is how I am calculating the counts now:
SELECT COUNT(*) FROM products;
SELECT COUNT(*) FROM products WHERE Brand IN ('Apple');
SELECT COUNT(*) FROM products WHERE Brand IN ('Apple', 'Samsung');
SELECT COUNT(*) FROM products WHERE Brand IN ('Apple') AND Model IN ('A71');
etc.
You can use a ROLLUP for this.
SELECT
model, type, size, COUNT(*)
FROM mytab
GROUP BY 1, 2, 3
WITH ROLLUP
With your sample data, we get the following:
| model | type | size | COUNT(*) |
| ----- | ---- | ---- | -------- |
| A21 | A | 25 | 1 |
| A21 | A | | 1 |
| A21 | | | 1 |
| A71 | A | 30 | 1 |
| A71 | A | 40 | 1 |
| A71 | A | | 2 |
| A71 | C | 40 | 1 |
| A71 | C | | 1 |
| A71 | | | 3 |
| B7C | B | 20 | 1 |
| B7C | B | | 1 |
| B7C | | | 1 |
| Q32 | B | 40 | 1 |
| Q32 | B | | 1 |
| Q32 | | | 1 |
| ZX5 | A | 30 | 1 |
| ZX5 | A | | 1 |
| ZX5 | | | 1 |
| | | | 7 |
The subtotals are present in the rows with null values in different columns, and the total is the last row where all group by columns are null.

mysql concat column from two rows based on a column

Have the following table which i am trying to concat two rows from the 'value' column into one
mysql> select * from table;
+-----+---------+----------+------------------------+
| id | rsvp_id | field_id | value |
+-----+---------+----------+------------------------+
| 181 | 37 | 1 | First |
| 184 | 37 | 4 | Last |
| 187 | 37 | 10 | |
| 190 | 37 | 13 | spicegirls |
| 193 | 37 | 7 | mark#test2.com |
| 196 | 40 | 1 | Brian |
| 199 | 40 | 1 | Smith |
| 202 | 40 | 7 | Brian#test .com |
| 205 | 40 | 10 | BBQ |
+-----+---------+----------+------------------------+
9 rows in set (0.00 sec)
Ideally i'd like to get the following result
rsvp_id | value
======== ========
37 First Last
40 Brian Smith
The query only grabs the rows with field_id=1 then concats the value column and creates a new row with rsvp_id and the concat value.
Also, the field_id column right now and the 1 is an example, i'll have to figure out how to make it work so instead of 1 it takes the condition from a different table.
Basically the above are values for first name and last name. field_id is a foreign_key to a different table.
I've tried searching online and messing with it myself but i wasn't able to merge the two rows into one row.
Thank You.
You have to use grouping and then use GROUP_CONCAT.
Something like this (untested) might work:
SELECT rsvp_id, GROUP_CONCAT(value SEPARATOR ' ')
FROM t
WHERE field_id = 1
GROUP BY rsvp_id
See MySQL docs for details, also to learn about ordering of values etc:
https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_group-concat

Recursive select Mysql

I have one table with example data:
+----+---------+
| id | rede_id |
+----+---------+
| 1 | 0 |
| 2 | 38 |
| 3 | 1 |
| 38 | 1 |
| 40 | 1 |
| 41 | 38 |
| 42 | 38 |
| 43 | 40 |
rede_id means what id some person belongs to. Its a network system.
For example, if I need to check network of id=1, the results needs to be like:
+----+---------+
| id | rede_id |
+----+---------+
| 3 | 1 |
| 38 | 1 |
| 40 | 1 |
| 41 | 38 |
| 42 | 38 |
| 40 | 1 |
And if rede_id of someone is '41' or '42' needs to be on results to. Goes to infinite.
I can have N rede_id with my id, N rede_id with some id that belongs to me and infinite... I need to get all results.
I don't know how to do that... Sincerely no I ideia.
MySQL 8.0 now supports recursive queries, documented here: https://dev.mysql.com/doc/refman/8.0/en/with.html#common-table-expressions-recursive
Before MySQL 8.0, there's no easy solution for querying this type of data.
There are alternative ways of storing the data, to make it easier to query.
See also:
What is the most efficient/elegant way to parse a flat table into a tree?
https://www.slideshare.net/billkarwin/models-for-hierarchical-data

Row combination choices based on condition - MySQL

I have a working SQL query which returns the following results:
What I'm looking to be able to do is for MySQL to calculate the sum of the weight column and present combinations of rows from the above table in which the sum(Weight) <= 300. An example of the expected results using the table above would be:
My questions about this are: is this possible from with MySQL? Would I need to execute multiple SQL queries and how would I be able to produce the results illustrated above? Is it possible to achieve the first table and the combinations from one query?
Disclaimer: I'm not sure how exactly you envision returning 3 result sets from one query, and why there are only three -- (1,4) and (2,3) would also be valid combinations. So, I'll assume it was just a general example, and you want the complete result in some form.
Let's say you have this table (I've added one row to make it more generic, you example would only produce 2-element combinations):
MariaDB [test]> SELECT * FROM t1;
+------+--------+
| id | weight |
+------+--------+
| 1 | 100 |
| 2 | 120 |
| 3 | 200 |
| 4 | 96 |
| 5 | 50 |
+------+--------+
5 rows in set (0.00 sec)
With MariaDB 10.2, you can use a recursive CTE to achieve your goal, e.g.
WITH RECURSIVE comb(id,ids,weights,sumweight) AS (
SELECT
id,
CAST(t1.id AS CHAR) AS ids,
CAST(weight AS CHAR) AS weights,
weight AS sumweight
FROM t1
WHERE weight <= 300
UNION
SELECT
t1.id AS id,
CONCAT(comb.ids,',',t1.id) AS ids,
CONCAT(comb.weights,',',weight) AS weights,
t1.weight + comb.sumweight AS sumweight
FROM t1 JOIN comb ON (comb.id < t1.id)
HAVING sumweight <= 300
) SELECT ids, weights, sumweight FROM comb;
You'll get this:
+-------+------------+-----------+
| ids | weights | sumweight |
+-------+------------+-----------+
| 1 | 100 | 100 |
| 2 | 120 | 120 |
| 3 | 200 | 200 |
| 4 | 96 | 96 |
| 5 | 50 | 50 |
| 1,2 | 100,120 | 220 |
| 1,3 | 100,200 | 300 |
| 1,4 | 100,96 | 196 |
| 1,5 | 100,50 | 150 |
| 2,4 | 120,96 | 216 |
| 2,5 | 120,50 | 170 |
| 3,4 | 200,96 | 296 |
| 3,5 | 200,50 | 250 |
| 4,5 | 96,50 | 146 |
| 1,2,5 | 100,120,50 | 270 |
| 1,4,5 | 100,96,50 | 246 |
| 2,4,5 | 120,96,50 | 266 |
+-------+------------+-----------+
17 rows in set (0.00 sec)
The query above is not perfect, it is just to give an idea of the possible solution. The result seems correct, and you can improve and polish representation according to your needs.
For your second question, "Is it possible to achieve the first table and the combinations from one query?", you didn't say how you got the first table, so it's hard to give a precise example, but in any case it surely should be possible. The most obvious way is to take whatever query you used to get that result set, wrap it into a view, and then use this view instead of t1 table in the above example.

Percentages in MySQL - Between two columns in the same table

I have a MySQL Table that looks like this:
Name | Pass | Fail | Pass Percent | Fail Percent
Abdy | 20 | 5 | |
Bob | 10 | 5 | |
Cantona | 40 | 10 | |
Dave | 30 | 20 | |
I am trying to get the percentages:
like : passpercent = (pass/pass+fail)*100
Can I fill the table with a single MySQL code for both the columns??
The Table would look like this hopefully:
Name | Pass | Fail | Pass Percent | Fail Percent
Abdy | 20 | 5 | 80 | 20
Bob | 10 | 5 | 66 | 33
Cantona | 40 | 10 | 80 | 20
Dave | 30 | 20 | 60 | 40
That's absolutely possible.
To fill the second table:
UPDATE mytable SET pass_pct=(pass/pass+fail)*100,fail_pct=(fail/pass+fail)*100
Granted, you could also generate those during selection of the first table (if you don't want to store the results), like:
SELECT name,pass,fail,(pass/pass+fail)*100 as pass_pct,(fail/pass+fail)*100 as fail_pct FROM mytable