Select WHERE IN and LIMIT by number of rows - mysql

I have a table which looks like this
userid | value | time
1 0 1
1 1 2
1 2 3
3 5 4
4 6 5
1 9 6
3 10 7
Using a select where in query I would want to select userd, value, and time but limit the total number of rows pulled for each userid
My SELECT query,
select userid, value, time from table where userid in (1,3) order by time desc;
This query outputs all the values like so
userid | value | time
1 0 1
1 1 2
1 2 3
3 5 4
3 10 7
I would hover want to limit the number of rows for each userid to two to get an output like so
userid | value | time
1 0 1
1 1 2
3 5 4
3 10 7
I tried using limit but that limits the number of rows for the entire output.

You can use a rank query to limit rows per user
select userid,
value,
`time`
from (
select *,
#r:= case when #g = userid then #r + 1 else 1 end row_num,
#g:=userid
from test t
cross join (select #g:= null,#r:=0) t1
where userid in (1,3)
order by userid,value,`time` desc
) t2
where row_num <= 2
Above query will give rank to each record for same user like user 1 has 3 records the they will assigned rank as 1,2,3 and if user 2 has 2 records then rank will be 1,2 for user 2 and in parent query i am just filtering the records according to the rank that return only result where rank is less than equal to 2 for for each user only 2 rows with rank 1 and 2 will be returned
Demo

Related

mysql sum, CASE WHEN with GROUP BY

In MySQL, I want to sum the values ​​of certain statuses and display them in the same count column,
Do I have to give a condition to count ?!
status is 0, 1, 2 and 3, and status = 2 is a sum of 2, 3, 4 count values.
What kind of conditions should I give?
My Query:
SELECT A.STATUS, B.COUNT, B.REG_DT FROM
(SELECT 0 AS STATUS UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) A
LEFT JOIN (
SELECT STATUS , COUNT(*) AS COUNT, FROM TB_EXE WHERE reg_dt >= CURDATE()
GROUP BY STATUS
) B ON A.STATUS = B.STATUS
My Data:
status | count
-----------------
0 | 1
-----------------
1 | 2
-----------------
2 | 1
-----------------
3 | 0
-----------------
4 | 2
Expected Results:
status | count
-----------------
0 | 1
-----------------
1 | 2
-----------------
2 | 3
SELECT STATUS,COUNT(*)
FROM T
WHERE STATUS < 2
GROUP BY STATUS
UNION ALL
(SELECT 2,COUNT(*)
FROM T
WHERE STATUS >= 2
)
Where the 2 aggregations are dealt with separately.
+--------+----------+
| STATUS | COUNT(*) |
+--------+----------+
| 0 | 1 |
| 1 | 1 |
| 2 | 3 |
+--------+----------+
3 rows in set (0.00 sec)
Or more succinctly
select case when status > 1 then 2 else status end, count(*)
from t
group by case when status > 1 then 2 else status end
you can try like below using case when
select case when status>1 then 2 else status end as status,
sum(count) as cnt from t
group by status
Hmmm, I think I'd go with a framing solution on this one. IE something like this:
SELECT
Status,
Count,
SUM(Count) OVER(ORDER BY status ROWS
BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW) AS FramedCount
FROM Status
this gives you a running total of the counts from all previous rows as the framed count. You can handle the logic in the application to determine which statuses should use the framed count OR you could handle it in the query by adding the following.
SELECT
status,
CASE
when status <= 3 THEN count
ELSE SUM(count) OVER(ORDER BY status ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
END AS 'MyCount'
FROM statusInfo

How to construct query that counts results based on column value being unique?

I have the query below which works fine but multiple records from the same member get counted in numField1. How would I change it so that numField1 only counts 1 record per member per position but still groups them as it currently does? In the table the member is in a column named memberId.
SELECT *, COUNT(field1) AS numField1, AVG(price1) FROM tableName GROUP BY field1, position HAVING status = '1' ORDER BY numField1 DESC, updated DESC
Edit: Perhaps this will help, I want to know how many records each unique pairing of field1 and position there are counting records that match by the same memberId only once.
recordId | memberId | status | updated | field1 | position | price
==================================================================
1 55 1 1 apple 1 1.00
2 55 1 2 apple 1 .50
3 65 1 3 apple 1 .75
4 75 1 4 apple 2 2.00
5 85 1 5 apple 2 3.00
6 95 1 6 apple 2 4.00
The expected output would be a count of 2 for apple with position 1 since only two unique memberIds contain apple and position of 1 and count of 3 for apple with position 2 since three unique membersIds contain apple with position 2. Original query counts 3 for each since it counts records with the same memberId, field1 and position multiple times. Relevant expected results below, hope this helps.
field1 | position | numField1
==============================
apple 1 2
apple 2 3
You want one result row per field1 + position, so group by them. For each such combination you want the count of distinct memberID, so count distinct memberID.
select field1, position, count(distinct memberid)
from tablename
group by field1, position
order by field1, position;
Can you try 'DISTINCT' ?
SELECT *
,COUNT(DISTINCT field1) AS numField1
,AVG(price1)
FROM tableName
GROUP BY field1
,position
HAVING STATUS = '1'
ORDER BY numField1 DESC
,updated DESC

need group by data in mysql

in mysql:
Have data in data:
ColA | ColB | Rank
1 2 0
1 3 1
2 1 0
3 1 0
3 2 1
Keeping Col A as key field, need to get data on base of highest rank i.e.,
output:
ColA | ColB | Rank
1 3 1
2 1 0
3 2 1
any ideas..
You can do it this way:
SELECT T1.ColA, T2.ColB, T1.Rank
FROM TableName T2 JOIN
(SELECT ColA,MAX(Rank) as Rank
FROM TableName
GROUP BY ColA) T1 ON T1.ColA=T2.ColA AND T1.Rank=T2.Rank
Explanation:
Inner query (T1) selects records with highest rank for each values of ColA.
Outer query (T2) is used to select ColB with respect to the values of ColA and Rank from T2.
Result:
ColA ColB Rank
--------------------
1 3 1
2 1 0
3 2 1
See result in SQL Fiddle

mysql limit with inner join and subquery

I have the following query:
SELECT saturday_combinations.index, v.val AS `row` , COUNT( * ) AS `count`
FROM saturday_combinations
INNER JOIN (
SELECT ONE AS val
FROM saturday_combinations
WHERE ONE IS NOT NULL
UNION
SELECT TWO AS val
FROM saturday_combinations
WHERE TWO IS NOT NULL
UNION
SELECT THREE AS val
FROM saturday_combinations
WHERE THREE IS NOT NULL
UNION
SELECT FOUR AS val
FROM saturday_combinations
WHERE FOUR IS NOT NULL
UNION
SELECT FIVE AS val
FROM saturday_combinations
WHERE FIVE IS NOT NULL
UNION
SELECT SIX AS val
FROM saturday_combinations
WHERE SIX IS NOT NULL
UNION
SELECT SEVEN AS val
FROM saturday_combinations
WHERE SEVEN IS NOT NULL
) v ON v.val = saturday_combinations.ONE
OR v.val = saturday_combinations.TWO
OR v.val = saturday_combinations.THREE
OR v.val = saturday_combinations.FOUR
OR v.val = saturday_combinations.FIVE
OR v.val = saturday_combinations.SIX
OR v.val = saturday_combinations.SEVEN
GROUP BY v.val
The purpose of the query is to provide a count of the different values contained in the columns ONE,TWO,THREE,FOUR,FIVE,SIX and SEVEN in the table saturday_combinations. However I want to put a desc limit 4 so that it only performs the count based on the last 4 rows (last four maximum indexes). But I am not getting it to work with the union. Adding order and limit at the very end only limits from the final select, rather than get the last 4 rows and calculate the distribution on them. Any tips?
The table schema is as follows:
index | ONE|TWO|THREE|FOUR|FIVE|SIX|SEVEN
1 1 3 7 10 11 12 13
2 3 4 5 30 31 22 23
3 1 2 3 4 5 6 7
4 1 2 3 4 5 6 7
5 1 2 3 4 5 6 7
6 1 2 3 4 5 6 7
7 1 2 3 4 5 6 7
8 1 2 3 4 5 6 7
9 1 2 3 4 5 6 7
10 1 2 3 4 5 6 7
Index is auto-increment and ONE-SEVEN has integer values.
There are about 3000 rows in the table and I want to count occurences for each value based on the last n rows.
Ideal result for the last n rows where n = last 3 rows should be
Numbers|Count
1 3
2 3
3 3
4 3
5 3
6 3
7 3
If I increase n to include last 6 rows their count should increase. If I could last 10 rows the count should increase and other numbers should appear with their count.
Here is a link to a sample of the real table.
http://sqlfiddle.com/#!2/d035b
If answer to my comment is yes then, you could try the following. When you need to add limit, order by to union selects you need to wrap union queries with brackets ().
SQLFIDDLE DEMO
Code:
(SELECT ONE AS val
FROM saturday_combinations
WHERE ONE IS NOT NULL
order by ONE desc limit 4)
UNION
(SELECT TWO AS val
FROM saturday_combinations
WHERE TWO IS NOT NULL
order by TWO desc limit 4)
UNION
(SELECT THREE AS val
FROM saturday_combinations
WHERE THREE IS NOT NULL
order by THREE desc limit 4)
If answer to my comment is no, then please clarify.
Here is the code based on your sample date:
select distinct x.one as uniqunumbers,
count(x.one) as counts
from(
sELECT DISTINCT 'one'
AS col1, one FROM sat_comb
UNION ALL
SELECT DISTINCT 'two'
AS col1, two FROM sat_comb
UNION ALL
SELECT DISTINCT 'three'
AS col1, three FROM sat_comb
) as x
group by x.one;
UNIQUNUMBERS COUNTS
1 1
3 2
4 1
5 1
7 1
EDIT as per OP has clarified and updated the question.
Quoted: "However I want to limit it so that it first takes the last n rows and then does the count on the values in those n rows. This means, if I have 3 columns with 3000 rows and 35 integers randomly appearing in these 3000 rows it should count how many times each integer appears."
SQLFIDDLE DEMO2
Query:
select x.one as uniqunumbers,
count(x.one) as counts
from(
(sELECT DISTINCT 'one'
AS col1, one FROM sat_comb
order by id desc limit 4)
UNION ALL
(SELECT DISTINCT 'two'
AS col1, two FROM sat_comb
order by id desc limit 4)
UNION ALL
(SELECT DISTINCT 'three'
AS col1, three FROM sat_comb
order by id desc limit 4)
UNION ALL
(SELECT DISTINCT 'four'
AS col1, four FROM sat_comb
order by id desc limit 4)
UNION ALL
(SELECT DISTINCT 'five'
AS col1, five FROM sat_comb
order by id desc limit 4)
UNION ALL
(SELECT DISTINCT 'six'
AS col1, six FROM sat_comb
order by id desc limit 4)
UNION ALL
(SELECT DISTINCT 'seven'
AS col1, seven FROM sat_comb
order by id desc limit 4)
) as x
group by x.one;
Output:
UNIQUNUMBERS COUNTS
2 4
3 3
4 3
5 4
6 4
8 3
9 4
20 3
Maybe I am missing something in your request but based on your desired result, why not just unpivot the data and perform the count.
select value, count(*) Total
from
(
select 'one' col, one value
from saturday_combinations
union all
select 'two' col, two value
from saturday_combinations
union all
select 'three' col, three value
from saturday_combinations
union all
select 'four' col, four value
from saturday_combinations
union all
select 'five' col, five value
from saturday_combinations
union all
select 'six' col, six value
from saturday_combinations
union all
select 'seven' col, seven value
from saturday_combinations
) src
group by value
See SQL Fiddle with Demo
The result of your sample is:
| VALUE | TOTAL |
-----------------
| 1 | 1 |
| 3 | 2 |
| 4 | 1 |
| 5 | 1 |
| 7 | 1 |
| 10 | 1 |
| 11 | 1 |
| 12 | 1 |
| 13 | 1 |
| 22 | 1 |
| 23 | 1 |
| 30 | 1 |
| 31 | 1 |
Edit #1: Based on your update this might be want you what:
select value, count(*)
from
(
select col, value
from
(
select 'one' col, one value
from saturday_combinations
order by one
limit 3
) one
union all
select col, value
from
(
select 'two' col, two value
from saturday_combinations
order by two desc
limit 3
) two
union all
select col, value
from
(
select 'three' col, three value
from saturday_combinations
order by three
limit 3
) three
union all
select col, value
from
(
select 'four' col, four value
from saturday_combinations
order by four
limit 3
) four
union all
select col, value
from
(
select 'five' col, five value
from saturday_combinations
order by five
limit 3
) five
union all
select col, value
from
(
select 'six' col, six value
from saturday_combinations
order by six
limit 3
) six
union all
select col, value
from
(
select 'seven' col, seven value
from saturday_combinations
order by seven
limit 3
) seven
) src
group by value
See SQL Fiddle with Demo
Result:
| VALUE | COUNT(*) |
--------------------
| 1 | 3 |
| 2 | 1 |
| 3 | 4 |
| 4 | 4 |
| 5 | 3 |
| 6 | 3 |
| 7 | 3 |
In case you want to look at the final solution:
http://sqlfiddle.com/#!2/867a6/13
Thanks to #bonCodigo for all the help

Select all rows with multiple occurrences

Ok, I have a single MySQL table with the name 'test' and 3 columns.
ID | playername | lastloginip
-----------------------------
1 | user 1 | 1
2 | user 2 | 2
3 | user 3 | 3
4 | user 4 | 4
5 | user 5 | 5
6 | user 6 | 1
7 | user 7 | 1
8 | user 8 | 2
Now, I would like to select ALL the rows where the lastloginip is found multiple times in the table, and then give the count of those rows.
In this case, it should return the number 5
as user 1, 2, 6, 7 and 8 have a lastloginip that is found multiple times.
I already tried using
SELECT COUNT(*)
FROM (
SELECT *
FROM test
GROUP BY lastloginip
HAVING COUNT(*) > 1
) t
But that gave back the number 2 instead of 5.
I am not sure how to set up this query correctly. Most of my findings on the internet keep showing only 2 rows or giving the number 2 instead of 5.
First COUNT(), then SUM():
SELECT SUM(occurences)
FROM
(
SELECT COUNT(*) AS occurences
FROM test
GROUP BY lastloginip
HAVING COUNT(*)>1
) t
Try this query.
SELECT SUM(loginip)
FROM(
SELECT
lastloginip,
COUNT(lastloginip)
as loginip
FROM test
GROUP BY lastloginip
HAVING COUNT(ID)>1
)t
You can fetch the sum of occurrences using the above code and if you want to view the records with multiple occurences, refer to the query below-
Select *
from test
where lastloginip in (
select *
from
(select lastloginip
from test
group by lastloginip
having count(lastloginip)>1
)
as a)