How do I make COUNT work how I need it to? - mysql

I'm running this query, it works except it doesn't return what I need...
SELECT COUNT(up.profileOwnerUserNumber)
FROM profiles up
INNER JOIN userRatings ur
ON (ur.userRatingTargetUser = up.profileOwnerUserNumber)
WHERE ur.userRatingDateTime>(now()-INTERVAL 1 WEEK)
I get a return of 8 from this query. It's counting all instances found where (ur.userRatingTargetUser = up.profileOwnerUserNumber). But the userRatings table has 4 genuinely different entries in it - the other 4 are duplicates of numbers already found. I want my COUNT to return 4 - the number of distinctly different ur.userRatingTargetUser numbers found, not all 8 entries.
Table userRatings:
userRatingNumber int (autoincrement)
userRatingTargetUser int
Table profiles:
profileNumber int (autoincrement)
profileOwnerUserNumber int
Both userRatingTargetUser and profileOwnerUserNumber have int values that can match because they are set using another table:
Table users:
userNumber int (autoincrement)
How do I change my query so that I no longer count these extra records? SELECT DISTINCT didn't work.

Have you tried GROUP BY:
SELECT COUNT(up.profileOwnerUserNumber)
FROM profiles up
INNER JOIN userRatings ur
ON (ur.userRatingTargetUser = up.profileOwnerUserNumber)
WHERE ur.userRatingDateTime>(now()-INTERVAL 1 WEEK)
GROUP BY up.profileOwnerUserNumber

COUNT is an aggregate function, you should use GROUP BY.
http://dev.mysql.com/doc/refman/5.1/en/group-by-functions.html

Related

mySQL Check if all link items are a specified value

I want to check if all linked Items that are a specified value. I am not sure how to properly explain it but the example is pretty self-explanatory in my opinion.
Example Database (simplified)
Table Groups
PK_Groups int
Groupname varchar
Table Person
PK_Person int
Name varchar
isAdult tinyint(1)
FK_Groups int
How can I check in which groups are only adults (1 query that returns all groups)?
Is there a way to do it in SQL or do I have to do "manually"?
Thanks in advance
SELECT PK_Groups
FROM Groups
INNER JOIN Person on PK_Group = FK_Groups
WHERE isAdult = 0
WHERE doesn´t work because there are some that are adult
and grouping by name and checking if adult doesnt work either because its inside the group
Couting non adults for each group would work (If Count <=0) but only for each group and not all groups at once
Check the minimum value of isAdult for each group. If they're all adults, the minimum value is 1.
SELECT PK_Groups
FROM Groups
INNER JOIN Person on PK_Groups = FK_Groups
GROUP BY PK_Groups
HAVING MIN(isAdult) = 1
Note that this isn't the general way to test that all values in a set are a specific value. It only works when the value you're trying to check for is the highest possible value (you can also test for the lowest value by changing MIN() to MAX()).
The more general condition can be tested with:
HAVING SUM(column = value) = COUNT(*)

Select rows from a table not matched in another table

So I have the following:
A lookup table that has two columns and looks like this for example:
userid moduleid
4 4
I also have a users table that has a primary key userid which the lookup table references. The user table has a few users lets say, and looks like this:
userid
1
2
3
4
In this example, it show that the user with ID 4 has a match with module ID 4. The others are not matched to any moduleid.
I need a query that gets me data from the users table WHERE the moduleid is not 4. In my application, I know the module but I don't know the user. So the query should return the other userids apart from 4, because 4 is already matched with module ID 4.
Is this possible to do?
I think I understand your question correctly. You can use a sub-query to cross-check the data between both tables using the NOT IN() function.
The following will select all userid records from the user_tbl table that do not exist in the lookup_tbl table:
SELECT `userid`
FROM `user_tbl`
WHERE `userid` NOT IN (
SELECT DISTINCT(`userid`) FROM `lookup_tbl` WHERE moduleid = 4
)
There are several ways to do this, one pretty intuitive way (in my opinion) is the use an in predicate to exclude the users with moduleid 4 in the lookup table:
SELECT * FROM Users WHERE UserID NOT IN (SELECT UserID FROM Lookup WHERE ModuleID = 4)
There are other ways, with possibly better performance (using a correlated not exists query or a join for instance).
One other option is to use a LEFT JOIN so that you can get the values from both tables, even when there is not a match. Then, pick the rows where there is no userid value from the lookup table.
SELECT u.userid
FROM usersTable u
LEFT JOIN lookupTable lt ON u.userid = lt.userid
WHERE lt.userid IS NULL
Are you looking for a query like this?
select userid from yourtablename where moduleid<>4

Using GROUP BY and returning all criteria matching records

