Finding most common values for all columns - mysql

Below is what I have in table myTable.
+----------+--------+--------+--------+--------+--------+---------+
| date | value1 | value2 | value3 | value4 | value5 | value6 |
+----------+--------+--------+--------+--------+--------+---------+
|2015-05-01| 2 | 10 | 20 | 1 | 40 | 50 |
|2015-05-02| 5 | 12 | 22 | 32 | 42 | 52 |
|2015-05-03| 6 | 1 | 24 | 34 | 2 | 5 |
|2015-05-04| 8 | 16 | 26 | 36 | 46 | 56 |
|2015-05-05| 1 | 18 | 28 | 38 | 48 | 58 |
|2015-05-06| 3 | 11 | 1 | 31 | 41 | 51 |
|2015-05-07| 5 | 13 | 23 | 3 | 43 | 53 |
|2015-05-08| 9 | 15 | 25 | 35 | 45 | 55 |
|2015-05-09| 4 | 3 | 27 | 37 | 47 | 3 |
|2015-05-10| 2 | 19 | 29 | 1 | 49 | 59 |
+----------+--------+--------+--------+--------+--------+---------+
This output, I wanted to get. But how?
+--------------------------------+--------------------------------+
| Output all table | Output last 5 days |
+--------------------------------+--------------------------------+
| number 1 (5 times) | number 1 (3 times) |
| number 3 (4 times) | number 2 (2 times) |
| number 2 (3 times) | number 5 (2 times) |
| number 5 (3 times) | |
+--------------------------------+--------------------------------+
Can I achieve this in mysql?

Steps(could help):
1) Decide all the columns you want to consider for similar values.
2) Create group by column values with count to create an array(value=>count,...)
3) Once all the array created. Merge them all to create final array. (Add up the count to get the final count)

Having columns in a table that are distinguished only by numbers at the end of the column names generally indicates a problem with the data structure. In general, you want one row per date and value, in something called a junction table.
You can do what you want by unpivoting the data and then aggregating the results:
select value, count(*)
from ((select date, value1 as value from mytable) union all
(select date, value2 from mytable) union all
(select date, value3 from mytable) union all
(select date, value4 from mytable) union all
(select date, value5 from mytable) union all
(select date, value6 from mytable)
) t
group by value
order by count(*) desc;
You can add a where clause on either the outside query or on all the subqueries if you want the histogram for a particular period.

Related

How to Identify duplicate value in MySQL?

I have a table employee_monitor below
Name | Code | ValueGain
------+------+-----------
Zakir | 10 | 15
Zakir | 10 | 16
Tame | 11 | 19
Raya | 12 | 12
Zakir | 10 | 20
Tame | 11 | 28
Now need a query for the below result
Name | Code | ValueGain | Rank
------+------+------------+-----
Zakir | 10 | 15 | 1
Zakir | 10 | 16 | 0
Tame | 11 | 19 | 1
Raya | 12 | 12 | 1
Zakir | 10 | 20 | 0
Tame | 11 | 28 | 0
Rank value 0 mean duplicate code.
If you determine a duplicate by the order of the ValueGain column, I think the answer is the following statement.
SELECT Name, Code, ValueGain, (
SELECT 1 - Count(*)
FROM TableName as T2
WHERE T1.Name = T2.Name AND T1.Code = T2.Code AND T1.ValueGain > T2.ValueGain
LIMIT 1
) as Rank FROM TableName as T1;
The inner query searches for equal Name and Code with higher ValueGain, returns at most 1 result and counts that. As you want to have it the other way round, invert it by subtraction.

return a unique list from query result after removing duplicate rows from the table

