Getting total in while statement with UNION query - php

I am trying to calculate how much a user has earned so it reflects on the users home page so they know how much their referrals have earned.
This is the code I have.
$get_ref_stats = $db->query("SELECT * FROM `members` WHERE `referral` = '".$user_info['username']."'");
$total_cash = 0;
while($ref_stats = $get_ref_stats->fetch_assoc()){
$get_ref_cash = $db->query("SELECT * FROM `completed` WHERE `user` = '".$ref_stats['username']."' UNION SELECT * FROM `completed_repeat` WHERE `user` = '".$ref_stats['username']."'");
$countr_cash = $get_ref_cash->fetch_assoc();
$total_cash += $countr_cash['cash'];
$countr_c_rate = $setting_info['ref_rate'] * 0.01;
$total_cash = $total_cash * $countr_c_rate;
}
It worked fine when I just had
$get_ref_cash = $db->query("SELECT * FROM `completed` WHERE `user` = '".$ref_stats['username']."'");
but as soon as I added in the UNION it no longer calculated correctly.
For example, there is 1 entry in completed and 1 entry in completed_repeat both of these entries have a cash entry of 0.75. The variable for $countr_c_rate is 0.10 so $total_cash should equal 0.15 but instead it displays as 0.075 with and without the UNION it acts as if it is not counting from the other table as well.
I hope this makes sense as I wasn't sure how to explain the issue, but I am very unsure what I have done wrong here.

In your second query instead of UNION you should use UNION ALL since UNION eliminates duplicates in the resultset. That is why you get 0.075 instead of 0.15.
Now, instead of hitting your database multiple times from client code you better calculate your cash total in one query.
It might be inaccurate without seeing your table structures and sample data but this query might look like this
SELECT SUM(cash) cash_total
FROM
(
SELECT c.cash
FROM completed c JOIN members m
ON c.user = m.username
WHERE m.referral = ?
UNION ALL
SELECT r.cash
FROM completed_repeat r JOIN members m
ON r.user = m.username
WHERE m.referral = ?
) q
Without prepared statements your php code then might look like
$sql = "SELECT SUM(cash) cash_total
FROM
(
SELECT c.cash
FROM completed c JOIN members m
ON c.user = m.username
WHERE m.referral = '$user_info['username']'
UNION ALL
SELECT r.cash
FROM completed_repeat r JOIN members m
ON r.user = m.username
WHERE m.referral = '$user_info['username']'
) q";
$result = $db->query($sql);
if(!$result) {
die($db->error()); // TODO: better error handling
}
if ($row = $result->fetch_assoc()) {
$total_cash = $row['cash_total'] * $setting_info['ref_rate'];
}
On a side note: make use of prepared statements in mysqli instead of building queries with concatenation. It's vulnerable for sql-injections.

With $countr_cash = $get_ref_cash->fetch_assoc(); you only fetch the first row of your result. However, if you use UNION, you get in your case two rows.
Therefore, you need to iterate over all rows in order to get all values.

Ok, So there is only one row in members table. You are iterating only once on the members table. Then you are trying to get rows using UNION clause which will result in two rows and not one. Then you are just getting the cash column of the first row and adding it to the $total_cash variable.
What you need to do is iterate over the results obtained by executing the UNION query and add the $total_cash variable. That would give you the required result.
$get_ref_stats = $db->query("SELECT * FROM `members` WHERE `referral` = '".$user_info['username']."'");
$total_cash = 0;
while($ref_stats = $get_ref_stats->fetch_assoc()){
$get_ref_cash = $db->query("SELECT * FROM `completed` WHERE `user` = '".$ref_stats['username']."' UNION SELECT * FROM `completed_repeat` WHERE `user` = '".$ref_stats['username']."'");
while($countr_cash = $get_ref_cash->fetch_assoc()){
$total_cash += $countr_cash['cash'];
}
$countr_c_rate = $setting_info['ref_rate'] * 0.01;
$total_cash = $total_cash * $countr_c_rate;
}

Related

selecting sql variable returning an empty array

