MySQL Pivot Field Names to values in row - mysql

I'm new to pivoting, so I came here to get some advice on this. I have a table with fields benchmarkname and value. However, another table is populated differently and out of my control: it has each benchmarkname as its own field in the table, with the row value being the value. The layout is below:
Table 1
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| stream | double | YES | | NULL | |
| pisec | double | YES | | NULL | |
| iozws | double | YES | | NULL | |
| iozwb | double | YES | | NULL | |
| iozrs | double | YES | | NULL | |
| iozrb | double | YES | | NULL | |
Table 2
| BenchmarkName | varbinary(43) | YES | | NULL | |
| Value | decimal(14,0) | YES | | NULL | |
My question is: how do I convert the first table to look like second dynamically? I believe the answer lies in a pivot, but I am unsure.

I think you want to unpivot the first table. UNPIVOTing takes the data from your columns and converts it into rows. MySQL does not have unpivot so you will have to use a UNION ALL query:
select 'stream' BenchmarkName, stream value
from table1
union all
select 'pisec' BenchmarkName, pisec value
from table1
union all
select 'iozws' BenchmarkName, iozws value
from table1
union all
select 'iozwb' BenchmarkName, iozwb value
from table1
union all
select 'iozrs' BenchmarkName, iozrs value
from table1
union all
select 'iozrb' BenchmarkName, iozrb value
from table1

Related

Easiest mysql ever. But I can't do it. Where clause isn't working

Here is my table when I do Select * from tempF;
| Timestamp | CurrentF | RecordMinF | RecordMaxF |
+-----------+----------+------------+------------+
| 21:12:53 | 69.23 | NULL | NULL |
| 21:15:53 | 67.9 | NULL | NULL |
| 21:16:02 | 68.08 | NULL | NULL |
| 21:16:08 | 68.08 | NULL | NULL |
| 21:16:14 | 68.08 | NULL | NULL |
| 22:37:56 | 68.98 | NULL | NULL |
| 22:38:08 | 69.16 | NULL | NULL |
| 22:38:14 | 69.34 | NULL | NULL |
| 22:38:15 | 69.16 | NULL | NULL |
| 22:38:32 | 69.34 | NULL | NULL |
I'm switching from MSSQL to MySQL so maybe I'm missing something. All I want to do is: select * from tempF where CurrentF = 67.9;
It says it returns an empty set but clearly in the table there is a row in the CurrentF column that has the number 67.9
select * from tempF where CurrentF = '67.9';
will work for sure..
Just figured this out from another StackOverflow post:
mysql float data not selecting in where clause
Here was the best answer that I saw:
Today, I also came across the same situation and get resolved just by
using FORMAT function of MySQL, It will return the results that
exactly match your WHERE clause.
SELECT * FROM yourtable WHERE FORMAT(col,2) = FORMAT(value,2)
Explanation:
FORMAT('col name',precision of floating point number)
Hope it helps.
So to answer my question, I had to write the query like this:
Select * from tempF where format(CurrentF,2) = format(67.9,2);

MySQL Views and Column Name Case Sensitivity

This might sounds like a simple question, but the one that I haven't been able to find a satisfying answer to.
In MySQL, if you are using a Unix Based machines, the tables names and column names are case in-sensitive when running the queries as long as you follow Camel Case in the names.
Now, here is the tricky part, Lets assume the following table structure.
> desc table1
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name | varchar(10) | YES | | NULL | |
| id | int(11) | NO | PRI | NULL | |
+-------+-------------+------+-----+---------+-------+
> desc table2
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name1 | varchar(10) | YES | | NULL | |
| id | int(11) | NO | PRI | NULL | |
+-------+-------------+------+-----+---------+-------+
> desc table_view
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | NO | | NULL | |
| name | varchar(10) | YES | | NULL | |
| name1 | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
Now, if I run the Queries on my table with column names mentioned in Upper case, the result will have the column name in Upper case and Lower case, if the query has lower case column names.
> select name from table1
+-------+
| name |
+-------+
| test |
| test2 |
+-------+
> select NAME from table1
+-------+
| NAME |
+-------+
| test |
| test2 |
+-------+
However, when I run the same queries on the View, the column names match the case of the string that were used while creating the view. i.e. the resulting data will have the same column as the view and not what is used in the query.
> select name from table_view
+-------+
| name |
+-------+
| test |
| test2 |
+-------+
> select NAME from table_view
+-------+
| name |
+-------+
| test |
| test2 |
+-------+
Is there is an easy way to fix this problem and make sure that the views also follow the same standard or format as the tables would when responding with query results ?
PS : We have some legacy code where we are running out of Table Row Size limit when creating new tables due to the number and size of the Columns. So we split them dynamically into n tables and joined them into a view with the same name as previous table to make sure we didn't have to do much of a code change.
But the case issue with the view is breaking things. Any help will be greatly appreciated.

