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.
Related
Let's say, in given num_table, there is a column, in which only numbers from 1 to 35 are stored.
Code for count nums in last 25rows is:
select num, count(*)
from (select C_1 as num from num_table order by id desc limit 25) n
group by num
order by num asc;
Result:
| num | count(*) |
|------|----------|
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 2 |
| 10 | 1 |
| 11 | 1 |
| 12 | 1 |
| 15 | 1 |
| 16 | 2 |
| 17 | 1 |
| 20 | 1 |
| 21 | 1 |
| 22 | 1 |
| 23 | 1 |
| 25 | 1 |
| 28 | 2 |
| 29 | 2 |
| 30 | 1 |
| 32 | 2 |
|------|----------|
How to get a result, where nums from 1 to 35 - which occured 0 times within last 25 rows - will be also displayed?
Example of desired result:
| num | count(*) |
|------|----------|
| 1 | 0 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 2 |
| 6 | 0 |
| 7 | 0 |
| 8 | 0 |
| 9 | 0 |
| 10 | 1 |
| ... | ... |
| 35 | 0 |
Maybe the quickest way is to make your existing query as sub-query and LEFT JOIN your num_table with it like :
SELECT A.C_1, IFNULL(cnt,0) total_count
FROM num_table A
LEFT JOIN
(SELECT num, COUNT(*) cnt
FROM (SELECT C_1 AS num FROM num_table ORDER BY id DESC LIMIT 25) n
GROUP BY num) B
ON A.C_1=B.num
GROUP BY A.C_1, cnt
ORDER BY A.C_1 ASC;
Here's a fiddle for reference:
https://dbfiddle.uk/?rdbms=mysql_5.7&fiddle=3ced94d698fd8a55a8ad07a9d3b42f3d
And by the way, the current result you're showing is only 24 rows despite you did LIMIT 25 in the first sub-query. So in my example fiddle, the result is slightly different.
Here is another way to solve your problem.
In this solution, first, you need a table with numbers between 1 and 35, but only for the query, so then you can left join (because with a left join you can have also 0 counter values) it with your existent num_table.
You can do it like this:
WITH RECURSIVE numbers(id) AS (
SELECT 1 as id
UNION ALL
SELECT id+1 FROM numbers WHERE id < 35
)
SELECT numbers.id AS num, count(nt.id) AS total
FROM numbers
LEFT JOIN (SELECT C_1 FROM num_table ORDER BY id DESC LIMIT 25) nt ON (nt.C_1 = numbers.id)
GROUP BY numbers.id
I have this table test_table below
USER_ID | YEAR | MONEY
----------------------
1 | 0 | 0
1 | 12 | 12
1 | 48 | 12
2 | 15 | 15
2 | 10 | 20
3 | 0 | 0
So I am trying to return the row which has the highest money. For example, the row return would be like this
USER_ID | YEAR | MONEY
----------------------
1 | 12 | 12
1 | 48 | 12
2 | 10 | 20
3 | 0 | 0
But because User ID 1 has the same value for money, I would like to check for the highest year of that money amount and return the result. The expected result should be
USER_ID | YEAR | MONEY
----------------------
1 | 48 | 12
2 | 10 | 20
3 | 0 | 0
Is it possible to get row like this?
Here is the link to test your query online
http://sqlfiddle.com/#!9/2e5660/1
You can try using correlated subquery
DEMO
select userid, moneyval,max(year) as year
from
(
select * from t a
where moneyval in
(select max(moneyval) from t b where a.userid=b.userid)
)A group by userid, moneyval
OUTPUT:
userid moneyval year
1 12 48
2 20 10
3 0 0
You can use not exists to get the rows with maximum values in money (and year):
select t.*
from test_table t
where not exists (
select 1 from test_table
where userid = t.userid and (
money > t.money or (money = t.money and year > t.year)
)
)
See the demo.
Results:
| userid | money | year |
| ------ | ----- | ---- |
| 1 | 12 | 48 |
| 2 | 20 | 10 |
| 3 | 0 | 0 |
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.
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().
In table I need to filter out nearest duplicated rows which have same status_id (but not completely all) when user_id is the same. GROUP BY or DISTINCT did not help in this situation. Here is an example:
---------------------------------------------------
| id | user_id | status_id | date |
---------------------------------------------------
| 1 | 10 | 1 | 2010-10-10 10:00:10|
| 2 | 10 | 1 | 2010-10-11 10:00:10|
| 3 | 10 | 1 | 2010-10-12 10:00:10|
| 4 | 10 | 2 | 2010-10-13 10:00:10|
| 5 | 10 | 4 | 2010-10-14 10:00:10|
| 6 | 10 | 4 | 2010-10-15 10:00:10|
| 7 | 10 | 2 | 2010-10-16 10:00:10|
| 8 | 10 | 2 | 2010-10-17 10:00:10|
| 9 | 10 | 1 | 2010-10-18 10:00:10|
| 10 | 10 | 1 | 2010-10-19 10:00:10|
Have to look like:
---------------------------------------------------
| id | user_id | status_id | date |
---------------------------------------------------
| 1 | 10 | 1 | 2010-10-10 10:00:10|
| 4 | 10 | 2 | 2010-10-13 10:00:10|
| 5 | 10 | 4 | 2010-10-14 10:00:10|
| 7 | 10 | 2 | 2010-10-16 10:00:10|
| 9 | 10 | 1 | 2010-10-18 10:00:10|
Oldest entries (by date) should remain in the table
You want to keep each row where the previous status is different, based on the id or date column.
If your ids are really sequential (as they are in the question), you can do this with a convenient join:
select t.*
from t left outer join
t tprev
on t.id = tprev.id+1
where tprev.id is null or tprev.status <> t.status;
If the ids are not sequential, you can get the previous one using a correlated subquery:
select t.*
from (select t.*,
(select t2.status
from t t2
where t2.user_id = t.user_id and
t2.id < t.id
order by t2.id desc
limit 1
) as prevstatus
from t
) t
where prevstatus is null or prevstatus <> t.status;