MySql Limit results per grouping in query with multiple joins - php

I have this query
select distinct
loc.mID,
loc.city,
loc.state,
loc.zip,
loc.country,
loc.latitude,
loc.longitude,
baseInfo.firstname,
baseInfo.lastname,
baseInfo.profileimg,
baseInfo.facebookID,
(((acos(sin(('37.8068406'*pi()/180)) * sin((`latitude`*pi()/180))+cos(('37.8068406'*pi()/180)) * cos((`latitude`*pi()/180)) * cos((('-121.3062367' - `longitude`)*pi()/180))))*180/pi())*60*1.1515) AS `distance`, teams.teamName, teams.leagueType, teams.teamType, teams.subcat
FROM memb_geo_locations loc
left join memb_friends friends on (friends.mID = loc.mID or friends.friendID = loc.mID) and (friends.mID = '100019' or friends.friendID = '100019')
join memb_baseInfo baseInfo on baseInfo.mID = loc.mID
join memb_teams teams on teams.mID = loc.mID
where
loc.primaryAddress = '1' and ((friends.mID is null or friends.friendID is null) or (friends.isactive = 2))
and
(teams.teamName like '%Buffalo Bills%' or teams.teamName like '%New England Patriots%' or teams.teamName like '%Dallas Cowboys%')
and
loc.mID != 100019
having
`distance` < 50
order by baseInfo.firstname asc limit 30
Which works perfectly for my core needs. However I am trying to firgure out how I can take the query and refine it so the part that is
(teams.teamName like '%Buffalo Bills%' or teams.teamName like '%New England Patriots%' or teams.teamName like '%Dallas Cowboys%')
will each yield a max defined amount of results per team name (less or none per is fine to, just seeking a max per), while having a max output of the limit specified at the end of the query. Is there anyway I can refine this query to do what I am hoping? Someone told me in another recent post similar to this that I made to check out UNION but I am not sure how that would apply to this query? Assuming that is the right direction to go.

Related

How can I order the results of an SQL query by the count of another table based on a shard ID?

I have an SQL query that fetches posts from a database. Everything works fine, but now I need to order the results by the number of comments each post has. The comments are on a separate table and they have a post_id column that links it to the post. I need to order the posts by the count of the comments table based on a shard ID? I have tried everything but every time I try to add something to my query it stops running completely and leaves my page blank. I need help to know where to put the other JOIN statement. This is my query:
$union = "UNION ALL
(
SELECT DISTINCT wallposts.p_id,wallposts.is_profile_notes,wallposts.times_viewed,wallposts.columnTimesShared,
wallposts.marked,wallposts.secure_id,wallposts.reshared,wallposts.group_id,
wallposts.totaluploads,wallposts.WallUploadID,wallposts.type,
wallposts.value,wallposts.media,wallposts.youtube,wallposts.post_type,
wallposts.privacy,wallposts.tagedpersons,wallposts.with_friends_tagged,wallposts.emotion_head,wallposts.selected_emotion,wallposts.title,
wallposts.url,wallposts.description,wallposts.cur_image,
wallposts.uip,wallposts.likes,wallposts.userid,
wallposts.posted_by,wallposts.post as postdata,wallusers.*,
UNIX_TIMESTAMP() - wallposts.date_created AS TimeSpent,
PosterTable.mem_pic as posterPic, PosterTable.gender as posterGender,PosterTable.oauth_uid as poster_oauth_uid, PosterTable.username as posterUsername,
PosterTable.mem_fname as posterFname,PosterTable.work as posterWork,
PosterTable.mem_lname as posterLname,walllikes_track.id as PostLikeFound,wallposts.date_created
FROM
wallusers,wallusers as PosterTable, wallposts
LEFT JOIN walllikes_track
ON wallposts.p_id = walllikes_track.post_id AND walllikes_track.member_id = ".$user_id."
WHERE
wallusers.active = 1
AND
PosterTable.active = 1
AND
wallposts.group_id IN (".$groups.")
AND
wallposts.group_id != 0
AND
PosterTable.mem_id = wallposts.posted_by
AND
wallposts.marked < ".$this->flagNumber."
AND
wallusers.mem_id = wallposts.posted_by ) ";
The comments table is called wallcomments and it has a column called post_id. I know I need to use JOIN and COUNT but I don't know where to put it within my current code.
Try this query, I didn't run but i updated it.
SELECT wallposts.p_id,wallposts.is_profile_notes,wallposts.times_viewed,wallposts.columnTimesShared,
wallposts.marked,wallposts.secure_id,wallposts.reshared,wallposts.group_id,
wallposts.totaluploads,wallposts.WallUploadID,wallposts.type,
wallposts.value,wallposts.media,wallposts.youtube,wallposts.post_type,
wallposts.privacy,wallposts.tagedpersons,wallposts.with_friends_tagged,wallposts.emotion_head,wallposts.selected_emotion,wallposts.title,
wallposts.url,wallposts.description,wallposts.cur_image,
wallposts.uip,wallposts.likes,wallposts.userid,
wallposts.posted_by,wallposts.post as postdata,wallusers.*,
UNIX_TIMESTAMP() - wallposts.date_created AS TimeSpent,
PosterTable.mem_pic as posterPic, PosterTable.gender as posterGender,PosterTable.oauth_uid as poster_oauth_uid, PosterTable.username as posterUsername,
PosterTable.mem_fname as posterFname,PosterTable.work as posterWork,
PosterTable.mem_lname as posterLname,walllikes_track.id as PostLikeFound,wallposts.date_created
FROM
wallusers,wallusers as PosterTable, wallposts
WHERE
wallusers.active = 1
AND
PosterTable.active = 1
AND
wallposts.group_id IN (".$groups.")
AND
wallposts.group_id != 0
AND
PosterTable.mem_id = wallposts.posted_by
AND
wallposts.marked < ".$this->flagNumber."
AND
wallusers.mem_id = wallposts.posted_by ) " AND wallposts.p_id = walllikes_track.post_id AND walllikes_track.member_id = ".$user_id.";
A more readable query might look like this...
At least then we'd have a chance.
SELECT DISTINCT p.p_id
, p.is_profile_notes
, p.times_viewed
, p.columnTimesShared
, p.marked
, p.secure_id
, p.media...
FROM wallposts p...

