I need to count repeated rows but only show them in results if at least one of them has status = 'new'.
______________
URL | Status
--------------
A new
A seen
B new
C seen
should echo:
___________
URL | SUM
-----------
A 2 (counts both the seen one and the new one because there is at least one nwe)
B 1
My idea is basically to count the repeated URLs and RIGHT JOIN it with the same table but only rows with Status = 'new' so that remaining rows disappear.
SELECT `userFlags` distinct(URL) WHERE Status = "new"
How do I add these conditions to the joining table and how is it called?
EDIT
I added Status = "new" to the query, how can I add distinct(URL) or nest the whole query on it?
SELECT userFlags.URL, COUNT( * ) AS SUM
FROM `userFlags`
RIGHT JOIN `userFlags` as u2 ON u2.Status = "new" AND userFlags.URL = u2.URL
GROUP BY u2.URL
ORDER BY SUM DESC
One possible answer is:
SELECT userFlags.URL, COUNT( * ) AS SUM
FROM `userFlags`
JOIN (select distinct URL from userflags where status = 'new') as u2 on u2.url = userflags.url
GROUP BY u2.URL
ORDER BY SUM DESC **strong text**
Try this :
Select userFlags.URL,Count(Status) AS SUM from userFlags
where Status = "new"
group by userFlags.URL
Edit
Select userFlags.URL,Count(Status) AS SUM from userFlags
where userFlags.URL in
(Select userFlags.URL from userFlags where Status = "new" )
group by userFlags.URL
Instead of an OUTER JOIN, do an INNER JOIN :
SELECT U1.URL, COUNT(*) AS Foo
FROM userFlags U1
INNER JOIN userFlags U2
ON U1.URL = U2.URL
AND U2.Status = 'new'
GROUP BY U1.URL;
If there is no row matching the join condition, then the row will not be added to the resultset. This filters out any URL that does not have at least one row where Status = new.
Edit: Removed the HAVING, for some reason I thought you only wanted rows where URL appeared more than once.
No need for a right join. I think that's just complicating things for you. Using a subquery to find the 'new' rows is one strategy.
select u2.URL, count(*) as SUM
from userFlags as u2
where u2.URL in (
select distinct u1.URL from userFlags as u1 where u1.Status = 'new'
) group by u2.URL;
Alternatively, this could be written as a join instead of a subquery.
select u2.URL, count(*) as SUM
from userFlags as u2
inner join (
select distinct u1.URL from userFlags as u1 where u1.Status = 'new'
) as subq on subq.URL = u2.URL
group by u2.URL;
Either one works. Here is a quick test to prove it:
mysql> create table userFlags (
-> URL varchar(255) not null,
-> Status enum('new', 'seen') not null,
-> index(URL),
-> index(Status)
-> ) engine=innodb;
Query OK, 0 rows affected (0.01 sec)
mysql> insert into userFlags (URL, Status) values ('A', 'new'), ('A', 'seen'), ('B', 'new'), ('C', 'seen');
Query OK, 4 rows affected (0.01 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select * from userFlags;
+-----+--------+
| URL | Status |
+-----+--------+
| A | new |
| A | seen |
| B | new |
| C | seen |
+-----+--------+
4 rows in set (0.00 sec)
mysql> select u2.URL, count(*) as SUM
-> from userFlags as u2
-> where u2.URL in (
-> select distinct u1.URL from userFlags as u1 where u1.Status = 'new'
-> ) group by u2.URL;
+-----+-----+
| URL | SUM |
+-----+-----+
| A | 2 |
| B | 1 |
+-----+-----+
2 rows in set (0.00 sec)
mysql> select u2.URL, count(*) as SUM
-> from userFlags as u2
-> inner join (
-> select distinct u1.URL from userFlags as u1 where u1.Status = 'new'
-> ) as subq on subq.URL = u2.URL
-> group by u2.URL;
+-----+-----+
| URL | SUM |
+-----+-----+
| A | 2 |
| B | 1 |
+-----+-----+
2 rows in set (0.01 sec)
Related
Hello I had this table:
id | user_id | status
1 | 34 | x
2 | 35 | x
3 | 42 | x
4 | 42 | y
My goal is to count the data with X status except if the user has a another data with Y status, it will exclude in the count. So instead of 3, it will only count 2 since the 3rd row has another data which is the 4th row with y status.
SELECT * FROM logs
AND user_id NOT IN (SELECT user_id FROM logs WHERE status = 'y')
GROUP BY user_id;
We can try the following aggregation approach:
SELECT COUNT(*) AS cnt
FROM
(
SELECT user_id
FROM logs
GROUP BY user_id
HAVING MIN(status) = MAX(status) AND
MIN(status) = 'x'
) t;
The above logic only counts a user having one or more records only having x status.
You can do it this way, I only modify a bit on your sql
SELECT COUNT(*) FROM (
SELECT u_id FROM tbl WHERE u_id NOT IN
(SELECT u_id FROM tbl WHERE status = 'y')
GROUP BY u_id
) as t
You can use inner join:
SELECT
count(t1.id) AS `cnt`
FROM
`test` AS t1,
`test` AS t2
WHERE
t2.`status`='y'
&& t1.`user_id` != t2.`user_id`;
I have a query that returns the counts from a database. Sample output of the query:
23
14
94
42
23
12
The query:
SELECT COUNT(*)
FROM `submissions`
INNER JOIN `events`
ON `submissions`.event_id = `events`.id
WHERE events.user_id IN (
SELECT id
FROM `users`
WHERE users.created_at IS NOT NULL
GROUP BY `events`.id
Is there a way to easily take the output and split it into pre-defined ranges of values (0-100, 101-200, etc), indicating the number of rows that fall into a particular range?
Use a case expression in select clause.
SELECT `events`.id ,
case when COUNT(`events`.id) between 0 and 100 then '0 - 100'
when COUNT(`events`.id) between 100 and 200 then '100 - 200'
end as Range
FROM `submissions`
INNER JOIN `events`
ON `submissions`.event_id = `events`.id
WHERE events.user_id IN (
SELECT id
FROM `users`
WHERE users.created_at IS NOT NULL
GROUP BY `events`.id
Use conditional count by leveraging SUM() aggregate.
If you need your ranges in columns
SELECT SUM(CASE WHEN n BETWEEN( 0 AND 100) THEN 1 ELSE 0 END) '0-100',
SUM(CASE WHEN n BETWEEN(101 AND 200) THEN 1 ELSE 0 END) '101-200'
-- , add other ranges here
FROM (
SELECT COUNT(*) n
FROM submissions s JOIN events e
ON s.event_id = e.id JOIN users u
ON e.user_id = u.id
WHERE u.created_at IS NOT NULL
GROUP BY e.id
) q
Sample output
+-------+---------+
| 0-100 | 101-200 |
+-------+---------+
| 2 | 3 |
+-------+---------+
1 row in set (0.01 sec)
If you'd rather have it as a set you can do
SELECT CONCAT(r.min, '-', r.max) `range`,
SUM(n BETWEEN r.min AND r.max) count
FROM (
SELECT COUNT(*) n
FROM submissions s JOIN events e
ON s.event_id = e.id JOIN users u
ON e.user_id = u.id
WHERE u.created_at IS NOT NULL
GROUP BY e.id
) q CROSS JOIN (
SELECT 0 min, 100 max
UNION ALL
SELECT 101, 200
-- add other ranges here
) r
GROUP BY r.min, r.max
Sample output
+---------+-------+
| range | count |
+---------+-------+
| 0-100 | 2 |
| 101-200 | 3 |
+---------+-------+
2 rows in set (0.01 sec)
i have table like :
id IP Subnet Duplicates Valid
1 foo 16 1
2 bar 24 1
3 foo 28 1
4 foo 32 1
i want update description with id of duplicated row . something like:
id IP Subnet Duplicates Valid
1 foo 16 3,4 0
2 bar 24 1
3 foo 28 1,4 0
4 foo 32 1,3 0
Here is my query :
update tblSample inner join (
select
t1.Id,
group_concat(t2.Id) dups
from
tblSample t1 inner join tblSample t2
on t1.Id<>t2.Id ) AND
((t1.IP >> (32-LEAST(t1.Subnet,t2.Subnet))
<< (32-LEAST(t1.Subnet,t2.Subnet))
=
((t2.IP >> (32-LEAST(t1.Subnet,t2.Subnet))
<< 32-LEAST(t1.Subnet,t2.Subnet)))
group by
t1.Id
) s on tblSample.Id = s.Id
set
Valid=0 ,Duplicates=dups
my code works but its very slow ( about 53 second for 10000 record )
How can i improve speed ?
is there any way that i can decrease comparison operation.
Here is a solution without self join in your sub query, maybe will not improve performance greatly, but try it, and also, try to explain it and yours.
update tblSample t1
join (
select name, group_concat(id order by id) as description
from tblSample
group by name
) t2
on t1.name = t2.name and cast(t1.id as char) <> t2.description
set t1.description = replace(
replace(
replace(
t2.description,
concat(',', t1.id, ','),
',')
, concat(',', t1.id)
, '')
, concat(t1.id, ',')
, '')
;
Demo Here
you can also use this query for test:
UPDATE dupli d
SET description = (
SELECT CONCAT('duplicate in ',GROUP_CONCAT(`id` ORDER BY id))
FROM (SELECT * FROM dupli) AS d1
WHERE `name` = d.`name` AND id <> d.id ) ;
sample
MariaDB [yourSchema]> UPDATE dupli d
-> SET description = (
-> SELECT CONCAT('duplicate in ',GROUP_CONCAT(`id` ORDER BY id))
-> FROM (SELECT * FROM dupli) AS d1
-> WHERE `name` = d.`name` AND id <> d.id ) ;
Query OK, 0 rows affected, 1 warning (0.00 sec)
Rows matched: 4 Changed: 0 Warnings: 1
MariaDB [yourSchema]> select * from dupli;
+----+------+------------------+
| id | name | description |
+----+------+------------------+
| 1 | foo | duplicate in 3,4 |
| 2 | bar | NULL |
| 3 | foo | duplicate in 1,4 |
| 4 | foo | duplicate in 1,3 |
+----+------+------------------+
4 rows in set (0.00 sec)
MariaDB [yourSchema]>
I got a table votes that indicates me if a user voted for a specific movie. It also shows me how many movies a user has voted for.
id_film | id_user | voting
----------------------------
1 | 1 | 7
1 | 33 | 5
3 | 1 | 9
4 | 7 | 7
4 | 2 | 8
4 | 1 | 6
6 | 1 | 6
... | ... | ...
I want to get a list of id_film's which are related to id_user's in this way:
Get all id_film's from a specific id_user like
SELECT id_film FROM votes WHERE id_user = 1
Grab every id_user which is related
SELECT DISTINCT v.user FROM votes v WHERE id_film IN ( id_film's )
Then SELECT id_film's FROM votes v WHERE user IN ( "user list from previous query" ) except id_film's from first query.
This was my first attempt:
SELECT id_film, film.title, film.originaltitle, COUNT(*)
FROM votes v
INNER JOIN film ON v.id_film = film.id
WHERE user IN
(
SELECT DISTINCT v.user
FROM votes v
WHERE id_film IN
(
SELECT id_film
FROM votes v
WHERE user = 1
)
)
AND
id_film NOT IN
(
SELECT id_film
FROM votes v
WHERE user = 1
)
GROUP BY id_film
It doesn't work. MySQL took too long for a result and I restarted XAMPP.
So I tried another SELECT, this time with JOINS:
SELECT DISTINCT v.id_film AS vFilm, v1.user AS v1User, v2.id_film AS v2Film
FROM votes v
LEFT OUTER JOIN votes v1 ON v1.id_film = v.id_film
LEFT OUTER JOIN votes v2 ON v1.user = v2.user
WHERE v.user = 1
AND v1.user != 1
AND v2.id_film NOT
IN
(
SELECT id_film
FROM votes
WHERE user = 1
)
GROUP BY v2.id_film
Also doesn't work, but when I tried it without the NOT IN condition in the end it works! (It took appr. 13 sec.) :-(
Here is the working query.
SELECT DISTINCT v2.id_film AS v2Film
FROM votes v
LEFT OUTER JOIN votes v1 ON v1.id_film = v.id_film
LEFT OUTER JOIN votes v2 ON v1.user = v2.user
WHERE v.user = 1
AND v1.user != 1
With Output
v2Film
---------
1
13
14
58
4
...
But this query doesn't except id_film's from first query.
Because I know that user 1 already voted for id_film 1.
So, am I totally wrong with my logic or is my code too complex for this?
I have:
TABLE: USERS
UID | NAME
1 | Bob
2 | John
And I have:
TABLE: HITS
HITID | UID
1 | 1
2 | 2
3 | 2
4 | 1
5 | 2
6 | 2
I want:
UID | HITS
1 | 2
2 | 4
Seems simple enough, but I can't seem to do it?
Try this:
SELECT UID, COUNT(UID) HITS FROM HITS
GROUP BY UID;
This Might help you
DECLARE #USERS TABLE(UID INT, NAME VARCHAR(20))
INSERT INTO #USERS (UID,NAME) VALUES ('1','Bob'),('2','John')
DECLARE #HITS TABLE(HITID INT,UID INT)
INSERT INTO #HITS (HITID,UID) VALUES('1','1'),('2','2'),('3','2'),('4','1'),('5','2'),('6','2')
Use JOIN if you want to use Both USERS Table and HITS Table
SELECT U.UID,COUNT(H.HITID) AS HITS FROM #USERS AS U INNER JOIN #HITS AS H ON U.UID = H.UID GROUP BY U.UID
OR Use Simple Query If you want to use only HITS Table
SELECT UID, COUNT(UID) HITS FROM #HITS GROUP BY UID
I also Created Temp tables in this.
SELECT b.UID, COUNT(b.UID) HITS FROM HITS a, USERS b
WHERE a.UID=b.UID
GROUP BY UID
This should work
This would do the trick
SELECT H.UID, COUNT(*) AS 'HITS'
FROM HITS H
GROUP BY H.UID
if you want to have the name of the users, then you need to join it
SELECT a.Name, COUNT(*) totalCount
FROM users a
INNER JOIN HITS b
ON a.UID = b.UID
GROUP BY a.UID
SQLFiddle Demo