Select a column from table based on other column values

I have a table in MySql and table name is logs
+---------------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+---------------+------+-----+---------+-------+
| domain | varchar(50) | YES | MUL | NULL | |
| sid | varchar(100) | YES | MUL | NULL | |
| email | varchar(100) | YES | MUL | NULL | |
+---------------+---------------+------+-----+---------+-------+
The following are sample rows from the table
+------------+----------------+---------------
| sid | email | domain|
+------------------------------------+-------+
| 1 | | xxx123#yahoo.com | xxx |
| 2 | | xxx123#yahoo.com | xxx |
| 2 | | yyy123#yahoo.com | yyy |
| 2 | | yyy123#yahoo.com | yyy |
| 3 | | zzz123#yahoo.com | zzz |
| 4 | | qqq123#yahoo.com | qqq |
| 2 | | ppp123#yahoo.com | ppp |
+---+--------+-----------------------+-------+
I want a query something like
select * from logs
where sid IN (select sid from logs
where domain="xxx" AND email="xxx123#yahoo.com")
Desired output
+------------+-----------------------+--------
| sid | email | domain|
+------------------------------------+-------+
| 1 | | xxx123#yahoo.com | xxx |
| 2 | | xxx123#yahoo.com | xxx |
| 2 | | yyy123#yahoo.com | yyy |
| 2 | | yyy123#yahoo.com | yyy |
| 2 | | ppp123#yahoo.com | ppp |
+---+--------+-----------------------+-------+
I can do it using joins but is there any way to get results without using joins or any optimized version of this query
You can use where exists as
select l1.* from logs l1
where exists(
select 1 from logs l2
where l1.sid = l2.sid
and l2.domain = 'xxx'
and l2.email = 'xxx123#yahoo.com'
);
First get a proper id on those rows. Second have you tried it? it looks like it should work. I have no idea why you want that though.
If it actually doesn't work try this structure, could be faster:
SELECT *
FROM some_table
WHERE relevant_field IN
(
SELECT * FROM
(
SELECT relevant_field
FROM some_table
WHERE conditions
) AS subquery
)
Do you want the whole table as result or just one column?
If I get your question right I would simple use:
SELECT * FROM logs WHERE domain="xxx" AND email="xxx123#yahoo.com"
Or if you want only the sid just replace the * with sid.
And if all sid´s are numbers, why don´t you use int or something similar as column type?
It seems like you are doing something redundant just by looking at your request you seem to look for
select * from logs where domain="xxx" AND email="xxx123#yahoo.com"
I dont't know why you are using the first part of the SQL string since this is not a join from other sql tables.
Or am i missing something?

MySQL merge results into table from count of 2 other tables, matching ids

I've got 3 tables: model, model_views, and model_views2. In an effort to have one column per row to hold aggregated views, I've done a migration to make the model look something like this, with a new column for the views:
+---------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | | NULL | |
| [...] | | | | | |
| views | int(20) | YES | | 0 | |
+---------------+---------------+------+-----+---------+----------------+
This is what the columns for model_views and model_views2 look like:
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | smallint(5) | NO | MUL | NULL | |
| model_id | smallint(5) | NO | MUL | NULL | |
| time | int(10) unsigned | NO | | NULL | |
| ip_address | varchar(16) | NO | MUL | NULL | |
+------------+------------------+------+-----+---------+----------------+
model_views and model_views2 are gargantuan, both totalling in the tens of millions of rows each. Each row is representative of one view, and this is a terrible mess for performance. So far, I've got this MySQL command to fetch a count of all the rows representing single views in both of these tables, sorted by model_id added up:
SELECT model_id, SUM(c) FROM (
SELECT model_views.model_id, COUNT(*) AS c FROM model_views
GROUP BY model_views.model_id
UNION ALL
SELECT model_views2.model_id, COUNT(*) AS c FROM model_views2
GROUP BY model_views2.model_id)
AS foo GROUP BY model_id
So that I get a nice big table with the following:
+----------+--------+
| model_id | SUM(c) |
+----------+--------+
| 1 | 1451 |
| [...] | |
+----------+--------+
What would be the safest route for pulling off commands from here on in to merge the values of SUM(c) into the column model.views, matched by the model.id to model_ids that I get out of the above SQL query? I want to only fill the rows for models that still exist - There is probably model_views referring to rows in the model table which have been deleted.
You can just use UPDATE with a JOIN on your subquery:
UPDATE model
JOIN (
SELECT model_views.model_id, COUNT(*) AS c
FROM model_views
GROUP BY model_views.model_id
UNION ALL
SELECT model_views2.model_id, COUNT(*) AS c
FROM model_views2
GROUP BY model_views2.model_id) toupdate ON model.id = toupdate.model_id
SET model.views = toupdate.c

