Can someone help. I have strange behavior on SQL query to "messages" table.
It supposed to return MAX(id)'s for each user contacted target user.
Table is simple:
id(int, ai) | from(int) | dest(int) | text(txt) | time(int) | msg_status(int)
USERS table have only 5 test users.
MSG table have about 40 messages.
When I query most of user ids(1, 2, 3, 4) - I receive normal result.
When I query one specific user No.5- I receive ONE less result.
The query is:
SELECT MAX(`id`) FROM `msg` WHERE `from` = '5' OR `dest` = '5'
GROUP BY (IF(`from` > `dest`, `from`, `dest`)), (IF(`from` < `dest`, `dest`, `from`));
For most users it gives normal result. For example for user 1 I have:
MAX(id) 37, 30, 33, 36
And it is OK as user No.1 have conversation messages with all other 4 users.
But for user No.5 I have:
MAX(id) 36
Thus this is not correct. As user No.5 have last messages as described here:
id from dest text
35 5 2 hellp
36 5 1 hi there
So there is one less result, as it have to be something like:
MAX(id) 35, 36
But it is not.
Can someone suggest what is wrong?
UPD.
Simplifying the query:
SELECT * FROM `msg` WHERE `id` IN (SELECT MAX(`id`) FROM `msg`
WHERE `from` = '5' OR `dest` = '5' GROUP BY `from`, `dest`);
I receive result:
id from desr text
32 1 5 test
35 5 2 hello
36 5 1 test2
So oroginal query have to produce 35 and 36 result, thus giving 36 only...
There's a logic error in the GROUP BY expressions:
GROUP BY
(IF(`from` > `dest`, `from`, `dest`)),
(IF(`from` < `dest`, `dest`, `from`));
If from > dest, then this is equivalent to GROUP BY from, from; if from < dest, then this is GROUP BY dest, dest. For the two example rows with from = 5, they're grouped by from, and thus in the same group, and thus MAX(id) is 36, with no 35 in the results.
In contrast, ID 1 will be the minimum when compared to any other user ID, so when querying for ID 1, the query will group by the other IDs, guaranteeing they remain separate groups. That is why the query works for ID 1.
To avoid this error, it's better to use the Greatest and Least functions:
GROUP BY Greatest(`from`, `dest`), Least(`from`, `dest`)
The 2 GROUP BY statements should return the same value (5) for both Id 35 and 36 so MAX(id) will return 36 - which is what you are getting.
Your SQL matches your result so it all seems to be working. If the result is not what you want then you’ll need to change your SQL - and if you want help with that then you’ll need to explain what the logic is that would return IDs 35 and 36
For a long time I have been trying to figure out how to make Hottest Posts
What I want to achieve : ORDER BY MOST UPVOTED IN LESS TIME
For example I got 4 posts:
ID UPVOTES(Total) UPVOTES(Weekly) DATE
1 50 50 01.09.2017
2 421 6 25.07.2017
3 71 50 13.08.2017
4 111 37 15.08.2017
And It would need to order like 1 -> 3 -> 4 -> 2
My Goal is to get UPVOTES(Weekly) - > I Don't know how to calculate
it. I just made it here, to better explain what I want to achieve.
I have got 2 database tables fun_posts and fun_post_upvotes
I was trying to achieve it like this, but it didn't work, it just ordered by id or ordered by upvotes
$stmt = $this->conn->prepare=("SELECT * , (SELECT COUNT(*) FROM
fun_post_upvotes WHERE image_id=fun_posts.id GROUP BY image_id) FROM fun_posts
ORDER BY fun_posts.id DESC, fun_posts.upvotes DESC");
This is working a part of it.
SELECT fun_posts_upvotes.image_ID, COUNT(image_ID) as 'Upvotes' FROM fun_posts_upvotes GROUP BY fun_posts_upvotes.image_ID ORDER BY Upvotes DESC;
Just try it and add the Date part. ;-) you can ask again if you tried some :P
If I understand the problem correctly you should quite easily be able to apply the following to your problem:
MYSQL Order By Sum of Columns
Order By Sum of Two Fields
CREATE TABLE `tb1` (
`id` int(11) NOT NULL,
`Name` varchar(50) NOT NULL,
`up` int(11) NOT NULL,
`Down` int(11) NOT NULL,
`Date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
SELECT `Name`, (`tb1`.`up`/ DATEDIFF(NOW(),`tb1`.`Date` )) as `heat`
FROM `tb1`
ORDER BY (`tb1`.`up`/ DATEDIFF(`tb1`.`Date`, NOW())) ASC
This should illustrate my point
I think adding to your query:
ORDER BY UPVOTES(Weekly) DESC
would work for your issue.
So maybe it's due to lack of sleep, but I am having a major brain malfunction and can't remember what is going wrong here. Here is my statement:
SELECT DISTINCT `county`, COUNT(*)
FROM `ips`
WHERE `county` != 'NULL' AND `county` != '' AND
EXISTS (SELECT * FROM `pages`
WHERE (`timestamp` BETWEEN FROM_UNIXTIME(?) AND FROM_UNIXTIME(?)))
GROUP BY `county`
I'm expecting the results to be something like:
County | Number
Some county | 42
Other county | 27
My pages table has a timestamp of each time a page is viewed by a user, so if they viewed a page between the date, the county from the IP table is selected and the number of that total county is being populated as the num. I'm using PDO and i'm passing in two times that I've used strtotime() on.
I'm currently stuck. All help is apprieciated. Hopefully it's not some stupid little mistake that I've overlooked.
You cant compare null with != you need to use is not null.
SELECT `county`, COUNT(*)
FROM `ips`
WHERE `county` IS NOT NULL AND `county` != '' AND
EXISTS (SELECT 1 FROM `pages`
WHERE (`timestamp` BETWEEN FROM_UNIXTIME(?) AND FROM_UNIXTIME(?)))
GROUP BY `county`
I have a MySQL query which does exactly what I want, but it takes anywhere between 110 & 130 seconds to process. The problem is that it works in tandem with a software that times out 20 seconds after making the query.
Is there anything I can do to speed up the query? I'm considering moving the db over to another server, but are there any more elegant options before I go that route?
-- 1 Give me a list of IDs & eBayItemIDs
-- 2 where it is flagged as bottom tier
-- 3 Where it has been checked less than 168 times
-- 4 Where it has not been checked in the last hour
-- 5 Or where it was never checked but appears on the master list.
-- 1 Give me a list of IDs & eBayItemIDs
SELECT `id`, eBayItemID
FROM `eBayDD_Main`
-- 2 where it is flagged as bottom tier
WHERE `isBottomTier`='0'
-- 3 Where it has been checked less than 168 times
AND (`id` IN
(SELECT `mainid`
FROM `eBayDD_History`
GROUP BY `mainid`
HAVING COUNT(`mainID`) < 168)
-- 4 Where it has not been checked in the last hour
AND id IN
(SELECT `mainID`
FROM `eBayDD_History`
GROUP BY `mainID`
HAVING ((TIME_TO_SEC(TIMEDIFF(NOW(), MAX(`dateCollected`)))/60)/60) > 1))
-- 5 Or where it was never checked but appears on the master list.
OR (`id` IN
(SELECT `id`
FROM `eBayDD_Main`)
AND `id` NOT IN
(SELECT `mainID`
FROM `eBayDD_History`))
If I understand the logic correctly, you should be able to replace this logic with this:
select m.`id`, m.eBayItemID
from `eBayDD_Main` m left outer join
(select `mainid`, count(`mainID`) as cnt,
TIME_TO_SEC(TIMEDIFF(NOW(), MAX(`dateCollected`)))/60)/60) as dc
from `eBayDD_History`
group by `mainid`
) hm
on m.mainid = hm.mainid
where m.`isBottomTier` = '0' and hm.cnt < 168 and hm.dc > 1 or
hm.mainid is null;
I am not a MySQL guru at all, and I would really appreciate if someone takes some time to help me. I have three tables as shown below:
TEAM(teamID, teamName, userID)
YOUTH_TEAM(youthTeamID, youthTeamName, teamID)
YOUTH_PLAYER(youthPlayerID, youthPlayerFirstName, youthPlayerLastName, youthPlayerAge, youthPlayerDays, youthPlayerRating, youthPlayerPosition, youthTeamID)
And this is the query that I have now:
SELECT team.teamName, youth_team.youthTeamName, youth_player.*
FROM youth_player
INNER JOIN youth_team ON youth_player.youthTeamID = youth_team.youthTeamID
INNER JOIN team ON youth_team.teamID = team.teamID
WHERE youth_player.youthPlayerAge < 18
AND youth_player.youthPlayerDays < 21
AND youth_player.youthPlayerRating >= 5.5
What I would like to add to this query is a more thorough checks like the following:
if player has 16 years, and his position is scorer, then the player should have at least 7 rating in order to be returned
if player has 15 years, and his position is playmaker, then the player should have at least 5.5 rating in order to be returned
etc., etc.
How can I implement these requirements in my query (if possible), and is that query going to be a bad-way solution? Is it maybe going to be better if I do the selection with PHP code (if we suppose I use PHP) instead of doing it in the query?
Here is a possible solution with an additional "criteria/filter" table:
-- SAMPLE TEAMS: Yankees, Knicks:
INSERT INTO `team` VALUES (1,'Yankees',2),(2,'Knicks',1);
-- SAMPLE YOUTH TEAMS: Yankees Juniors, Knicks Juniors
INSERT INTO `youth_team` VALUES (1,'Knicks Juniors',1),(2,'Yankees Juniors',2);
-- SAMPLE PLAYERS
INSERT INTO `youth_player` VALUES
(1,'Carmelo','Anthony',16,20,7.5,'scorer',1),
(2,'Amar\'e','Stoudemire',17,45,5.5,'playmaker',1),
(3,'Iman','Shumpert',15,15,6.1,'playmaker',1),
(4,'Alex','Rodriguez',18,60,3.5,'playmaker',2),
(5,'Hiroki','Kuroda',16,17,8.7,'scorer',2),
(6,'Ichiro','Suzuki',19,73,8.3,'playmaker',2);
-- CRITERIA TABLE
CREATE TABLE `criterias` (
`id` int(11) NOT NULL,
`age` int(11) DEFAULT NULL,
`position` varchar(45) DEFAULT NULL,
`min_rating` double DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- SAMPLE CRITERIAS
-- AGE=16, POSITION=SCORER, MIN_RATING=7
-- AGE=15, POSITION=PLAYMAKER, MIN_RATING=5.5
INSERT INTO `criterias` VALUES (1,16,'scorer',7), (2,15,'playmaker',5.5);
Now your query could look like:
SELECT team.teamName, youth_team.youthTeamName, youth_player.*
FROM youth_player
CROSS JOIN criterias
INNER JOIN youth_team ON youth_player.youthTeamID = youth_team.youthTeamID
INNER JOIN team ON youth_team.teamID = team.teamID
WHERE
(
youth_player.youthPlayerAge < 18
AND youth_player.youthPlayerDays < 21
AND youth_player.youthPlayerRating >= 5.5
)
AND
(
youth_player.youthPlayerAge = criterias.age
AND youth_player.youthPlayerPosition = criterias.position
AND youth_player.youthPlayerRating >= criterias.min_rating
)
This yields (shortened results):
teamName youthTeamName youthPlayerName Age Days Rating Position
=============================================================================
Yankees "Knicks Juniors" Carmelo Anthony 16 20 7.5 scorer
Yankees "Knicks Juniors" Iman Shumpert 15 15 6.1 playmaker
Knicks "Yankees Juniors" Hiroki Kuroda 16 17 8.7 scorer
Doing it in the query is quite fine...... as long as it doesn't get too messed up. You can perform a lot of stuff in your query, but it may get hard to maintain. So if it gets too long and you want somebody else to take a look at it, you should split it up or find a solution in your php-script.
As for your requirements add this too your WHERE-part:
AND
(
(YOUTH_PLAYER.youthPlayerAge >= 16 AND YOUTH_PLAYER.youthPlayerPosition = 'scorer' AND YOUTH_PLAYER.youthPlayerRating >= 7)
OR (YOUTH_PLAYER.youthPlayerAge >= 15 AND YOUTH_PLAYER.youthPlayerPosition = 'playmaker' AND YOUTH_PLAYER.youthPlayerRating >= 5.5)
)