I have a table that stores various types of flags. Each flag type has a reasonId column. So you could flag a post as spam and use several reasons; as abusive and use several reasons, etc.
I need a query to return all spam flags (flagTypeId=1) on a single post and, in addition, an extra column to return the number of times a flag reason occurred (reasonId). I need the full record set because I need to tack the user data, thus returning a grouped result is not sufficient by itself:
Assuming I have a flags table with PK id, int flagTypeId, int postId, int reasonId, and userId, I wrote this:
SELECT id, flagTypeId, postId, userId, reasonId, COUNT(reasonId) reasonCount
FROM flags
WHERE flagTypeId = #flagTypeId AND postId = #postId
GROUP BY reasonId
ORDER BY reasonCount DESC
This query does not return the correct number of records. If I have four spam records, and two of those four share the same reasonId, only three records come back. I want all four records to come back with an extra column showing the number of times a reasonId occurred.
Any ideas how I can modify my query to achieve this?
SAMPLE INPUT/OUTPUT
Assuming three peope flagged the same post, and two of them used the same flag reason.
id flagTypeId postid reasonid userid count
1 1 1 1 1 2
2 1 1 1 2 2
3 1 1 2 3 1
Would this work:
SELECT id, flagTypeId, postId, flags.reasonId, x.reasonCount
FROM
flags
JOIN (SELECT reasonid, COUNT(*) AS reasonCount FROM flags WHERE flagTypeId = #flagTypeId AND postId = #postId GROUP BY reasonid) AS X
ON flags.reasonid = x.reasonid
WHERE
flagTypeId = #flagTypeId AND postId = #postId
I think you're going about it a little backwards. Keep in mind that, if you're already retrieving all the information in a collection of records, you already have the count of records, just by getting the size of the returned collection.
Tweak your query to remove the GROUP BY clause and COUNT column. Then, assuming it was something like PHP, and you fetched the results of the modified query into an array $flagReasons, you can just reference count($flagReasons) to get the count.

Help with an SQL Query to sum of the number of rows depending on an option in another table

What I have are two tables:
mark_notifications
mark_notifications_options
The mark_notifications table contains rows of data that include a column tid and userid
The mark_notifications_options table contains a special column grouptogether
What I am trying to achieve is that if the userid's mark_notifications_options.grouptogether value is set to 0, it will add up every row that matches his userid in the mark_notifications table
However, if the userid's mark_notifications_options.grouptogether value is set to 1, it will add up every row that matches his userid where all the tids are grouped, so that if there no matter how many times the same tid value comes up, it only gets counted as 1. I also would like to count the times tid = 0 as a separate entitiy (but NOT grouped) and then I would just add the values later in php.
This is what I have come up with so far, but the resulting values dont make any sense at all, im getting results that number in the thousands (when it should be a low number like 8 for example).
SELECT
mark_notifications_options.grouptogether,
COUNT(mark_notifications.threadid) AS ungrouped,
SUM(mark_notifications.threadid = 0) AS total_zero,
COUNT(DISTINCT mark_notifications.threadid) AS grouped
FROM mark_notifications, mark_notifications_options
WHERE mark_notifications.userid = $userid
GROUP BY mark_notifications_options.grouptogether
Thanks!!!
You were missing a join predicate, and so were getting the cartesian product (ie resulting in n x n rows).
Try this:
SELECT
mark_notifications_options.grouptogether,
COUNT(mark_notifications.threadid) AS ungrouped,
SUM(mark_notifications.threadid = 0) AS total_zero,
COUNT(DISTINCT mark_notifications.threadid) AS grouped
FROM mark_notifications mark_notifications
LEFT JOIN mark_notifications_options mark_notifications_options on mark_notifications_options.userid = mark_notifications.userid
WHERE mark_notifications.userid = $userid
GROUP BY mark_notifications_options.grouptogether

MySQL query - find "new" users per day

I have a table of data with the following fields
EventID : Int, AutoIncrement, Primary Key
EventType : Int ' Defines what happened
EventTimeStamp : DateTime ' When the Event Happened
UserID : Int ' Unique
The query needs to tell me how many events occurred with new UserIDs for each day in the whole set. So, for each day, how many events exist which have a UserID which doesn't exist in any prior day. I've tried lots, and I can get unique users per day, but can't work out how to get 'NEW' users per day.
Select count(EventId) from table
where
UserId
not in (select UserId from table where EventTimeStamp < now() - interval 1 day)
Thank you all for your help - I've voted up the assistance. Here's what I did:
I created these 2 views (I needed to end up with a view, and had to create 2 as it seems you can't nest select statements within views).
Sightings:
select min(to_days(`Events`.TimeStamp)) AS Day0,
`Events`.TimeStamp AS TimeStamp,
`Events`.UserID AS UserID
from `Events` group by `Events`.UserID order by `Events`.UserID
NewUsers:
select count(distinct Sightings.UserID) AS Count,
date(Sightings.TimeStamp) AS Date from Sightings
group by date(Sightings.TimeStamp)
Good question. I don't have an exact solution but here's the approach I've seen before:
Do a SELECT where you compare the EventTimeStamp with MIN(EventTimeStamp) for a given userID, as determined by a nested SELECT statement on the same table to calculate the MIN timestamp for each ID (e.g. GROUP BY UserID).
First get a table b with for each user when he first arrived,
then join that table to get all events for that user for that day.
SELECT DATE(a.EventTimeStamp), COUNT(*) FROM table a
JOIN
(SELECT MIN(EventTimeStamp) AS EventTimeStamp, UserID from table group by userID) b
ON a.UserID = b.UserID
AND DATE(a.EventTimeStamp) = DATE(b.EventTimeStamp)
GROUP BY DATE(a.EventTimeStamp)
86400-(EventTimeStamp) as new_users