mysql query select depending on 2 tabels - php

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.

Related

Select a fixed number of records from a particular user in a sql result

I have 2 tables - users and articles.
users:
user_id (int)
name (varchar)
articles:
article_id (int)
user_id (int)
title (varchar)
description (text)
In my application I need to display 20 RANDOM articles on a page.
My query is like this:
SELECT a.title
, a.description
, u.name
FROM articles a
JOIN users u
USING (user_id)
ORDER
BY RAND()
LIMIT 20
A user can have any number of articles in the database.
Now the problem is sometimes out of 20 results, there are like 9-10 articles from one single user.
I want those 20 records on the page to not contain more than 3 (or say 4) articles from a particular user.
Can I achieve this through SQL query. I am using PHP and MySQL.
Thanks for your help.
You could try this?
SELECT * FROM
(
SELECT B.* FROM
(
SELECT A.*, ROW_NUMBER() OVER (PARTITION BY A.USER_ID ORDER BY A.R) USER_ROW_NUMBER
FROM
(
SELECT a.title, a.description, u.name, RND() r FROM articles a
INNER JOIN users u USING (user_id)
) A
) B
WHERE B.USER_ROW_NUMBER<=4
) C
ORDER BY RAND() LIMIT 20
Mmm, intresting I don't think this is possible through a pure sql query.
My best idea would be to have an array of the articles that you'll eventually display query the database and use the standard SELECT * FROM Articles ORDER BY RAND() LIMIT 20
The go through them, making sure that you have indeed got 20 articles and no one has breached the rules of 3/4 per user.
Have another array of users to exclude, perhaps using their user id as an index and value of a count.
As you go through add them to your final array, if you find any user that hits you rule add them to the array.
Keep running the random query, excluding users and articles until you hit your desired amount.
Let me try some code (it's been a while since I did php)
$finalArray = [];
$userArray = [];
while(count($finalArray) < 20) {
$query = "SELECT * FROM Articles ";
if(count($finalArray) > 0) {
$query = $query . " WHERE articleID NOT IN(".$finalArray.")";
$query = $query . " AND userID NOT IN (".$userArray.filter(>4).")";
}
$query = $query . " ORDER BY Rand()";
$result = mysql_query($query);
foreach($row = mysql_fetch_array($result)) {
if(in_array($finalArray,$row) == false) {
$finalArray[] = $row;
}
if(in_array($userArray,$row[userId]) == false) {
$userArray[$row[userId]] = 1;
}
else {
$userArray[$row[userId]] = $userArray[$row[userId]] + 1;
}
}

php mysql query combination

I first search all questions info. from "question" table including title, content, user etc.
the Code:
$sql = "select * FROM question where id>0 ORDER BY id ASC";
$result1 = mysql_query($sql);
$res=Array();
And then I want to search the user's point from "user" table. So I must search point for each user in each row from the result1
The Code:
while($rows=mysql_fetch_assoc($result1))
{
$res[]=$rows;
$user = $rows['user'];
$sql2 = "select point from user where name='$user'";
$result2 = mysql_query($sql2);
}
My problem is how to combine all the users' point(result2) with the questions info.(result1) together so that I can return a json for each row.
Use left join, as my understanding this work for you
$sql = "SELECT q.*, u.point AS point FROM question AS q LEFT JOIN user AS u ON q.user = u.name WHERE q.id > 0 ORDER BY q.id ASC";
$result = mysql_query($sql);
It's better go with the joins here i am giving you the query.i hope it may helps you
select * from question q,user u where q.id>0 ORDER BY id ASC
try something like this:using left join
select question.*,user.point FROM question left join user on user.name= question.name where id>0 ORDER BY id ASC

Combining queries for speed

I started using only 1 query but then I wanted some to show up more than others so I ended up doing more queries but it, really slows down the load time, is there a way I can do them all in a single query but have them all with their separate variable name?
$sql23 = "SELECT * FROM monsters WHERE rare='0' AND level<='".$row['level']."' ORDER BY RAND() LIMIT 1;";
$result23 = mysqli_query($link,$sql23) or die(mysqli_error());
$battle_get23 = mysqli_fetch_array($result23);
$boss = "SELECT * FROM monsters WHERE rare='1' AND level<='".$row['level']."' ORDER BY RAND() LIMIT 1;";
$boss = mysqli_query($link,$boss) or die(mysqli_error());
$boss = mysqli_fetch_array($boss);
$rare1 = "SELECT * FROM monsters WHERE rare='2' AND level<='".$row['level']."' ORDER BY RAND() LIMIT 1;";
$rare1 = mysqli_query($link,$rare1) or die(mysqli_error());
$rare1 = mysqli_fetch_array($rare1);
$rare2 = "SELECT * FROM monsters WHERE rare='3' AND level<='".$row['level']."' ORDER BY RAND() LIMIT 1;";
$rare2 = mysqli_query($link,$rare2) or die(mysqli_error());
$rare2 = mysqli_fetch_array($rare2);
$rare3 = "SELECT * FROM monsters WHERE rare='4' AND level<='".$row['level']."' ORDER BY RAND() LIMIT 1;";
$rare3 = mysqli_query($link,$rare3) or die(mysqli_error());
$rare3 = mysqli_fetch_array($rare3);
$rare4 = "SELECT * FROM monsters WHERE rare='5' AND level<='".$row['level']."' ORDER BY RAND() LIMIT 1;";
$rare4 = mysqli_query($link,$rare4) or die(mysqli_error());
$rare4 = mysqli_fetch_array($rare4);
$rare5 = "SELECT * FROM monsters WHERE rare='6' AND level<='".$row['level']."' ORDER BY RAND() LIMIT 1;";
$rare5 = mysqli_query($link,$rare5) or die(mysqli_error());
$rare5 = mysqli_fetch_array($rare5);
$rare6 = "SELECT * FROM monsters WHERE rare='7' AND level<='".$row['level']."' ORDER BY RAND() LIMIT 1;";
$rare6 = mysqli_query($link,$rare6) or die(mysqli_error());
$rare6 = mysqli_fetch_array($rare6);
$rare7 = "SELECT * FROM monsters WHERE rare='8' AND level<='".$row['level']."' ORDER BY RAND() LIMIT 1;";
$rare7 = mysqli_query($link,$rare7) or die(mysqli_error());
$rare7 = mysqli_fetch_array($rare7);
$rare8 = "SELECT * FROM monsters WHERE rare='9' AND level<='".$row['level']."' ORDER BY RAND() LIMIT 1;";
$rare8 = mysqli_query($link,$rare8) or die(mysqli_error());
$rare8 = mysqli_fetch_array($rare8);
$rare9 = "SELECT * FROM monsters WHERE rare='10' AND level<='".$row['level']."' ORDER BY RAND() LIMIT 1;";
$rare9 = mysqli_query($link,$rare9) or die(mysqli_error());
$rare9 = mysqli_fetch_array($rare9);
First. You are barking the wrong tree.
Combining a number of slow queries in one won't make them fast. Overhead for running a query is NOT that important as most php users think. If query itself is fast, no matter how many times it is called (within sane numbers of course). If query is slow, no combining would help.
You have to take care for the queries themselves instead of trying to combine them. Thus, to solve your problem you have to provide a lot more info:
Define "really slows" in certain numbers. For all queries in one and for the every single query.
Provide database schema and data amounts.
Provide result of one of the queries run perpended with EXPLAIN keyword
You could give your monsters a random number once a day or once an hour, so
update monsters set sortorder=rand();
It might help to have an index on that key sortorder.
Then you could calculate for every read a random number in php:
$rand = mt_rand(0,1); // or however mt_rand() is called
Then you could select:
$sql23 = "SELECT * FROM monsters WHERE rare='0' AND level<='".intval($row['level'])."' ORDER BY (sortorder-$rand) DESC LIMIT 1;";
$result23 = mysqli_query($link,$sql23) or die(mysqli_error());
$battle_get23 = mysqli_fetch_array($result23);
From SQL it is easy to create a solution with only one select, but that needs a temporary table to support undisturbed random.
Use a category-table
CREATE TABLE raretype (id int(11), name varchar(255), sortkey float default 0, primary key(id));
Put your rares in there:
INSERT INTO raretype (id, name) values (0, 'battle_get23'),(1,'boss'),(2,'rare1'),...
Create a random sortorder for your read:
DROP TEMPORARY TABLE IF EXISTS tmp_rare_sort;
CREATE TEMPORARY TABLE tmp_rare_sort (raretype int(11) not null primary key, sortorder float);
INSERT INTO tmp_rare_sort SELECT id, rand() from raretype;
Read them out:
SELECT rt.name as type, m.*
FROM raretype rt
INNER JOIN tmp_rare_sort rts on rts.raretype = rt.id
LEFT JOIN monsters m on m.id =
( select id from monsters imo where imo.rare = rt.id
and imo.level <= {intval($level)}
order by abs(sortorder - rts.sortorder) desc
limit 1
)
You should read out an array as a result:
$allMonsters = array();
while($line = $rs->next()){
$allMonsters[$line['type']] = $line;
}
So that $allMonsters['boss'] gives the boss (with an additional field 'type', that should not hurt).
If you really want it as single variables, you could extract() this array.
Hope that helps!
If some syntax errors, please create a SQL-fiddle and I'll check. Just no time to create the tables myself. ;-)
1) take out all of your order by RAND() and limit 1
2) do randomization after query
$bossSql = "SELECT * FROM monsters WHERE rare='1' AND level<='".$row['level']."' ";
$bossRs = mysqli_query($link,$bossSql) or die(mysqli_error());
$bossArray = mysqli_fetch_array($bossRs);
//just saw you had limit in your sql, edited
//shuffle($bossArray);
$randomBosskey = array_rand($bossArray);
$randomBoss = $bossArray[$randomBossKey];
edit: thank you #flaschenpost for pointing out the potential problem, which inspired me to come up with a possibly quicker solution (under certain assumption which might not be true)
Solution 2) cache the table
From the looks of the code I think there is a high chance that you would need to do the query for monster action many times throughout the whole program lifetime.
Instead of getting a new random monster from DB everytime, will it be better to do full query:
SELECT * FROM monsters
save it in a variable and then pick the a random monster according to rarity and level from the same variable everytime you need a monster? But this method takes up unknown amount of memory depends on your table size and might be faster/slower than your original depending on how many "random monster" query you are actually using in your program. It might also depends on the "power" of your machine, assuming your DB and server are not in the same machine and the 2 machine have significant difference in processing power.

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