I have two columns product_id, r_store_id which have a few rows with same values. Rest of the column rows have different values
I have duplicate rows with same r_store_id and product_id because every time I have to add new entries into this table. I want unique rows list with latest update_dt
(refer the DB table below).
id | m_store_id |r_store_id|product_id | amount |update_dt |
1 | 4 | 1 | 45 | 10 |18/03/5 |
2 | 4 | 1 | 45 | 100 |18/03/9 |
3 | 4 | 1 | 45 | 20 |18/03/4 |
4 | 5 | 2 | 49 | 10 |18/03/8 |
5 | 5 | 2 | 49 | 60 |18/03/2 |
6 | 9 | 3 | 45 | 19 |18/03/5 |
7 | 9 | 3 | 45 | 56 |18/03/3 |
My result should look like this:
id | m_store_id |r_store_id|product_id | amount |update_dt |
2 | 7 | 1 | 45 | 100 |18/03/9 |
4 | 5 | 2 | 49 | 10 |18/03/8 |
6 | 9 | 3 | 45 | 19 |18/03/5 |
I want to put this result in a list like this:
List<Sales> salesList = (List<Sales>) query.list();
I am not able to find an easy solution. Please help me with this!
We can select the chronologically most recent update for each store, and then join to get all the variables:
select a.*
from mytable a
join (select m_store_id, r_store_id, product_id, max(update_dt) as maxdate
from mytable
group by 1,2,3) b
on a.m_store_id=b.m_store_id
and a.r_store_id=b.r_store_id
and a.product_id=b.product_id
and a.update_dt = b.maxdate;

How to get max value with various conditions from a single MySQL table

I have table with a bunch of (machine id) mid's and (sensor id) sid's, and their corresponding (values) v's. Needless to say the id column is a unique row number. (NB: There are other columns in the table, and not all mid's have the same sid's)
Current Table:
+------+-------+-------+-----+---------------------+
| id | mid | sid | v | timestamp |
+------+-------+-------+-----+---------------------+
| 51 | 10 | 1 | 40 | 2015/5/1 11:56:01 |
| 52 | 10 | 2 | 39 | 2015/5/1 11:56:25 |
| 53 | 10 | 2 | 40 | 2015/5/1 11:56:42 |
| 54 | 11 | 1 | 50 | 2015/5/1 11:57:52 |
| 55 | 11 | 2 | 18 | 2015/5/1 11:58:41 |
| 56 | 11 | 2 | 19 | 2015/5/1 11:58:59 |
| 57 | 11 | 3 | 58 | 2015/5/1 11:59:01 |
| 58 | 11 | 3 | 65 | 2015/5/1 11:59:29 |
+------+-------+-------+-----+---------------------+
Q: How would I get the MAX(v)for each sid for each mid?
Expected Output:
+------+-------+-------+-----+---------------------+
| id | mid | sid | v | timestamp |
+------+-------+-------+-----+---------------------+
| 51 | 10 | 1 | 40 | 2015/5/1 11:56:01 |
| 53 | 10 | 2 | 40 | 2015/5/1 11:56:42 |
| 54 | 11 | 1 | 50 | 2015/5/1 11:57:52 |
| 56 | 11 | 2 | 19 | 2015/5/1 11:58:59 |
| 58 | 11 | 3 | 65 | 2015/5/1 11:59:29 |
+------+-------+-------+-----+---------------------+
The expected output is to obtain the whole row with all the (single) max value for all the sids in all the mids.
Addendum:
Due to a very big table, I need to place boundaries with dates. For the sample above the two boundary dates should be 2015/05/01 00:00:00 (1st of May'15) till 2015/05/02 00:00:00 (2nd of May'15). Q: How could I add this date boundary?
Find the max v in subquery for each combination of mid, sid and then join it with your original table to get the desired result.
select *
from your_table t
join (
select mid, sid, max(v) as v
from your_table
group by mid, sid
) t2 using (mid, sid, v);
Note here that if there are multiple rows with same sid, mid and v, it will return all of them.
As mentioned in the comments, since you have an id column, you can include that in limited correlated query like this:
select *
from your_table t1
where id = (select id
from your_table t2
where t1.mid = t2.mid
and t1.sid = t2.sid
order by v desc, id desc
limit 1
);
This will give you one single row per mid, sid combination with max v (and latest id in case of ties).
Use MAX() function with GROUP BY clause
SELECT id, mid, sid, MAX(v) AS v, `timestamp`
FROM MyTable
GROUP BY mid, sid;
This returns rows with maximum values of v for each combination of mid and sid.

How to count values conditionally in SQL

