How to link and display MySQL data from two different tables? - php

I have two tables named "stats" and "users"
users table has all the typical user data like id,username,password,email(columns)
stats table has id,attack, defense,ostats,gold,food(columns)
I want to display data from these two tables side by side and have the data linked through their IDS
For example,
Rank user_uid ostats attack defense gold
1 Test 10 5 5 100
2 Test2 8 2 6 60
3 Test3 6 5 1 40
Username is from table "users" and the rest of them are from table "stats"
So first I want to know how to link and display the data from the same ID, like Username(user_id=1) and ostats,attack,defense,gold,food(id=1)
Then I want them in order by their "ostats" (I don't have a column named "rank" in any table yet, just don't know how to create the rank using overall stats)

You could do something like (untested)
SELECT u.username, s.overall, s.attack, s.defense, s.gold
FROM stats s JOIN users u on s.user_uid = u.id
ORDER BY s.overall;
Possible solution to ranking:
set #row_number=0;
SELECT (#row_number:=#row_number+1) as rank, u.username, s.overall, s.attack, s.defense, s.gold
FROM stats s JOIN users u on s.user_uid = u.id
ORDER BY s.overall;
Another, horrible looking attempt:
set #row_number = (select count(*) from users) + 1;
select (#row_number:=#row_number-1) as rank, u.username, s.overall from
stats s join users u on s.user_uid = u.id order by s.overall desc;
set #row_number = 0;
Here in PHP code, you have to run it as two queries to set the variable, then run the actual ranking query. This way, the rank variable is always set to 0 when running this. Note that I've used different table and column names, just to simplify things a little. Remember to adjust to your specific needs.
// connect to database
$conn = mysqli_connect("localhost", "user", "password", "database");
// this query will set a variable to 0.
$setSql = "SET #row_number = 0;";
// run the query. This will return a boolean - true or false, depending on whether or not the query ran successfully
$variableSet = mysqli_query($conn, $setSql);
// if the query ran successfully
if($variableSet){
// setup the actual ranking query
$statsSql = "select
(#row_number:=#row_number+1) as rank,
u.id,
u.username,
s.overall
from
mstats s
join
musers u
on
s.muser = u.id
order by
s.overall desc;";
$ranks = mysqli_query($conn, $statsSql);
if(!$ranks){
// dump error from rank query
var_dump($conn->error);
} else {
// dump results as associative array
var_dump($ranks->fetch_all(MYSQLI_ASSOC));
}
} else {
// dump errors from setting variable
var_dump($conn->error);
}
For me, the results dump looks like this:
array (size=3)
0 =>
array (size=4)
'rank' => string '1' (length=1)
'id' => string '2' (length=1)
'username' => string 'Bar' (length=3)
'overall' => string '1000' (length=4)
1 =>
array (size=4)
'rank' => string '2' (length=1)
'id' => string '6' (length=1)
'username' => string 'Tom' (length=3)
'overall' => string '7' (length=1)
2 =>
array (size=4)
'rank' => string '3' (length=1)
'id' => string '1' (length=1)
'username' => string 'Foo' (length=3)
'overall' => string '3' (length=1)

Related

Php mysql join to subarray with field names

I trying to join table using ONE query into sub array with column name => column value..
Short table(1) "users" structure with data:
user_id email ...
1 xxx#xx.xx ...
2 yyy#yy.yy ...
Short table(2) "users_permissions" structure with data:
user_id plugin_enter offers_view ...
1 1 0 ...
2 1 1 ...
If i use classic method - join left
SELECT `uperms`.*, `u`.*
FROM (`users` as u)
LEFT JOIN `users_permissions` as uperms ON `u`.`user_id` = `uperms`.`user_id`
I get classic output
[0] = array(
'user_id' => 1,
'email' => xxx#xx.xx,
'plugin_enter' => 1,
'offers_view' => 0
),
[1] = array(
'user_id' => 2,
'email' => yyy#yy.yy,
'plugin_enter' => 1,
'offers_view' => 1,
...
),
All i need is output into subarray as this:
[0] = array(
'user_id' => 1,
'email' => xxx#xx.xx,
'permissions => array(
'plugin_enter' => 1,
'offers_view' => 0
),
),
...
Is this possible to do with ONE query?
Table2 (permissions) contains about 60 columns. Is possible to CONCAT column's names with column value, if is joined to Table1 only one row?
MySQL doesn't have arrays or nested structures, so it's not possible to do this in SQL.
Change your query so you give all the fields from users_permissions a consistent naming style. Then you can use a PHP loop to collect all the array elements whose keys match that pattern into the permissions array.
Query:
SELECT u.*, up.plugin_enter AS perm_plugin_enter, up.offers_view AS perm_offers_view, ...
FROM users AS u
JOIN users_permissions AS up ON u.user_id = up.user_id
PHP:
foreach ($all_results as &$row) {
$permissions = array();
foreach ($row as $key => $value) {
if (strpos($key, 'perm_') === 0) {
$permission[substr($key, 5)] = $value;
unset($row[$key]);
}
}
$row['permissions'] = $permissions;
}
You could do it by concatenating all the column names and values in the table:
SELECT u.*, CONCAT_WS(',', CONCAT('plugin_enter:', plugin_enter), CONCAT('offers_view:', offers_view), ...) AS permissions
FROM users AS u
JOIN users_permissions AS up ON u.user_id = up.user_id
Then your PHP code can use explode() to split $row['permissions'] into array of name:value pairs, and then convert those to key=>value in the PHP array.
Another solution is to redesign your users_permissions table:
user_id permission_type value
1 plugin_enter 1
1 offers_view 0
...
2 plugin_enter 1
2 offers_view 1
...
Then you can query:
SELECT u.*, GROUP_CONCAT(permission_type, ':', value) AS permission
FROM users AS u
JOIN users_permissions AS up on u.user_id = up.user_id
Another possible sollution is to add prefixes to query.
Inspired by post: https://stackoverflow.com/a/9926134/2795923
SELECT `u`.*, ':prefix_start:', `uperms`.*, ':prefix_end:'
FROM (`users` as u)
LEFT JOIN `users_permissions` as uperms ON `u`.`user_id` = `uperms`.`user_id`
Output array looks like this:
[0] => array(
'user_id' => 1
'email' => xxx#xx.xx,
'prefix_start' =>
'plugin_enter' => 1,
'offers_view' => 0
'prefix_end' =>
)
...
Then easy PHP script to add all array data between prefix_start and prefix_end into own subarray.

Codeigniter $query->result() returns strange results

This peace of code is driving me crazy for last hour...
I have this model which should return all non active records from DB
$query = $this->db->get($tableName);
echo $this->db->last_query();
var_dump($query->result());
$this->db->last_query() output is
SELECT * FROM `locations` LEFT JOIN `provinces` ON `provinces`.`id_province` = `locations`.`id_province` LEFT JOIN `countries` ON `countries`.`id_country` = `provinces`.`id_country` LEFT JOIN `statuses` ON `statuses`.`id_status` = `locations`.`id_status` WHERE `locations`.`active` = '0' ORDER BY `locations`.`id_location` DESC LIMIT 50
If i run exactsame query in phpmyadmin i get correct results
But when i var_dump data var_dump($query->result()); i get the following results
array (size=50)
0 =>
object(stdClass)[61]
public 'unique_id' => string 'OWYwYjBmNm' (length=10)
public 'active' => string '1' (length=1)
public 'owner_name' => string 'Cleve Greenfelder' (length=17)
1 =>
object(stdClass)[62]
public 'unique_id' => string 'YWY4YmMzMm' (length=10)
public 'active' => string '1' (length=1)
public 'owner_name' => string 'Bradford Hyatt' (length=14)
Why/how this active state get's overwritten from 0 to 1?
IF you need any additional information's, please let me know and i will provide. Thank you!
Once i wrote a question, answer quickly appeared in my head :)
Table Countries has also active field, so this field overwrites active state as enabled. I needed to specified fields and there's name in query in order to get proper results
$fields = 'unique_id, locations.active as active, ....';

Count instances in table and capture the id of every instance

What I'm trying to do is search through my table and count the instances of a letter, and store the ID of each instance in mysql and php (PDO).
What I had been messing around with is this:
$user = 'john';
$stmt = $pdo->prepare("SELECT id, SUBSTR(surname, 1, 1) as surname_init,COUNT(*) as count FROM first_table WHERE user = :user GROUP BY surname_init ORDER BY count DESC");
$stmt->bindValue(":user", $user);
$stmt->execute();
$row = $stmt->fetchAll(PDO::FETCH_ASSOC);
var_dump($row);
This is the result:
array (size=2)
0 =>
array (size=3)
'id' => string '3' (length=1)
'surname_init' => string 'B' (length=1)
'count' => string '2' (length=1)
1 =>
array (size=3)
'id' => string '7' (length=1)
'surname_init' => string 'D' (length=1)
'count' => string '1' (length=1)
So I have two results: B has 2 instances, D has one. However "B" has only one resulting id returned from two.
Is this possible? I think I'm missing something here..
Use GROUP_CONCAT() to get all rows that matched the group by, like:
SELECT
GROUP_CONCAT(id) AS id_list,
SUBSTR(surname, 1, 1) as surname_init,
COUNT(*) as count
FROM first_table
WHERE user = :user
GROUP BY surname_init
ORDER BY count DESC
See if this helps:
$user = 'john';
// use this to get unique starting characters for surnames for the user John
$stmt = $pdo->prepare("SELECT SUBSTR(surname, 1, 1) as `surname_init`,
COUNT(*) as `count` FROM first_table
WHERE user = :user GROUP BY
surname_init ORDER BY count DESC");
$stmt->bindValue(":user", $user);
$stmt->execute();
$rows1 = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows1 as $row1){
echo "<BR>Starting Letter: " . $row1['surname_init'];
echo "<BR>Count: " . $row1['count'];
// now get all the IDs for this user that have the
// surnames starting with this alphabet
$stmt = $pdo->prepare("SELECT ID, SUBSTR(surname, 1, 1) as `surname_init`,
FROM first_table
WHERE user = :user
AND surname LIKE :surname");
$stmt->bindValue(":user", $user);
$stmt->bindValue(":surname", $row1['surname_init']."%");
$stmt->execute();
$rows2 = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($rows2 as $row2){
// do insert based on ID here
}
}

Desirable result in "UNION"

MY sql query is
SELECT id, content FROM table1
UNION ALL
SELECT p_id, p_content FROM table2;
It is giving the desirable result but with column name of first select statement.
e.g
if the query get the data from second select statement it give the result as
array (size=2)
'id' => string '15' (length=2)
'content' => string 'table2 content' (length=22)
i want column name with respective select statement result.
e.g
if select got result from first select then the array of result should be like this
array (size=2)
'id' => string '15' (length=2)
'content' => string 'table1 content' (length=22)
else if select got result from second select statement then the array of result should be like this
array (size=2)
'**p_id**' => string '15' (length=2)
'**p_content**' => string 'table2 content' (length=22)
This is not possible. The column names will be the same throughout the query result. Those column names are actually the column names of the query result and don't need to be the same as column names in the table(s):
SELECT id as Numbers, content as Texts FROM table1
UNION ALL
SELECT p_id, p_content FROM table2;
You can execute two separate queries and process their results separately.
Or otherwise you could return an extra constant value to determine between the results:
SELECT id, content, '1' as TableNr FROM table1
UNION ALL
SELECT p_id, p_content, '2' FROM table2;
Now, for each row you can ask the value of the column 'TableNr' to see which table it came from.

Selecting unique records from mysql with considering only one field

My question may be not reflecting my problem, sorry for that at first. I have a problem , I need to select distinct movie names from a table also selecting its id and other records. But since ids are different for each movies, all the movies are selected(with same name ). Here's the query :
$sql = "
SELECT DISTINCT
movie_id,movie_name
FROM
tbl_current_movies as cm, tbl_movie_hall as mh
WHERE
movie_active = 'active'
AND
cm.hall_id = mh.hall_id
";
$res = $this->db->returnArrayOfObject($sql,$pgin = 'no');
var_dump($res);
And var_dump($res) says :
array
0 =>
object(stdClass)[48]
public 'movie_id' => string '1' (length=1)
public 'movie_name' => string 'MIB' (length=12)
1 =>
object(stdClass)[49]
public 'movie_id' => string '2' (length=1)
public 'movie_name' => string 'Jetuka Pator Dare' (length=17)
2 =>
object(stdClass)[50]
public 'movie_id' => string '3' (length=1)
public 'movie_name' => string 'MIB' (length=12)
So as you can see the movie MIB is showing twice, but I want to get in the results the movies MIB only once !
Change your query to this :
$sql = "SELECT movie_id , movie_name
FROM tbl_current_movies as cm
LEFT JOIN tbl_movie_hall mh ON cm.hall_id = mh.hall_id
WHERE movie_active = 'active'
GROUP BY movie_name
";
You shouldn't join your tables in the WHERE clause, if you're not confortable with the JOINs you can read some of the docs : http://dev.mysql.com/doc/refman/5.0/en/join.html
That should help you understand what they are for.

Categories