How to display only rows that match values in another table - php

How would it work in something like this? I've even tried using "AND tb1.name !=", but it didn't work.
$area = 0;
$stmt = $dbh->prepare('SELECT * FROM charinfo WHERE current_area != :area ORDER BY current_area');
$stmt->execute(array('area' => $area));
$result = $stmt->fetchAll();
$place = 1;
I run a game server, and on the website I have a Top 30 leaderboard which is working wonders (found the code directly off another topic here), the issue I'm having is not being able to use the JOIN function that everybody is suggesting in order to prevent the ADMIN's characters from being listed as well.
Here's the code that I have on my website right now, it shows the rank number 1-30, character name and the level in a table. Here's it working on my website
<?php
require("srvcs/config.php");
$stmt = $dbh->prepare('SELECT * FROM chars ORDER BY CAST(experience AS UNSIGNED ) DESC LIMIT 30;');
$stmt->execute();
$result = $stmt->fetchAll();
$place = 1;
echo '<table class="justShowme" style="width:600px;height:150px;">
<tr>
<td>Rank</td>
<td>Character Name</td>
<td>Level</td>
</tr>';
foreach ($result as $index => &$item) {
$exp = floor(pow($item['experience'] + 1, 1/4));
$name = $item['name'];
echo '<tr>';
echo "<td><B>" . $place++ . "</B></td>";
echo "<td>" . $name . "</td>";
echo "<td>" . $exp . "</td>";
echo '</tr>';
}
echo '</table></center>';
?>
I'm not very familiar with MySQL, so I'll just start by listing out what I know is necessary...
'chars' table includes the character information
'sID' column is unique and matches the subscriber 'ID' column, whoever owns the character
'subscriber' table includes the account information and admin status
'ID' is the subscriber ID which the 'sID' from chars table refers to
'admin' is the admin status of the account as Y or N
If a character has an sID value of a subscriber ID with the admin value as Y, it should not be listed.
If the character has an sID value of a subscriber ID with the admin value N, it will be listed and the table is listed as DESC and only show 30 rows of results.
How would I go about doing this?
Any help would be greatly appreciated! This is my first post, so tips on future help requests would be nice too :) Thank you in advance!

SELECT tb1.*
FROM chars tb1
JOIN subscriber tb2
ON tb1.sID=tb2.ID
WHERE admin = 'N'
ORDER BY CAST(experience AS UNSIGNED ) DESC
LIMIT 30;

You could use a NOT IN subquery.
See below.
SELECT chars.*
FROM chars
WHERE sID NOT IN (SELECT ID FROM subscriber WHERE subscriber.admin = 'Y')
ORDER BY CAST(experience AS UNSIGNED ) DESC
LIMIT 30;

Related

The sum of the user's points

I am a beginner when it comes to PHP and it is not my specialty, I am rather in the front end and I have a big problem.
I need to edit one of the tables after a guy who doesn't work with our company anymore and it seemed simple to me at first, but I can't find a solution.
I have a table with 4 columns: Date, Full Name, Login, and Points. Records of added points are saved in the database, but each action adding points creates a new record in the database, let's say:
Date
Full Name
Login
Points
04/10/2021
John Kovalsky
koval
10
04/11/2021
John Kovalsky
koval
20
04/12/2021
John Kovalsky
koval
15
The script below works, and I can almost understand the syntax, there is a display limit set here and a table pagination added. The script displays all records in the database.
The problem is that I need exactly the same, but with the sum of the user's points, so that a given user is displayed only once, and in the "Points" column, the sum of all his points is displayed.
I tried with the array_sum () function, but it enumerates all the records in the database for me. The script looks like this:
<?php
$login = $_GET['login'];
$_SESSION["login"] = $login;
include('Pagination.php');
include('config.php');
$limit = 200;
$queryNum = $db->query("SELECT COUNT(*) as ID FROM db_main");
$resultNum = $queryNum->fetch_assoc();
$rowCount = $resultNum['ID'];
$pagConfig = array(
'totalRows' => $rowCount,
'perPage' => $limit,
'link_func' => 'searchFilter'
);
$pagination = new Pagination($pagConfig);
$query = $db->query("SELECT * FROM db_main LIMIT $limit");
echo "<center>";
echo "<table id=\"tabela\" cellpadding=\"2\" border=1>";
echo "<tr>";
echo "<th>".'Date'."</th>";
echo "<th>".'Full Name'."</th>";
echo "<th>".'Login'."</th>";
echo "<th>".'Points'."</th>";
echo "</tr>";
echo "</tr>";
if($query->num_rows > 0){
?>
<?php
while($r = $query->fetch_assoc()){
echo "<tr>";
echo "<td>".$r['Date']."</td>";
echo "<td>".$r['Full_name']."</td>";
echo "<td>".$r['Login']."</td>";
echo "<td>".$r['Points']."</td>";
echo "</tr> </center>";
}
echo $pagination->createLinks();
}
?>
Please help, I have no idea how to do it. I will be very grateful for your help and hints.
You could do it by using a different query.
First, get all unique users.
$db->query("SELECT COUNT(DISTINCT(Full_name)) as ID FROM db_main");
Now get the collected data for each user.
$db->query("SELECT MAX(Date) AS Date, Full_name, Login, SUM(Points) AS Points FROM db_main GROUP BY Full_name LIMIT $limit");
Using the GROUP option will make sure you get one row per user.
The SUM will give you the amount of all the user's points.
The MAX(Day) will return user's the last day field.
There are two assumptions here, that the login is always the same for the user, and that the Points field is numeric and not a string.