I have an index table of entity attribute values that looks like this:
+-----------+--------------+----------+-------+
| entity_id | attribute_id | store_id | value |
+-----------+--------------+----------+-------+
| 38 | 190 | 1 | 22 |
| 38 | 190 | 1 | 23 |
| 39 | 190 | 1 | 22 |
| 39 | 190 | 1 | 23 |
| 39 | 190 | 1 | 42 |
| 40 | 190 | 1 | 22 |
| 41 | 190 | 1 | 54 |
| 42 | 190 | 1 | 54 |
| 43 | 190 | 1 | 22 |
| 44 | 190 | 1 | 22 |
| 45 | 190 | 1 | 54 |
+-----------+--------------+----------+-------+
As you can see, a single entity can have multiple values for a single attribute (entity_id 38 has values 22,23) and these values are not unique per entity (entity_id 38,39 both share value 22).
The first problem to solve is getting the number of distinct entities per value; this is easily accomplished with:
SELECT value, COUNT(entity_id) AS count
FROM catalog_product_index_eav
WHERE attribute_id=190
GROUP BY value;
which results in:
+-------+-------+
| value | count |
+-------+-------+
| 22 | 5 |
| 23 | 2 |
| 42 | 1 |
| 54 | 3 |
+-------+-------+
My question is how can I nest an OR condition in this count, namely: for some specific value Y, for each value X, count the number of entities that have either value X or Y.
I would like to do this in a single query. For instance, for attribute_id 190 and value 23, the output from above example should be:
+-------+-------+
| value | count |
+-------+-------+
| 22 | 5 | # all entities with value 22 happen to have 23 as well
| 23 | 2 | that is, one is a subset of the other
| 42 | 2 | # intersection is nonempty
| 54 | 5 | # sets are disjoint
+-------+-------+
select c1.value,
( SELECT COUNT(DISTINCT entity_id) as count
FROM catalog_product_index_eav
where attribute_id=81
and (value=c1.value || value=7) ) as count
FROM catalog_product_index_eav c1
WHERE attribute_id=81
GROUP BY c1.value
Try to use
Select C.value, max(C.count) from (
SELECT A.value, (Select COUNT(B.entity_id) from FROM catalog_product_index_eav B
WHERE B.attribute_id=A.attribute_id and (B.value=A.value or B.value=23)) AS count
FROM catalog_product_index_eav A
WHERE A.attribute_id=190) C group by C.value
It gives you both results in single query if it is satisfied your output.
SELECT i.value AS [value], COUNT(i.entity_id) AS [count],
(SELECT COUNT(b.entity_id) tot FROM catalog_product_index_eav b
WHERE b.entity_id IN (SELECT v.entity_id FROM
catalog_product_index_eav v WHERE v.VALUE = i.value)) AS [total_count]
FROM catalog_product_index_eav i
WHERE i.attribute_id=190
GROUP BY i.value

Do a SELECT in MYSQL to return the remainder of an ID COUNT/8

I would like to know how to do a Query in MySQL to get the remainder of the ID_COUNT / 8.
Here's an example table:
ID (INT) | PRODUCT ID | TIME
1 | 14 | 09:34:00
5 | 26 | 09:47:00
5 | 01 | 09:58:00
1 | 02 | 10:10:00
2 | 63 | 10:36:00
4 | 59 | 10:47:00
3 | 18 | 11:00:00
1 | 27 | 11:15:00
5 | 36 | 11:38:00
1 | 44 | 09:34:00
5 | 55 | 09:47:00
5 | 14 | 09:58:00
1 | 24 | 10:10:00
2 | 54 | 10:36:00
4 | 44 | 10:47:00
3 | 54 | 11:00:00
1 | 64 | 11:15:00
5 | 14 | 11:38:00
What i would like to do here is, every time a new row is inserted, I want to get the COUNT of that ID (for example for the ID=5 it would be 6), and them divide that number by 8 (6/8) and then get the remainder of that division.
I'm using PHP by the way, if there's no way of doing it only with MySQL.
Thanks in advance, any question fell free to ask!
Miguel.
Use MOD function
Query for you example
SELECT COUNT(1) MOD 8 AS result
FROM `table`
WHERE id=5
Query for common example
SELECT id, COUNT(1) MOD 8 AS result
FROM `table`
GROUP BY id
SELECT MOD(cnt, 8) FROM (SELECT COUNT(ID) cnt FROM mytable GROUP BY ID)
You can use the mod() function:
select mod(count(*), 8)
from t
where id = #Last_Id
The id is not auto incremented, so you cannot use last_inserted_id().