Paginate while ignoring sub rows, with a Right Join

I have this basic query that returns a main row of a program title(eventdesc) and then lists program participants and info as multiple sub rows.
PROGRAM 1
Email 1, email 2, name, status (first participant)
Email 1, email 2, name, status (second participant)
PROGRAM 2
Email 1, Email 2, name, status (first participant)
ETC...
Basic query:
$query_perpage = "SELECT COUNT(*) FROM camps_events";
$result = mysql_query($query_perpage, $db) or die(mysql_error());
$r = mysql_fetch_row($result);
$numrows = $r[0];
$pages = new Paginator($query);
$pages->items_total = $numrows;
$pages->paginate();
$pages->mid_range = 7;
$query = mysql_query("SELECT ce.eventcode, ce.eventdesc, ce.date, r.participant_fname, r.participant_lname,
r.position, r.dob, r.status, r.email_primary, r.order_number
FROM camps_events ce
RIGHT JOIN registrations r on r.eventcode = ce.eventcode
WHERE ce.reg_status = 'Active'
AND r.status NOT IN ('Incomplete','Canceled')".getAllowedPrograms()."
ORDER BY ce.eventdesc, ce.eventcode, r.participant_lname ASC $pages->limit ") or die(mysql_error());
I've been trying to figure out how to paginate it by Program, no matter how many subrows.
I have a pagination class in place on another page, but that only pulls from one table.
I've been trying to implement the same pagination, but I can only get it to pull the first program, and then it limits the page based on the sub rows, not the main program row. And in the state I've posted it here, each following page displays only the first programs. The sub rows that come up are different on each page, but I can't tell if they are all in the first program.
The query works fine for pulling all results properly, but if it's a huge list, it's extremely inefficient, and can even timeout the browser.
Any help would be much appreciated, please let me know if I can include anything else.
I'm not too concerned with using the same pagination class, so I'm completely open to different approaches.
Thanks in advance
Try using a subselect:
SELECT ce.eventcode, ce.eventdesc, ce.date, r.participant_fname, r.participant_lname,
r.position, r.dob, r.status, r.email_primary, r.order_number
FROM camps_events ce
RIGHT JOIN registrations r on r.eventcode = ce.eventcode
WHERE ce.reg_status = 'Active'
AND r.status NOT IN ('Incomplete','Canceled')".getAllowedPrograms()."
AND ce.id in (select id from camps_events pgce order by ce.eventdesc, ce.eventcode $pages->limit)
ORDER BY ce.eventdesc, ce.eventcode, r.participant_lname ASC ")
or die(mysql_error());
Edit: unfortunately MySQL can not yet limit subqueries. :-(
So it has to be a temp-table:
mysql_query("drop temporary table if exists tmp_events", $db);
mysql_query("create temporary table tmp_events select id from camps_events order by eventdesc, eventcode " . $pages->limit, $db);
mysql_query("SELECT ce.eventcode, ce.eventdesc, ce.date, r.participant_fname, r.participant_lname,
r.position, r.dob, r.status, r.email_primary, r.order_number
FROM camps_events ce
inner join tmp_events pgce on pgce.id = ce.id
RIGHT JOIN registrations r on r.eventcode = ce.eventcode
WHERE ce.reg_status = 'Active'
AND r.status NOT IN ('Incomplete','Canceled')".getAllowedPrograms()."
ORDER BY ce.eventdesc, ce.eventcode, r.participant_lname ASC ")
or die(mysql_error());
There can be of course pages with less than paged items, because events without registrations will not show.

Categories