Temporary assigning NULL to a value for the purpose of sorting values in mysql

I am trying to get the correct formatting of results back from a Mysql query. When I ignore the NULL values, the formatting is correct, but when I allow null values to be included, my results are messed up.
I have the following query I am using:
select name,suite,webpagetest.id,MIN(priority) AS min_pri
FROM webpagetest,comparefileerrors
WHERE vco="aof" AND user="1" AND calibreversion="9"
AND webpagetest.id=comparefileerrors.id
AND comparefileerrors.priority IS NOT NULL
GROUP BY id
ORDER BY coalesce(priority,suite,name) ASC;
This returns the expected output:
+-----------------------------+-----------------------------+-------+---------+
| name | suite | id | min_pri |
+-----------------------------+-----------------------------+-------+---------+
| set_get_status | shortsRepairDB_2009.1_suite | 6193 | 0 |
| u2uDemo | shortsRepairDB_2009.1_suite | 6195 | 0 |
| change_sets | shortsRepairDB_2009.1_suite | 6194 | 0 |
| bz1508_SEGV_password | NULL | 6185 | 1 |
| assign_short_AND_user_info | shortsRepairDB_2009.1_suite | 6198 | 2 |
| bz1273_cmdline_execplussvdb | NULL | 6203 | 2 |
| bz1747_bad_lvsf | NULL | 36683 | 3 |
+-----------------------------+-----------------------------+-------+---------+
However, sometimes the priority values will not be set. If this is the case, I want the database to treat the priority as if it had an extremely high priority, so that the values with a null-priority are at the very bottom. I can not set the priority ahead of time (using a default value), but for the purposes of the sort, is it possible to do this?
Currently, if I issue the following command,
select name,suite,webpagetest.id,MIN(priority) AS min_pri
FROM webpagetest,comparefileerrors
WHERE vco="aof" AND user="1" AND calibreversion="9"
AND webpagetest.id=comparefileerrors.id
GROUP BY id
ORDER BY coalesce(priority,suite,name) ASC;
I get output like the following:
| name | suite | id | min_pri |
+-----------------------------+-------+-------+---------+
| bz1747_bad_lvsf | NULL | 36683 | 1 |
| NEC_Dragon.query | NULL | 36684 | NULL |
| avago_hwk_elam0_asic | NULL | 6204 | NULL |
| bz1273_cmdline_execplussvdb | NULL | 6203 | 2 |
| bz1491_query_server_crash | NULL | 6188 | NULL |
| bz1493_export_built_in_prop | NULL | 6186 | NULL |
+-----------------------------+-------+-------+---------+
6 rows in set (0.68 sec)
Here I have lost the formatting I had before. I would like the formatting to be as follows:
| name | suite | id | min_pri |
+-----------------------------+-------+-------+---------+
| bz1747_bad_lvsf | NULL | 36683 | 0 |
| NEC_Dragon.query | NULL | 36684 | 0 |
| avago_hwk_elam0_asic | NULL | 6204 | 1 |
| bz1273_cmdline_execplussvdb | NULL | 6203 | 2 |
| bz1491_query_server_crash | NULL | 6188 | NULL |
| bz1493_export_built_in_prop | NULL | 6186 | NULL |
+-----------------------------+-------+-------+---------+
6 rows in set (0.68 sec)
Hopefully I've explained this well enough that someone can understand what I want here.
Thanks for looking!
if you don't want to use sentinel value, i.e. ORDER BY COALESCE(priority, 99999); use:
select * from x
order by
case
when priority is not null then 1 /* non-nulls, first */
else 2 /* nulls last */
end,
priority
or you can take advantage of the fact that mysql boolean expression results to either 1 or 0:
select * from x
order by priority is null, priority
or if you're using postgresql:
select * from x order by priority nulls first
alternatively:
select * from x order by priority nulls last
Sounds like you want MIN(IFNULL(priority, 99999)). See the documentation for the IFNULL() function.