Path report from MySQL

I have a database table that tracks all pageviews which are fired in via a php script. The table looks like this:
rowid (AI)
user_id
page_url
visitor_ip
session_id
I want to be able to query my table to "Show the paths (max 5 pages) visitors take to get to X page within a single session". The output would be a table with a URL in each column, so the path is left to right in the order they visited pages with the same session_id ending with a certain page.
Any clue? I've been looking for a reporting tool to help me build these segments but I'm not coming up with anything so I'm trying to see if there is a way to just query it. I'd like to avoid turning to some other tool for collection and just query my DB if I can.
Does something like this give you what you want (warning - untested):
select group_concat(page_url order by rowid separator '->'),session_id
from pageviews group by session_id
?
One idea is to use correlated subqueries in the select list.
If I understood the specification, the argument(parameter) to the query will be a specific `page_url`, given as "X" in the specification.
The outer query will retrieve the rows for that page_url. The subqueries in the SELECT list will get the previous page_url in the session. (We don't see a datetime/timestamp, so we will need to depend on values of `rowid` increasing for subsequent page views (i.e. previous page views will have a "lower" value of `row_id`.
Something like this:
SELECT ( SELECT p5.page_url
FROM pageviews p5
WHERE p5.session_id = t.session_id
AND p5.rowid < t.rowid
ORDER BY p5.rowid DESC
LIMIT 4,1
) AS back_5_page_url
, ( SELECT p4.page_url
FROM pageviews p4
WHERE p4.session_id = t.session_id
AND p4.rowid < t.rowid
ORDER BY p4.rowid DESC
LIMIT 3,1
) AS back_4_page_url
, ( SELECT p3.page_url
FROM pageviews p3
WHERE p3.session_id = t.session_id
AND p3.rowid < t.rowid
ORDER BY p3.rowid DESC
LIMIT 2,1
) AS back_3_page_url
, ( SELECT p2.page_url
FROM pageviews p2
WHERE p2.session_id = t.session_id
AND p2.rowid < t.rowid
ORDER BY p2.rowid DESC
LIMIT 1,1
) AS back_2_page_url
, ( SELECT p1.page_url
FROM pageviews p5
WHERE p1.session_id = t.session_id
AND p1.rowid < t.rowid
ORDER BY p1.rowid DESC
LIMIT 0,1
) AS back_1_page_url
, t.page_url
, t.session_id
, t.row_id
FROM pageviews t
WHERE t.page_url = 'X'
Those subqueries are going to be executed for each row returned by the outer query, so this could eat our lunch in terms of performance. If no suitable indexes are available, it's going to eat our lunch box too.
For the subqueries, we are going to want an index...
ON pageviews (session_id, row_id, page_url)
The outer query will benefit from an index ...
ON pageviews (page_url, row_id, session_id)
As an idea for the start of a different approach, if we were getting the path to every page_url, and not just a specific one...
SET group_concat_max_len = 524288 ;
SELECT t.session_id
, t.page_url
, SUBSTRING_INDEX(
GROUP_CONCAT(t.page_url SEPARATOR '\t' ORDER BY t.rowid DESC)
,'\t',6) AS `last_5_pages`
FROM pageviews t
GROUP
BY t.session_id
, t.page_url
HAVING t.page_url = 'X'
This assumes that the page_url will not contain a tab (0x09) character.
The last_5_pages column would be a tab-delimited list of page_url, the most recent page view first, followed by the previously viewed page_url, etc.
Getting those split out as individual columns would be more work, wrapping that query in an inline view and some combination of SUBSTRING_INDEX, possibly REVERSE, and a function to count the number of page_url in the list... that gets kind of nasty to do in SQL. If I went this approach, I'd prefer to handle parsing out the page_url from the tab delimited list in the client.
Here is what I ended up doing - worked great.
<?php
require_once 'init.php';
// ----------------- PAGE PATH REPORT
$html = "<table>";
$html .= "<tr><th align='left'>PAGE PATHS HITTING GOAL.PHP</th></tr>";
$paths = array();
$sql = "SELECT cookie_uid, page_url FROM pageviews ORDER BY rowid";
$result = mysqli_query($conn, $sql);
$got_rows = mysqli_num_rows($result);
if ($got_rows) {
while ($row = mysqli_fetch_array($result)) {
// Create an array for the cookie_uid if it doesn't exist yet
if ( ! array_key_exists($row['cookie_uid'], $paths) || ! is_array($paths[$row['cookie_uid']])) {
$paths[$row['cookie_uid']] = [];
}
// Add to the array now that we know it exists
array_push($paths[$row['cookie_uid']], $row['page_url']);
}
foreach ($paths as $session => $page) {
$html .= "<tr>";
$html .= '<td>' . implode(' ---> ', $page) . "</td>";
$html .= "</tr>";
}
} else {
$html .= '<td colspan="2">No results</td>' . "";
}
$html .= "</table>";
echo $html;
if (!mysqli_query($conn,$sql)) {
die('Error: ' . mysqli_error($conn));
}
// ----------------- ALL PAGES REPORT
echo "</br></br>";
echo "<tbody><table>";
echo "<tr><th align='left'>UNIQUE PAGES</th></tr>";
$sql = "SELECT distinct page_url FROM pageviews";
$allpages = mysqli_query($conn, $sql);
foreach ($allpages as $page){
echo "<tr>";
echo "<td>" . $page['page_url'] . "</td>";
echo "</tr>";
}
echo "</tbody></table>";
mysqli_close($conn);
error_reporting(E_ALL);
?>
That gives me this:
/analytics/testpage.php ---> /analytics/testpage2.php ---> /analytics/goal.php

How to find total rows before required row [duplicate]

This question already has answers here:
Rank function in MySQL
(13 answers)
Closed 8 years ago.
I have a text based mafia game and I am selected some GameRecords. The game records are all defined in the "users" table. For this example I am using "totalcrimes". I need to select all the rows from the users table and order it by totalcrimes and then find out which row each specific user is that is viewing the page.
If I was the user that was "ranked" 30th it would echo "30". The code I use to find the top 5 is here however I need to expand on it:
<?php
$i = 0;
$FindCrimes = mysql_query("SELECT * FROM players WHERE status='Alive' AND robot = 0 ORDER BY `totalcrimes` DESC LIMIT 5");
while($Row = mysql_fetch_assoc($FindCrimes)){
$Username = $Row['playername'];
$TotalCrimes = number_format($Row['totalcrimes']);
$i++;
echo "
<tr>
<td bgcolor='#111111' width='5%'>$i</td>
<td bgcolor='#111111' width='50%'><a href='viewplayer?playerid=$Username'>$Username</a></td>
<td bgcolor='#333333' width='45%'>$TotalCrimes</a></td></td>
</tr>
";
}
?>
I am going to assume that you already have a variable set to hold the current users ID number and total crimes, so in this case I will use $user as my variable.
Change yours to fit.
Now, I see 2 instances in which you could mean as your post wasn't very specific, so I will address both.
To show the number at the top of the page, you would use something like;
<?php
$sql = "SELECT * FROM `players` WHERE `totalcrimes` > '{$user['totalcrimes']}'";
$run = mysql_query($sql);
$rank = mysql_num_rows($run) + 1;
echo 'Your rank: ' . $rank;
Other than that, I see it's possibly being used to highlight your row, so something like this would suffice;
<?php
$i = 0;
$FindCrimes = mysql_query("SELECT * FROM players WHERE status='Alive' AND robot = 0 ORDER BY `totalcrimes` DESC LIMIT 5");
while($Row = mysql_fetch_assoc($FindCrimes))
{
$Username = $Row['playername'];
$TotalCrimes = number_format($Row['totalcrimes']);
$i++;
$primary = '#111111';
$secondary = '#333333';
if ($Row['id'] == $user['id'])
{
$primary = '#222222';
$secondary = '#444444';
}
echo "<tr>
<td bgcolor='$primary' width='5%'>$i</td>
<td bgcolor='$primary' width='50%'><a href='viewplayer?playerid=$Username'>$Username</a></td>
<td bgcolor='$secondary' width='45%'>$TotalCrimes</a></td></td>
</tr>";
}
If neither of those give your requirements, please comment and I'll edit to suit.
edit: I've worked on games for a few years - care to share the link to yours?
This can do the trick
SELECT COUNT(*)+1 as rank
FROM users
WHERE totalcrimes > (SELECT totalcrimes
FROM users
WHERE user_id='12345' AND status='Alive' AND robot='0');
So it counts all rows with greater totalcrimes than selected user (in this example I have used user_id column and some id 12345), than adds 1 on that sum and returns as rank value.
Course, modify WHERE clause inside the brackets to make it work for you.
I assumed that table name is users and user's id is integer user_id.
Test preview (Navicat Premium):
What this query does? It returns number of selected rows + 1 as rank column, from the table users where totalcrimes is greater than totalcrimes of some user. That user's totalcrimes is selected by another query (by its user_id). If you have multiple users with same totalcrimes value, this query will return same rank for all of them.

MySQL_Query from Multiple Tables with ROUND and Math

I'm trying to make a database of items for the game "EVE Online" for me and my friends to use, and I set up a SQL server and got tables created and the like, etc etc, and everything's running fine. However, I have one issue when I'm trying to import data from two different tables and compare them against each other within the same html table element. It works perfectly if I just import from one table with multiple columns, but I get issues when I try to select more than one source.
The tables I'm pulling from are...
testmetrics.eve_inv_types
and
testmetrics.items_selling
Ideally, I'd like to import the "name", "type_id", "jita_price_sell" columns from table #1, and "price", "type_id", "station_id", and "qty_avail" from table #2.
I'm also using the ROUND operator on jita_price_sell and price to get a 2 decimal approximation for price points of various items. I also have it so that in table #2 only results with the correct station_id will get displayed. But it keeps throwing up an error!
Here is my code so far...
<?php
$con = mysql_connect("testmetrics.db.10198246.xxxx.com","xxxx","xxxx");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db("testmetrics", $con);
$result = mysql_query("
SELECT testmetrics.eve_inv_types.name, testmetrics.eve_inv_types.type_id, ROUND(testmetrics.eve_inv_types.jita_price_sell, 2) as jita_price_sell, ROUND(testmetrics.items_selling.price, 2) as price, testmetrics.items_selling.qty_avail, testmetrics.items_selling.sation_id, testmetrics.items_selling.type_id
FROM testmetrics.eve_inv_types, testmetrics.items_selling
WHERE testmetrics.eve_inv_types.type_id = testmetrics.items_selling.type_id, testmetrics.items_selling.station_id = '61000746'");
echo "<table class='sortable'>
<tr>
<th>Item Name</th>
<th>Price (Jita)</th>
<th>Price (K-6K16)</th>
<th>Qty Avail (K-6K16)</th>
</tr>";
while($row = mysql_fetch_array($result))
{
echo "<tr>";
echo "<td>" . $row['testmetrics.eve_inv_types.name'] . "</td>";
echo "<td>" . $row['jita_price_sell'] . "</td>";
echo "<td>" . $row['price'] . "</td>";
echo "<td>" . $row['testmetrics.items_selling.qty_avail'] . "</td>";
echo "</tr>";
}
echo "</table>";
mysql_close($con);
?>
Any help or insight you could give would be greatly appreciated. I'd also like to be able to do a math function where I'd go something like testmetrics.eve_inv_types.jita_price_sell + (testmetrics.eve_inv_types.volume * 300) to get shipping costs and have that exported to it's own column as well.
Anything you have to say is greatly appreciated!
EDIT: I know I'm already asking for alot of help here, but, does anyone know how to limit returns to "top 100" dependent on the column that it's sorted by? I'm using a Javascript addon to be able to sort easily!
This is the code that solved it for me!
SELECT eve_inv_types.name,
eve_inv_types.type_id,
Round(eve_inv_types.jita_price_sell, 2) AS jita_price_sell,
Round(items_selling.price, 2) AS price,
items_selling.qty_avail,
items_selling.type_id
FROM eve_inv_types
JOIN items_selling
ON eve_inv_types.type_id = items_selling.type_id
AND items_selling.station_id = '61000746'
SELECT eit.name,
eit.type_id,
Round(eit.jita_price_sell, 2) AS jita_price_sell,
Round(eis.price, 2) AS price,
eis.qty_avail,
eis.sation_id,
eis.type_id
FROM eve_inv_types eit
JOIN `items_selling` eis
ON eit.type_id = eis.type_id
AND eis.station_id = '61000746'
You can join tables (assuming you have a key that connects them), here's an example:
table A:
personId
firstName
lastName
numOfChildren
table B:
personId
streetName
cityName
countryName
Select from both (using personID as a join key):
SELECT firstName, lastName, numOfChildren, streetName, cityName, countryName
FROM tableA JOIN tableB USING (personId)
If you want to limit the result you can add:
LIMIT 100
And if you want the top 100 parents you can order by numOfChildren:
ORDER BY numOfChildren
Final Query will look like this:
SELECT firstName, lastName, numOfChildren, streetName, cityName, countryName
FROM tableA JOIN tableB USING (personId)
ORDER BY numOfChildren
LIMIT 100;
-- or --
SELECT firstName, lastName, numOfChildren, streetName, cityName, countryName
FROM tableA JOIN tableB ON (tableA.personId=tableB.personId)
ORDER BY numOfChildren
LIMIT 100;
Read more about join here: http://dev.mysql.com/doc/refman/5.1/en/join.html

Doing an SQL query in PHP where a field from a different table is referenced

OK,
In this query I am displaying the sales for a particular person, matching the passport number from the current form I am working on.
What I want to do however, is to sum the total sales and display it, excluding records which have been marked as paid.
I am having trouble because "paid" does not existent in the current form I am working on as a variable, nor the table it relates to.
I canĀ“t use row['paid'] as I need to do this query outside of the while loop.
What should I do in this situation?
$sqlstr = mysql_query(
"SELECT * FROM sales where passport = ".
"'{$therecord['passport']}'");
if (mysql_numrows($sqlstr) != 0) {
echo "<b>Sales for {$therecord['firstname']} ".
"{$therecord['lastname']}</b><br />";
echo "<table><tr>";
echo '<tr><th align="left">Name</th><th align="left">Quantity</th>".
"<th align="left">Cost</th></tr>';
while ($row = mysql_fetch_array($sqlstr)) {
echo "<td>{$row['product']}</td>";
echo "<td>{$row['quantity']}</td>";
echo "<td>{$row['cost']}</td>";
echo "</tr>";
}
}
echo "</table>";
$sqltotal = mysql_query(
"SELECT SUM(cost) as total FROM sales where passport = ".
"'{$therecord['passport']} AND {$therecord['paid']} <> 1'");
$row = mysql_fetch_array($sqltotal);
echo "<br /><b>Total Owing: {$row['total']}</b>";
You could either create a MySQL view, of look at SQL joins. I'm not sure on your database structure, but you should have a SQL query like this:
SELECT SUM(sales.cost) AS total
FROM sales, table2
WHERE sales.passport = '$passport_id'
AND sales.passport = table2.passport
AND table2.paid = '1'
Not sure as that was wrote off-hand. Again, it'd be better if we knew the structure of your tables.
you've misplaced simple quote in :
"'{$therecord['passport']} AND {$therecord['paid']} <> 1'"
it must be :
"'{$therecord['passport']}' AND {$therecord['paid']} <> 1"

Categories