I searched and found similar post to what I am trying to accomplish but not an exact solution. I have a table of grouped articles (articles that have information in common). I need to select articles from said table where there are at least 10 articles belonging to the group.
Group ID | Article ID | Posting Date
------------------------------------
| 1 | 1234 | 2017-07-14
| 1 | 5678 | 2017-07-14
| 1 | 9000 | 2017-07-14
| 2 | 8001 | 2017-07-14
| 2 | 8002 | 2017-07-14
------------------------------------
SELECT `groupid`, `article_id`, `publish_date`
FROM `article_group`
WHERE `groupid` IN ( SELECT `groupid`, count(`groupid`) as cnt
FROM `article_group`
WHERE date(`publish_date`) = '2017-07-14'
group by `groupid`
having cnt > 10
order by cnt desc
)
I understand the sub-query should just return the one column, but how do I accomplish this with the count and having?
You are very close. You should only be selecting one column in the subquery and the ORDER BY is not necessary:
SELECT `groupid`, `article_id`, `publish_date`
FROM `article_group`
WHERE `groupid` IN (SELECT `groupid`
FROM `article_group`
WHERE date(`publish_date`) = '2017-07-14'
GROUP BY `groupid`
HAVING COUNT(*) > 10
)
Related
It's been asked before, but I can't get it to work properly. The selected answer doesn't work with duplicate values. The second answer should be able to handle duplicates according to the poster, but it's not functioning correctly with my data.
What I want to achieve is pretty simple:
I have a database containing all scores of all users. I want to build a highscore table, so I want to select all highscore rows of each user. With highscore row I mean the row for that user where his score is the highest.
Here's a demo I made based on the answer I mentioned at the top:
CREATE TABLE test(
score INTEGER,
user_id INTEGER,
info INTEGER
);
insert into test(score, user_id, info)
values
(1000, 1, 1),
(1000, 1, 2),
(2000, 2, 3),
(2001, 2, 1);
--
SELECT t.*
FROM test t
JOIN (SELECT test.user_id, max(score) as mi FROM test GROUP BY user_id) j ON
t.score = j.mi AND
t.user_id = j.user_id
ORDER BY score DESC, info ASC;
Expected output:
+-------+---------+------+
| score | user_id | info |
+-------+---------+------+
| 2001 | 2 | 1 |
| 1000 | 1 | 1 |
+-------+---------+------+
--> every user_id is present with the row where the user had the highest score value.
Real output:
+-------+---------+------+
| score | user_id | info |
+-------+---------+------+
| 2001 | 2 | 1 |
| 1000 | 1 | 1 |
| 1000 | 1 | 2 |
+-------+---------+------+
--> when there are duplicate values, user show up multiple times.
Anyone who can point me in the right direction?
I assume when there are duplicate scores you want the lowest info just like your expected output.
With NOT EXISTS:
select t.* from test t
where not exists (
select 1 from test
where user_id = t.user_id and (
score > t.score or (score = t.score and info < t.info)
)
);
See the demo.
For MySql 8.0+ you can use ROW_NUMBER():
select t.score, t.user_id, t.info
from (
select *, row_number() over (partition by user_id order by score desc, info asc) rn
from test
) t
where t.rn = 1
See the demo.
Results:
| score | user_id | info |
| ----- | ------- | ---- |
| 1000 | 1 | 1 |
| 2001 | 2 | 1 |
If the combination of (user_id, info) is UNIQUE and NOT NULL (or PRIMARY KEY), then you can use a LIMIT 1 subquery in the WHERE clause:
SELECT t.*
FROM test t
WHERE (t.score, t.info) = (
SELECT t2.score, t2.info
FROM test t2
WHERE t2.user_id = t.user_id
ORDER BY t2.score DESC, t2.info ASC
LIMIT 1
)
ORDER BY t.score DESC, t.info ASC;
The result will be:
| score | user_id | info |
|-------|---------|------|
| 2001 | 2 | 1 |
| 1000 | 1 | 1 |
demo on sqlfiddle
SELECT info FROM test HAVING MAX(score) was used to keep the info field relevant with the row containing the MAX(score).
SELECT MAX(score) score, user_id, (SELECT info FROM test HAVING MAX(score)) AS info FROM test GROUP BY user_id ORDER BY score DESC;
Sorry to confuse you about my title. I am building an auction system and I am having a difficulty in getting the user's winning item.
Example I have a table like this:
the columns are:
id, product_id, user_id, status, is_winner, info, bidding_price, bidding_date
here's my sql fiddle:
http://sqlfiddle.com/#!9/7097d/1
I want to get every user's item that they already win. So I need to identify if they are the last who bid in that item.
I need to filter it using a user_id.
If I do a query like this:
SELECT MAX(product_id) AS product_id FROM auction_product_bidding
WHERE user_id = 3;
it will get only the product_id that is 12 and the product_id of 9 did not get. Product ID 9 is also that last bid of the user_id 3.
Can you help me? I hope you got my point. Thanks. Sorry if my question a little bit confusing.
According to your question, seems 11 is also what you want, try this query:
SELECT apd.product_id
FROM auction_product_bidding apd
JOIN (
SELECT MAX(bidding_date) AS bidding_date, product_id
FROM auction_product_bidding
GROUP BY product_id
) t
ON apd.product_id = t.product_id
AND apd.bidding_date = t.bidding_date
WHERE apd.user_id = 3;
Check Demo Here
select id,product_id,user_id,status,is_winner,info,bidding_price,bidding_date,rank
from
( SELECT apb.*,
greatest(#rank:=if(product_id=#prodGrp,#rank+1,1),-1) as rank,
#prodGrp:=product_id as dummy
FROM auction_product_bidding apb
cross join (select #prodGrp:=-1,#rank:=0) xParams
order by product_id,bidding_date DESC
) xDerived
where user_id=3 and rank=1;
That user won 9,11,12
+----+------------+---------+--------+-----------+------+---------------+---------------------+------+
| id | product_id | user_id | status | is_winner | info | bidding_price | bidding_date | rank |
+----+------------+---------+--------+-----------+------+---------------+---------------------+------+
| 60 | 9 | 3 | | 0 | | 75000.00 | 2016-08-02 16:31:23 | 1 |
| 59 | 11 | 3 | | 0 | | 15000.00 | 2016-08-02 12:04:16 | 1 |
| 68 | 12 | 3 | | 0 | | 18000.00 | 2016-08-10 09:20:01 | 1 |
+----+------------+---------+--------+-----------+------+---------------+---------------------+------+
SELECT product_id FROM auction_product_bidding where bidding_price= any
(select max(bidding_price) from auction_product_bidding group by product_id)
and user_id='3';
select * from
(select product_id,user_id,max(bidding_price) from
(select * from auction_product_bidding order by bidding_price desc) a
group by product_id) b
where user_id=3;
Answer:
product_id user_id max(bidding_price)
9 3 75000
11 3 15000
12 3 18000
An idea could be to sort the table desc by date and select every distinct row by product_id and customer_id. Something like
SELECT DISTINCT prod_id, user_id FROM (
SELECT * FROM auction_product_bidding ORDER BY date DESC
)
You want everything that bids last in 3, is it right ?
I have two tables: contacts and client_profiles. A contact has many client_profiles, where client_profiles has foreign key contact_id:
contacts:
mysql> SELECT id,first_name, last_name FROM contacts;
+----+-------------+-----------+
| id | first_name | last_name |
+----+-------------+-----------+
| 10 | THERESA | CAMPBELL |
| 11 | donato | vig |
| 12 | fdgfdgf | gfdgfd |
| 13 | some random | contact |
+----+-------------+-----------+
4 rows in set (0.00 sec)
client_profiles:
mysql> SELECT id, contact_id, created_at FROM client_profiles;
+----+------------+---------------------+
| id | contact_id | created_at |
+----+------------+---------------------+
| 6 | 10 | 2014-10-09 17:17:43 |
| 7 | 10 | 2014-10-10 11:38:01 |
| 8 | 10 | 2014-10-10 12:20:41 |
| 9 | 10 | 2014-10-10 12:24:19 |
| 11 | 12 | 2014-10-10 12:35:32 |
+----+------------+---------------------+
I want to get the latest client_profiles for each contact. That means There should be two results. I want to use subqueries to achieve this. This is the subquery I came up with:
SELECT `client_profiles`.*
FROM `client_profiles`
INNER JOIN `contacts`
ON `contacts`.`id` = `client_profiles`.`contact_id`
WHERE (client_profiles.id =
(SELECT `client_profiles`.`id` FROM `client_profiles` ORDER BY created_at desc LIMIT 1))
However, this is only returning one result. It should return client_profiles with id 9 and 11.
What is wrong with my subquery?
It looks like you were trying to filter twice on the client_profile table, once in the JOIN/ON clause and another time in the WHERE clause.
Moving everything in the where clause looks like this:
SELECT `cp`.*
FROM `contacts`
JOIN (
SELECT
`client_profiles`.`id`,
`client_profiles`.`contact_id`,
`client_profiles`.`created_at`
FROM `client_profiles`
ORDER BY created_at DESC
LIMIT 1
) cp ON `contacts`.`id` = `cp`.`contact_id`
Tell me what you think.
Should be something like maybe:
SELECT *
FROM `client_profiles`
INNER JOIN `contacts`
ON `contacts`.`id` = `client_profiles`.`contact_id`
GROUP BY `client_profiles`.`contact_id`
ORDER BY created_at desc;
http://sqlfiddle.com/#!2/a3f21b/9
You need to prequery the client profiles table grouped by each contact.. From that, re-join to the client to get the person, then again to the client profiles table based on same contact ID, but also matching the max date from the internal prequery using max( created_at )
SELECT
c.id,
c.first_name,
c.last_name,
IDByMaxDate.maxCreate,
cp.id as clientProfileID
from
( select contact_id,
MAX( created_at ) maxCreate
from
client_profiles
group by
contact_id ) IDByMaxDate
JOIN contacts c
ON IDByMaxDate.contact_id = c.id
JOIN client_profiles cp
ON IDByMaxDate.contact_id = cp.contact_id
AND IDByMaxDate.maxCreate = cp.created_at
IT IS NOT THE SAME QUESTION AS : Using LIMIT within GROUP BY to get N results per group?
but i admit it is similar.
I need to select the first 2 rows per person.
the rows are ordered by Year received
Problem : there is a possibility than 2 data were entered the same month (Date is entered YYYY-MM)
The query I came with (following the referred question) is stuck in an BIG loop.
SELECT *
FROM `table_data` as b
WHERE (
SELECT count(*) FROM `table_data` as a
WHERE a.Nom = b.Nom and a.year < b.year
) <= 2;
Sample Data :
A | year | Nom
---------------------
b | 2011-01 | Tim
---------------------
d | 2011-01 | Tim
---------------------
s | 2011-01 | Tim
---------------------
a | 2011-03 | Luc
---------------------
g | 2011-01 | Luc
---------------------
s | 2011-01 | Luc
Should export :
A | year | Nom
---------------------
b | 2011-01 | Tim
---------------------
d | 2011-01 | Tim
---------------------
a | 2011-03 | Luc
---------------------
g | 2011-01 | Luc
(
-- First get a set of results as if you only wanted the latest entry for each
-- name - a simple GROUP BY from a derived table with an ORDER BY
SELECT *
FROM (
SELECT *
FROM `table_data`
ORDER BY `year` DESC
) `a`
GROUP BY `Nom`
)
UNION
(
-- Next union it with the set of result you get if you apply the same criteria
-- and additionally specify that you do not want any of the rows found by the
-- first operation
SELECT *
FROM (
SELECT *
FROM `table_data`
WHERE `id` NOT IN (
SELECT `id`
FROM (
SELECT *
FROM `table_data`
ORDER BY `year` DESC
) `a`
GROUP BY `Nom`
)
ORDER BY `year` DESC
) `b`
GROUP BY `Nom`
)
-- Optionally apply ordering to the final results
ORDER BY `Nom` DESC, `year` DESC
I feel sure there is a shorter way of doing it but right now I can't for the life of me work out what it is. That does work, though - assuming you have a primary key (which you should) and that it is called id.
I've got a table that looks something like this:
CREATE TABLE `mailer__opens` (
`id` int(10) unsigned NOT NULL auto_increment,
`idSubscriber` int(10) unsigned NOT NULL,
`date` datetime NOT NULL,
PRIMARY KEY (`id`)
)
I'm trying to build a query which returns only the results where the value in idSubscriber is repeated 5 or more times. (I hope I'm explaining this right).
EG, if the data in the table looked like this:
id | idSubscriber | date
------------------------------
1 | 00001 | 2010-01-01
2 | 00002 | 2010-01-02
3 | 00001 | 2010-01-05
4 | 00003 | 2010-01-26
5 | 00004 | 2010-02-14
6 | 00001 | 2010-02-28
7 | 00002 | 2010-03-05
8 | 00001 | 2010-03-06
9 | 00003 | 2010-03-10
10 | 00001 | 2010-04-01
11 | 00004 | 2010-05-06
12 | 00002 | 2010-05-08
I'd be interested in records 1, 3, 6, 8 and 10, because the idSubscriber 00001 has 5 or more records.
Can anyone provide me with a query that would do this? Thank you.
To list the idSubscriber that has repeated five of more times you can use:
select idSubscriber
from mailer__opens
group by(idSubscriber) having count(*) >= 5;
To get the rows corresponding to such an idSubscriber you can use:
select *
from mailer__opens
where idSubscriber in
( select idSubscriber
from mailer__opens
group by(idSubscriber) having count(*) >= 5 )
You must use GROUP BY with a HAVING clause:
SELECT id FROM mailer__opens GROUP BY idSubscriber HAVING COUNT(id) >= 5
First of all you need to get the different idSubscriber values:
SELECT idSubscriber
FROM `mailer__opens`
GROUP BY idSubscriber
HAVING count( * ) >=5
For the given dataset, this will fetch only one value: 1
Then you need to select all rows where the idSubscriber is equal to those values. Therefore, your final query becomes:
SELECT *
FROM mailer__opens
WHERE idsubscriber
IN (
SELECT idSubscriber
FROM `mailer__opens`
GROUP BY idSubscriber
HAVING count( * ) >=5
)
SELECT id FROM mailer__opens WHERE idSubscriber IN (SELECT idSubscriber FROM mailer__opens GROUP BY idSubscriber HAVING COUNT(id) >= 5)