I'm attempting to SET 3 variables in MySQL and get the sum of two of them.
The fist two variables, #cFollow and #cComment, should return an integer value each (the count of how many rows are returned); the third one is the sum of those two integers.
This is my SQL:
SET #cFollow = (SELECT COUNT(*) FROM followers WHERE unix > :unix AND following = :user);
SET #cComment = (SELECT COUNT(*) FROM comments WHERE comment_unix > :unix AND comment_track IN (SELECT upload_id FROM uploads WHERE upload_artist = :user));
SET #total = #cFollow + #cComment;
SELECT #total;
When I tested this on PHPMyAdmin, it returned the correct values and worked perfectly fine. However, when I tested it within PHP, it returned an empty array.
This is my PHP:
$holdPoint = (int)Input::get("hold_point");
$_SQL = "
SET #cFollow = (SELECT COUNT(*) FROM followers WHERE unix > :unix AND following = :user);
SET #cComment = (SELECT COUNT(*) FROM comments WHERE comment_unix > :unix AND comment_track IN (SELECT upload_id FROM uploads WHERE upload_artist = :user));
SET #total = #cFollow + #cComment;
SELECT #total;";
$_PARAMS = [":unix" => $holdPoint, ":user" => $user_id];
$check = DB::getInstance()->queryPro($_SQL, $_PARAMS);
var_dump($check);
This is the result of that var_dump:
array(0){} // not very impressive...
// should be something like int(1) instead
I've been searching around all night learning how to return a variable in PHP from a MySQL query, and this is as far as I've gotten.
All help is appreciated,
Cheers.
This answer is not really meant as a answer but more as a comment.
Also note that your queries
SET #cFollow = (SELECT COUNT(*) FROM followers WHERE unix > :unix AND following = :user);
SET #cComment = (SELECT COUNT(*) FROM comments WHERE comment_unix > :unix AND comment_track IN (SELECT upload_id FROM uploads WHERE upload_artist = :user));
SET #total = #cFollow + #cComment;
SELECT #total;
Can be most likely be rewritten as one query
SELECT
SUM(alias.c) AS total
FROM (
SELECT COUNT(*) AS c FROM followers WHERE unix > :unix AND following = :user
UNION ALL
SELECT COUNT(*) AS c FROM comments WHERE comment_unix > :unix AND comment_track IN (SELECT upload_id FROM uploads WHERE upload_artist = :user)
) AS alias

How can I convert these two queries in a loop into a single JOINed query?