mysql query select depending on 2 tabels

I've reached the php code that I want. But my website is too slow because it keeps repeating and round over and over again,
$pages= mysql_query("SELECT * FROM ex_instagram_p WHERE type = '".follow."' AND active=1 And username !='".$username."' ORDER BY cpc DESC" );
$prow = mysql_fetch_array($pages);
Do{
$dollowed = mysql_query("SELECT * FROM exchanges WHERE user = '".$username."' AND exid = '".$prow['id']."'");
$followed = mysql_num_rows($dollowed);
;}while($followed > 0 && $prow = mysql_fetch_array($pages));
Actually I can explain the code a little more,
I need to choose the maximum CPC row from the first table
But also to make sure that:
type = '".follow."' AND active=1 And username !='".$username."' ORDER BY cpc DESC"
And here comes the problem,
before continue I need to make sure that the 'id' field form the first table does't got a record on the second table with the user username,
is it got result it'll repeat again using the next row,
over and over until finding a result that satisfies both tables.
This method is soooo heavy
I hope to get a simpler and lighter way, thanks
I've tried to do this but it does not work
$prow= mysql_query("SELECT *
FROM (mysql_query("SELECT * FROM ex_instagram_p WHERE type = '".follow."' AND active=1
And username !='".$username."' ORDER BY cpc DESC" );)
INNER JOIN (mysql_query("SELECT * FROM exchanges WHERE user = '".$username."'");)
ON ex_instagram_p.id=exchanges.exid";);
You can do this in one query. It is a bit hard to follow the logic, but I think this is the query that you want:
SELECT i.*
FROM ex_instagram_p i join
exchanges e
on i.id = e.exid
WHERE i.type = '".follow."' AND i.active=1 And
i.username <> '".$username."' and e.user = '".$username."'
ORDER BY i.cpc DESC
LIMIT 1;
Doing the work in the database is generally much faster than cycling through rows in the application. After all, that is what databases are good for -- managing and querying large amounts of data.

Is there an easier way to code this XP to LVL script?

The system works but I am sure there is another way of coding this in order to make it easier to access the users level depending on their XP points.
$getxp = mysql_query("SELECT `xp` FROM `members` WHERE `id` = '$logged[id]'");
$xp = mysql_fetch_array($getxp);
$x = $xp['xp'];
echo "$x";
$level = MYSQL_QUERY("SELECT * FROM `levels` WHERE `xp` >= '$x' LIMIT 1");
while ($n = mysql_fetch_array($level)) {
$mylvl = $n[level];
echo "You are a level $mylvl";
}
I have a database table for 'MEMBERS' (ID, USERNAME, PASS, XP) and a table for 'LEVELS' (ID, XP, LEVELS). Let me know of an easier method to get the LVL for the user. Many Thanks!
I think this should do it.
SELECT `levels`
FROM `members` m
LEFT JOIN `levels` l ON m.`xp` >= l.`xp`
WHERE m.`id` = '. $logged[id] .'
ORDER BY `levels` ASC
LIMIT 1;
Get all members where your member.id = $logged[id]. Next, link your member.id to all xp-requirements that are smaller than your current exp. This will give you a list of all the levels that you surpassed. Now the only thing you have to do is order them in a way that the highest level is first, and then simply limit it to 1 entry. This should result in the highest level that your exp allows you to have -- therefore your current level.
Note that of course, the more levels you have, the larger the LEFT JOIN becomes, which will end up consuming more memory on your SQL server.
also note you're using MYSQL. This is outdate and will be taken out of the next PHP version. Look into MYSQLi at least, or go straight for PDO. This way you wont have to change all your code once the new PHP releases.
$sql = "SELECT * FROM levels WHERE xp >= (SELECT xp FROM members WHERE id='".$loggedin['id']."')";
subselect not a join as you have no keys relating levels to members

Mysql return results based on SUM of a column

I have a query where I need to get all customers where they have spent less that a certain amount in a given month and return only those that have not met the quota.
The query as it is now is as follows.
SELECT cus.id, cus.email_address, COALESCE(SUM(credit_total),0) AS totalSpend
FROM customers AS cus
LEFT JOIN tasks_custs AS tsk ON tsk.user_id = cus.id
WHERE (
YEAR(date_ordered) = '2013'
AND MONTH(date_ordered) = '09'
AND paid = '1'
AND totalSpend < '300'
)
The error that is being returned is Unknown column 'totalSpend' in 'where clause'.
What I am wondering is can I accomplish what I am trying to do with a single sql query or am I going to have to select all customers and check the spend using php.
I was hoping to just have mysql return only the results that I need.
When working with aggregate functions you need to use the HAVING keyword instead of WHERE.
SELECT cus.id, cus.email_address, COALESCE(SUM(credit_total),0) AS totalSpend
FROM customers AS cus
LEFT JOIN tasks_custs AS tsk ON tsk.user_id = cus.id
WHERE (
YEAR(date_ordered) = '2013'
AND MONTH(date_ordered) = '09'
AND paid = '1')
GROUP BY cus.id
HAVING SUM(credit_total) < 30
If you are interested here is a good explanation in the difference between WHERE and HAVING look here. But if you want a quick summary,in my words, I would say it is this:
WHERE conditions are applied before any grouping on the specified criteria, and cannot be applied to aggregate functions
whereas HAVING is applied after grouping and can use aggregate functions to filter the result set.
How does this work for you? I have group'ed customer information and summed the total, just like you have - except that I have added a HAVING CLAUSE after grouping the data.
SELECT
cus.id,
cus.email_address,
COALESCE(SUM(credit_total),0) AS totalSpend
FROM customers AS cus
LEFT JOIN tasks_custs AS tsk
ON tsk.user_id = cus.id
WHERE
YEAR(date_ordered) = '2013'
AND MONTH(date_ordered) = '09'
AND paid = '1'
GROUP BY
cus.id,
cus.email_address
HAVING COALESCE(SUM(credit_total),0) < '300'

How to union 2 SQL-query in Codeigniter? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
UNION query with codeigniter's active record pattern
I have the following code:
$language_id=$this->get_language_id($language_code);
$english_id=$this->get_language_id('en');
$query="SELECT e.label_value, t.user_id, t.votes, t.approved, t.language_value FROM labels e left outer join labels t on e.label_value=t.label_value WHERE e.language=$english_id and t.language=$language_id and (t.approved=1 or t.user_id=$user_id) and e.label_value in (select distinct label_value from labels WHERE language=$english_id order by label_value limit $start_index, 30) order by e.label_value, t.votes";
$query=$this->db->query($query);
$data=$query->result_array();
But I have got the following error:
This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
So, I need to do the folowoing part "select distinct label_value from labels WHERE language=$english_id order by label_value offset $start limit 30" in another query. Please, help me, how can I do it using CodeIgniter?
UPDATE:
There are is table labels
(label_value, language_value, language) - PK,
user_id,
timestamp,
approved,
votes
and I need to get all queries from this table (for example, it's name is t and e) with labels t.label_value, e.label_value (is exists), e.user_id, e.votes, e.timestamp where t.label_value=e.label_value(same label), t.language=45 (english language), e.language=24 (my language) and (e.user_id=121234 or e.approved=1). But I need all entries, and if (t.label_value!=e.label_value) I need to get this entry with NULL fields.
This is a limitation of MySQL and not PHP or CI. In order to get around it, you need to wrap your sub query in an aliased sub query so it becomes a derived table:
$language_id = $this->get_language_id($language_code);
$english_id = $this->get_language_id('en');
$query = "
SELECT e.label_value, t.user_id, t.votes, t.approved, t.language_value
FROM labels e
LEFT OUTER JOIN labels t on e.label_value=t.label_value
WHERE
e.language = $english_id
AND t.language = $language_id
AND (t.approved = 1 OR t.user_id = $user_id)
AND e.label_value IN (
SELECT label_value
FROM (
SELECT DISTINCT label_value
FROM labels
WHERE language = $english_id
ORDER BY label_value
LIMIT $start_index, 30
) i
)
ORDER BY e.label_value, t.votes
";
$query = $this->db->query($query);
$data = $query->result_array();
I think that will work, let me know if it doesn't and I will take another look at it.
EDIT
I'm having a little difficulty working out exactly what you are trying to do, but I think it might be something more like this:
SELECT t.label_value, t.user_id, t.votes, t.approved, t.language_value
FROM (
SELECT DISTINCT label_value
FROM labels
WHERE language = $english_id
) e
LEFT JOIN labels t ON e.label_value = t.label_value
WHERE
t.language = $language_id
AND (t.approved = 1 OR t.user_id = $user_id)
ORDER BY t.label_value, t.votes
LIMIT $start_index, 30
If this is still not correct, please show some example rows, and the result set you would like to retrieve from those rows.

Categories