I am trying to find a MySQL query that will find distinct values in a particular field, count the number of occurrences of that value in 2 fields (1_user, 2_user) and then order the results by the count.
example db
+------+-----------+-----------+
| id | 1_user | 2_user |
+------+-----------+-----------+
| 1 | 2 | 1 |
| 2 | 3 | 2 |
| 3 | 8 | 7 |
| 4 | 1 | 8 |
| 5 | 2 | 8 |
| 6 | 3 | 8 |
+------+-----------+-----------+
expected result
user count
----- -----
8 4
2 3
3 2
1 2
The Query
SELECT user, count(*) AS count
FROM
(
SELECT 1_user AS USER FROM test
UNION ALL
SELECT 2_user FROM test
) AS all_users
GROUP BY user
ORDER BY count DESC
Explanation
List all the users in the first column.
SELECT 1_user AS USER FROM test
Combine them with the users from the second column.
UNION ALL
SELECT 2_user FROM test
The trick here is the UNION ALL which preserves duplicate values.
The rest is easy -- select the results you want from the subquery:
SELECT user, count(*) AS count
aggregate by user:
GROUP BY user
and prescribe the order:
ORDER BY count DESC
SELECT u, count(u) AS cnt
FROM (
SELECT 1_user AS u FROM table
UNION ALL
SELECT 2_user AS u FROM table
) subquery
GROUP BY u
ORDER by cnt DESC
Take the 2 queries:
SELECT COUNT(*) FROM table GROUP BY 1_user
SELECT COUNT(*) FROM table GROUP BY 2_user
Now combine them:
SELECT user, SUM(count) FROM
((SELECT 1_user as user FROM table)
UNION ALL
(SELECT 2_user as user FROM table))
GROUP BY user, ORDER BY count DESC;
I think this what you are looking for since your expected result did not include 7
select usr, count(usr) cnt from
(
select user_1 usr from users
union all
select user_2 usr from users
) u
where u.usr in (select user_1 from users)
group by usr
order by count(u.usr) desc
Related
Here's what I'm trying to do. Let's say I have this table t:
key_id | id | record_date | other_cols
1 | 18 | 2011-04-03 | x
2 | 18 | 2012-05-19 | y
3 | 18 | 2012-08-09 | z
4 | 19 | 2009-06-01 | a
5 | 19 | 2011-04-03 | b
6 | 19 | 2011-10-25 | c
7 | 19 | 2012-08-09 | d
For each id, I want to select the row containing the minimum record_date. So I'd get:
key_id | id | record_date | other_cols
1 | 18 | 2011-04-03 | x
4 | 19 | 2009-06-01 | a
The only solutions I've seen to this problem assume that all record_date entries are distinct, but that is not this case in my data. Using a subquery and an inner join with two conditions would give me duplicate rows for some ids, which I don't want:
key_id | id | record_date | other_cols
1 | 18 | 2011-04-03 | x
5 | 19 | 2011-04-03 | b
4 | 19 | 2009-06-01 | a
How about something like:
SELECT mt.*
FROM MyTable mt INNER JOIN
(
SELECT id, MIN(record_date) AS MinDate
FROM MyTable
GROUP BY id
) t ON mt.id = t.id AND mt.record_date = t.MinDate
This gets the minimum date per ID, and then gets the values based on those values. The only time you would have duplicates is if there are duplicate minimum record_dates for the same ID.
I could get to your expected result just by doing this in mysql:
SELECT id, min(record_date), other_cols
FROM mytable
GROUP BY id
Does this work for you?
To get the cheapest product in each category, you use the MIN() function in a correlated subquery as follows:
SELECT categoryid,
productid,
productName,
unitprice
FROM products a WHERE unitprice = (
SELECT MIN(unitprice)
FROM products b
WHERE b.categoryid = a.categoryid)
The outer query scans all rows in the products table and returns the products that have unit prices match with the lowest price in each category returned by the correlated subquery.
I would like to add to some of the other answers here, if you don't need the first item but say the second number for example you can use rownumber in a subquery and base your result set off of that.
SELECT * FROM
(
SELECT
ROW_NUM() OVER (PARTITION BY Id ORDER BY record_date, other_cols) as rownum,
*
FROM products P
) INNER
WHERE rownum = 2
This also allows you to order off multiple columns in the subquery which may help if two record_dates have identical values. You can also partition off of multiple columns if needed by delimiting them with a comma
This does it simply:
select t2.id,t2.record_date,t2.other_cols
from (select ROW_NUMBER() over(partition by id order by record_date)as rownum,id,record_date,other_cols from MyTable)t2
where t2.rownum = 1
If record_date has no duplicates within a group:
think of it as of filtering. Simpliy get (WHERE) one (MIN(record_date)) row from the current group:
SELECT * FROM t t1 WHERE record_date = (
select MIN(record_date)
from t t2 where t2.group_id = t1.group_id)
If there could be 2+ min record_date within a group:
filter out non-min rows (see above)
then (AND) pick only one from the 2+ min record_date rows, within the given group_id. E.g. pick the one with the min unique key:
AND key_id = (select MIN(key_id)
from t t3 where t3.record_date = t1.record_date
and t3.group_id = t1.group_id)
so
key_id | group_id | record_date | other_cols
1 | 18 | 2011-04-03 | x
4 | 19 | 2009-06-01 | a
8 | 19 | 2009-06-01 | e
will select key_ids: #1 and #4
SELECT p.* FROM tbl p
INNER JOIN(
SELECT t.id, MIN(record_date) AS MinDate
FROM tbl t
GROUP BY t.id
) t ON p.id = t.id AND p.record_date = t.MinDate
GROUP BY p.id
This code eliminates duplicate record_date in case there are same ids with same record_date.
If you want duplicates, remove the last line GROUP BY p.id.
This a old question, but this can useful for someone
In my case i can't using a sub query because i have a big query and i need using min() on my result, if i use sub query the db need reexecute my big query. i'm using Mysql
select t.*
from (select m.*, #g := 0
from MyTable m --here i have a big query
order by id, record_date) t
where (1 = case when #g = 0 or #g <> id then 1 else 0 end )
and (#g := id) IS NOT NULL
Basically I ordered the result and then put a variable in order to get only the first record in each group.
The below query takes the first date for each work order (in a table of showing all status changes):
SELECT
WORKORDERNUM,
MIN(DATE)
FROM
WORKORDERS
WHERE
DATE >= to_date('2015-01-01','YYYY-MM-DD')
GROUP BY
WORKORDERNUM
select
department,
min_salary,
(select s1.last_name from staff s1 where s1.salary=s3.min_salary ) lastname
from
(select department, min (salary) min_salary from staff s2 group by s2.department) s3
I have table:
+----------------+
| table |
+----------------+
| u_id | sail_id |
+----------------+
| 1 | 5 |
| 1 | 5 |
| 2 | 5 |
| 2 | 4 |
| 1 | 4 |
+----------------+
How to write sql statement to count different u_id with different sail_id (means no duplicate)?
Example:
if SELECT COUNT(*) FROM table GROUP BY sail_id, result will be 2
if SELECT COUNT(*) FROM table GROUP BY sail_id, user_id, result will be 1
I need result to be 4 (because there are 5 rows and only first and second rows have same u_id and sail_id).
Maybe I need add somewhere DISTINCT.
1) You can use COUNT(DISTINCT ...):
SELECT COUNT(DISTINCT u_id,sail_id)
FROM tab;
SqlFiddleDemo
2) You can use subquery with DISTINCT:
SELECT COUNT(*)
FROM (SELECT DISTINCT u_id, sail_id
FROM table) AS sub;
LiveDemo
3) You can use subquery with GROUP BY:
SELECT COUNT(*)
FROM (SELECT u_id, sail_id
FROM table
GROUP BY u_id, sail_id) AS sub;
4) Last possibility is to use:
SELECT COUNT(DISTINCT CONCAT(u_id,',',sail_id))
FROM table;
SqlFiddleDemo
I am trying to select distinct rows within my SQL table, however I'm not having luck in labeling the returned rows appropriately using the code below:
SELECT #row:=#row+1 as rank,
a.id,
a.name
FROM table a,
( SELECT #row:=0) b
GROUP BY a.id
ORDER BY a.name ASC
This query will return the following:
| RANK | ID | NAME
--------------------------
2 | 4483 | Bob
8 | 9453 | Joe
10 | 4543 | Maurice
What I want it to return is this, however:
| RANK | ID | NAME
--------------------------
1 | 4483 | Bob
2 | 9453 | Joe
3 | 4543 | Maurice
Would it be more appropriate for me to use a DISTINCT query for a query of this magnitude?
As per Marc B's solution, I decided to wrap my query with another one however instead I decided to Select DISTINCT columns rather than grouping them which would remove my margin of error, by using this code
SELECT #row:=#row+1 as rank, a.id, a.name FROM
(
SELECT DISTINCT id, name
FROM Table1
) a, (SELECT #row:=0) b
ORDER BY a.name ASC
I need to generate some big data from many tables, regarding filters, at there also i need to get the sum of some columns, and also counts of rows like example
i have 5 records
ID | NAME | DELETED
1 | A | 1
2 | A | 0
3 | A | 1
4 | B | 1
5 | C | 1
I have the query,
SELECT p.name, sum(p.deleted) as del, count(p.id) as numbers from products as p
join other AS b ON p.id=b.id
The output i need is,
The sum of deleted records
NAME | Deletion | Count
A | 2 | 3
B | 1 | 1
C | 1 | 1
Try this ::
SELECT
p.name,
sum(p.deleted) as del,
count(id) as numbers
from products as p
join other AS b ON p.id=b.id
group by p.name
You should not need to join to get your result. This should work:
SELECT name, sum(deleted), count(1)
FROM products
GROUP BY name
SELECT name,
SUM(CASE WHEN deleted = 1 THEN 1 ELSE 0 END) Deletion,
COUNT(*) `COunt`
FROM products
GROUP BY name
OR
SELECT name,
SUM(deleted) Deletion,
COUNT(*) `COunt`
FROM products
GROUP BY name;
SQLFiddle Demo (both queries)
I have this table: I want to search by UID
ID | VID | UID
1 | 1 | 5
1 | 1 | 6
1 | 2 | 6
2 | 3 | 5
2 | 3 | 6
2 | 4 | 6
I want to end up with this result:
ID | VID | UID
1 | 2 | 6
2 | 4 | 6
In other words, only select the entries where the VID is MAX of the UID but keeping in min NID could differ. Something like this I suppose:
select * from TABLE where uid = 6 and max(vid)
???
But this doesn't work?
One way is to order by the value in descending order (so the max is at the top), then just select the first result.
SELECT t.ID,
t.VID,
t.UID
FROM table t
WHERE t.ID = 1
ORDER BY t.VID DESC
LIMIT 1
Or do you mean you want all rows where t.VID is the highest value? In which case you could do something like this,
SELECT t.ID,
t.VID,
t.UID
FROM table t
WHERE t.ID = 1
AND t.VID = (SELECT MAX(VID) FROM table);
EDIT: Based on the edit to your question, it looks like you just want the max VID value for each ID? If I'm understanding you correctly, then this should give you what you need.
SELECT t.ID,
max(t.VID) as VID,
t.UID
FROM table t
WHERE t.UID = 6
GROUP BY t.ID
You need to have a subquery. This should work:
select * from TABLE where ID='1' AND VID=(select max(VID) from TABLE)
I expect your real-life example is more complicated (at least has more data).
This query will give you the row you want.
SELECT id,vid, uid
FROM TABLE
where id = 1
and vid in (select max(vid) from TABLE where id = 1)