I am currently trying to get data from my table (mostKills by Weapon in a table with over 300 kills). Initially I did a normal query
$q = $mysql->query("SELECT * FROM `kills`") or die($mysql->error);
but when I tried to
$query2 = $mysql->query("SELECT `killerID`, COUNT(`killerID`) AS tot_kills FROM `kills` WHERE `killText` LIKE '%$gun%' GROUP BY `killerID` ORDER BY `tot_kills` DESC;") or die($mysql->error);
$kData = $query2->fetch_assoc();
$query3 = $mysql->query("SELECT `Username` FROM `players` WHERE `ID` = '" . $kData['killerID'] . "'") or die($mysql->error);
$uData = $query3->fetch_assoc();
$array[$gun]['Kills']++;
$array[$gun]['Gun'] = $gun;
$array[$gun]['BestKiller'] = $uData['Username'];
$array[$gun]['killAmount'] = $kData['tot_kills'];
function sortByKills($a, $b) {
return $b['Kills'] - $a['Kills'];
}
usort($array, 'sortByKills');
foreach($array as $i => $value)
{
// table here
}
I had to do it in a while loop, which caused there to be around 600 queries, and that is obviously not acceptable. Do you have any tips on how I can optimize this, or even turn this into a single query?
I heared JOIN is good for this, but I don't know much about it, and was wondering if you guys could help me
Try this...
I added a inner join and added a username to your select clause. The MIN() is just a way to include the username column in the select and will not have an impact on you result as long as you have just 1 username for every Killerid
SELECT `killerID`
, COUNT(`killerID`) AS tot_kills
, MIN(`Username`) AS username
FROM `kills`
INNER JOIN `players`
ON `players`.`id` = `kills`.`killerid`
WHERE `killText` LIKE '%$gun%'
GROUP BY `killerID`
ORDER BY `tot_kills` DESC
SELECT kills.killerID, count(kills.killerID) as killTotal, players.Username
FROM kills, players
WHERE kills.killText
LIKE '%$gun%'
AND players.ID` = kills.killerID
GROUP BY kills.killerID
ORDER BY kills.tot_kills DESC
Here is a good place to learn some more about joins.
http://www.sitepoint.com/understanding-sql-joins-mysql-database/
The best way is to have your own knowledge so you can be able to tune up your select queries.
Also put more indexes to your DB, and try to search and join by index.

How do I connect two tables to see if a value exist in any of the two

I having problems connecting the below query together so that It works more efficient.Can someone please tell me how I can connect these two queries so that it is only one?
$rs_duplicate = mysql_query("select count(*) as total
from advertisers_account
where user_email='$user_email' ") or die(mysql_error());
list($total) = mysql_fetch_row($rs_duplicate);
}
$rs_duplicate_pub = mysql_query("select count(*) as total
from publishers_account
where user_email='$user_email' ") or die(mysql_error());
list($totalpub) = mysql_fetch_row($rs_duplicate_pub);
if ($totalpub || $total > 0)
{
echo "Not Available ";
} else {
echo "Available";
}
Use a UNION:
SELECT 'advertisers' AS which, count(*) AS total
FROM advertisers_account
WHERE user_email = '$user_email'
UNION
SELECT 'publishers' AS which, count(*) AS total
FROM publishers_account
WHERE user_email = '$user_email'
This query will return two rows, you can use the which column to tell whether it's advertisers or publishers.
This is how you could do it. you need to use joins, but you should make sure to not let any variables in the query be directly from an outside user like from a form submit. That will open you up to SQL Injection. Use Prepared Statements instead.
select count(*) as total from publishers_account INNER JOIN advertisers_account ON advertisers_account.user_email = publishers_account.user_email WHERE user_email='$user_email'
in response to:
Can someone please tell me how I can connect these two queries so that it is only one?
Why not:
Select
(select count(*) as total from advertisers_account where user_email='$user_email') +
(select count(*) as total from publishers_account where user_email='$user_email') as sumofCount
SELECT count(advertisers_account.id)
FROM publishers_account
LEFT JOIN advertisers_account ON publisher_account.email = advertisers_account.email
WHERE publisher_account.email = '$user_email';
If the count is greater than zero, then the email exists in both tables at least once. If it exists only in the left table (publishers), then the counter would be zero. If it doesn't exist at all in the left table, then you'll get no rows at all, even if it does exist in the right table (advertisers)

Total Rows From Each GROUP BY

I'm trying to run a MySQL query and use PHP to do the following:
I need to group data in a column (GROUP BY) then count (COUNT) the number of rows in each group. After that, I need to divide the number of rows in a given group by the number of groups to get that groups percentage of popularity.
So if I had a table with the following data:
Version_Number
1.1
1.2
1.1
1.2
1.2
1.1
I need the final output to be:
1.1 50%
1.2 50%
You may need to adjust this for mysql (I normally work in oracle) but:
SELECT
( count(*) / totalCount * 100) AS percentOfVersionedThings
, Version_Number
FROM tableOfVersionedThings
INNER JOIN ( SELECT count(*) as totalCount FROM tableOfVersionedThings ) ON 1=1
GROUP BY Version_Number
If this was Oracle, I'd suggest using analytics, but I'm not sure if there is an equivalent in MySQL. That said, in your case a simple sub-query should solve the problem, and it should be workable on any SQL database.
This is what I ended up doing after trying the above:
$result = mysql_query("SELECT COUNT(*) AS nsites FROM table WHERE auth = '$auth'") or
die(mysql_error());
$return_sites = mysql_fetch_array($result);
if (!$return_sites['nsites']) {
echo "...";
} else {
$esult = mysql_query("SELECT * FROM table WHERE auth = '$auth' GROUP BY theme_version") or die(mysql_error());
while($row = mysql_fetch_array($esult)){
$get_current_version = $row['theme_version'];
$vresult = mysql_query("SELECT COUNT(*) AS nversion FROM table WHERE auth = '$auth' AND theme_version = '$get_current_version'") or die(mysql_error());
$version = mysql_fetch_array($vresult);
$percent = round($version['nversion'] / $return_sites['nsites'] * 100);
echo "...";
}
}
Something like this:
select v."Version_Number", count(v."Version_Number"),count(v."Version_Number")::float / (select count(v2."Version_Number")::float from versions v2 )::float * 100::float
from versions as v
group by v."Version_Number"

Help construct a simple query Using 3 tables

Hey guys need some more help
I have 3 tables USERS, PROFILEINTERESTS and INTERESTS
profile interests has the two foreign keys which link users and interests, they are just done by ID.
I have this so far
$statement = "SELECT
InterestID
FROM
`ProfileInterests`
WHERE
userID = '$profile'";
Now I want it so that it selects from Interests where what it gets from that query is the result.
So say that gives out 3 numbers
1
3
4
I want it to search the Interests table where ID is = to those...I just don't know how to physically write it in PHP...
Please help.
Using a JOIN:
Best option if you need values from the PROFILEINTERESTS table.
SELECT DISTINCT i.*
FROM INTERESTS i
JOIN PROFILEINTERESTS pi ON pi.interests_id = i.interests_id
WHERE pi.userid = $profileid
Using EXISTS:
SELECT i.*
FROM INTERESTS i
WHERE EXISTS (SELECT NULL
FROM PROFILEINTERESTS pi
WHERE pi.interests_id = i.interests_id
AND pi.userid = $profileid)
Using IN:
SELECT i.*
FROM INTERESTS i
WHERE i.interests_id IN (SELECT pi.interests_id
FROM PROFILEINTERESTS pi
WHERE pi.userid = $profileid)
You are on the right track, lets say you execute the query above using this PHP code:
$statement = mysql_query("SELECT InterestID FROM `ProfileInterests`
WHERE userID = '$profile'");
Then you can use a PHP loop to dynamically generate an SQL statement that will pull the desired IDs from a second table. So, for example, continuing the code above:
$SQL = "";
while ($statementLoop = mysql_fetch_assoc($statement)) {
//Note the extra space on the end of the query
$SQL .= "`id` = '{$statementLoop['InterestID']}' OR ";
}
//Trim the " OR " off the end of the query
$SQL = rtrim($SQL, " OR ");
//Now run the dynamic SQL, using the query generated above
$query = mysql_query("SELECT * FROM `table2` WHERE {$SQL}")
I haven't tested the code, but it should work. So, this code will generate SQL like this:
SELECT * FROM `table2` WHERE `id` = '1' OR `id` = '3' OR `id` = '4'
Hope that helps,
spryno724
Most likely you want to join the tables
select
i.Name
from
ProfileInterests p
inner join
interests i
on
p.interestid = i.interestid
where
p.userid = 1

Categories