Joining MySQL Tables and Calculating Counts - Output in PHP - php

I am trying to query a MySQL database of available computers in a busy public computer lab. I have two tables, COMPUTERS and COMPUSE. The COMPUSE table is updated each time a user logs on or signs off a computer. When the logofftime is null, the computer is in use. In this example, Computers 1, 2, 3, and 8 are in use. Computers 4, 5, 6, 7, 9, 10 are available.
|-----------------------|-----------------------|----------|-----------|
| logontime | logofftime | recID | compname |
|-----------------------|-----------------------|----------|-----------|
| 2011-05-13 13:45:16 | <<null>> | 310052 | Comp001 |
| 2011-05-13 13:35:18 | 2011-05-13 13:39:37 | 310043 | Comp001 |
| 2011-05-13 12:12:09 | 2011-05-13 12:33:37 | 309979 | Comp001 |
| 2011-05-13 13:00:57 | <<null>> | 310018 | Comp002 |
| 2011-05-13 11:30:13 | 2011-05-13 12:58:15 | 309940 | Comp002 |
| 2011-05-13 09:36:15 | 2011-05-13 09:47:22 | 309850 | Comp002 |
| 2011-05-13 09:25:29 | <<null>> | 309840 | Comp003 |
| 2011-05-13 08:45:38 | 2011-05-13 09:24:03 | 309793 | Comp003 |
| 2011-05-12 22:39:58 | 2011-05-13 00:36:31 | 309640 | Comp003 |
| 2011-05-13 12:06:22 | 2011-05-13 12:50:23 | 309972 | Comp004 |
| 2011-05-13 11:10:16 | 2011-05-13 12:01:16 | 309915 | Comp004 |
| 2011-05-13 07:17:18 | 2011-05-13 09:42:10 | 309731 | Comp004 |
| 2011-05-13 11:51:38 | 2011-05-13 12:15:35 | 309959 | Comp005 |
| 2011-05-13 08:55:14 | 2011-05-13 09:47:48 | 309807 | Comp005 |
| 2011-05-12 18:15:05 | 2011-05-12 18:15:16 | 309502 | Comp005 |
| 2011-05-13 12:08:40 | 2011-05-13 13:16:41 | 309974 | Comp006 |
| 2011-05-13 11:29:09 | 2011-05-13 12:05:56 | 309939 | Comp006 |
| 2011-05-13 11:10:41 | 2011-05-13 11:19:14 | 309916 | Comp006 |
| 2011-05-13 10:45:27 | 2011-05-13 11:16:44 | 309896 | Comp007 |
| 2011-05-13 09:21:42 | 2011-05-13 09:55:48 | 309839 | Comp007 |
| 2011-05-13 08:23:33 | 2011-05-13 09:14:24 | 309770 | Comp007 |
| 2011-05-13 13:54:12 | <<null>> | 310058 | Comp008 |
| 2011-05-13 13:38:53 | 2011-05-13 13:39:23 | 310045 | Comp008 |
| 2011-05-13 10:13:23 | 2011-05-13 13:26:51 | 309878 | Comp008 |
| 2011-05-13 12:16:06 | 2011-05-13 13:26:21 | 309984 | Comp009 |
| 2011-05-13 10:13:09 | 2011-05-13 12:15:13 | 309877 | Comp009 |
| 2011-05-13 08:23:22 | 2011-05-13 10:07:08 | 309769 | Comp009 |
| 2011-05-13 13:45:51 | 2011-05-13 13:47:11 | 310053 | Comp010 |
| 2011-05-13 11:18:12 | 2011-05-13 13:19:59 | 309925 | Comp010 |
| 2011-05-13 07:28:50 | 2011-05-13 09:50:09 | 309737 | Comp010 |
|-----------------------|-----------------------|----------|-----------|
This data needs to be joined with a table that indicates which floor of the building the computer is on. That table looks similar to this:
|--------|-----------|-------------|
| compID | compname | LOCATION |
|--------|-----------|-------------|
| 95 | Comp001 | 1st Floor |
| 96 | Comp002 | 1st Floor |
| 97 | Comp003 | 1st Floor |
| 98 | Comp004 | 1st Floor |
| 99 | Comp005 | 2nd Floor |
| 100 | Comp006 | 2nd Floor |
| 101 | Comp007 | 2nd Floor |
| 102 | Comp008 | 3rd Floor |
| 103 | Comp009 | 3rd Floor |
| 104 | Comp010 | 3rd Floor |
|--------|-----------|-------------|
The first table, COMPUSE, has several thousand records in it as it is used for calculating usage statistics for the lab. I need to create an output of how many computers are available on each level. I don't know how to join location from the COMPUTERS table to compname from the COMPUSE table without disrupting my query. Initially, I ran the following query to determine the total number of computers available, but I really need to be able to break it down by area of the building.
SELECT
(SELECT COUNT(compname)
FROM compusage.computers) -
(SELECT COUNT(compname)
FROM compusage.compuse
WHERE logofftime IS NULL)
Can anyone help me construct a query that would output the number of available computers on each level of the building? The expected result in this example would be:
Level 1: 1 computer (of 4) available
Level 2: 3 computers (of 3) available
Level 3: 2 computers (of 3) available
Thanks,
Jordan
UPDATE: This is really similar to what I'm trying to do, but I also can't figure out how to adapt these queries: PHP::Group and subtract two tables
UPDATE 2: This is what I am trying to adapt now, but I don't understand subqueries well enough to get this to work:
select (totalcomps.total - inuse.inusecomps) as available, totalcomps.total
from (SELECT count(compname) as total, location
FROM compuse.computers
GROUP BY location) as totalcomps
inner join (SELECT count(compname) as inusecomps
FROM computers.compuse
WHERE logofftime is null
GROUP BY location) as inuse
on computers.compname = compuse.compname
UPDATE 3: I've updated the sample data to be more of a real-world example with more records.

Have you tried this?
SELECT LOCATION, COUNT(1) as numberOfComps
FROM COMPUTERS c
LEFT JOIN COMPUSE cu ON c.COMPNAME = cu.Computer
WHERE logofftime IS NULL
GROUP BY LOCATION

I did accomplish this task through some PHP calculations based on two separate MySQL queries. This works, but I would prefer to structure an SQL query that does the same thing. Here's the PHP:
<?php
$username = "user"; $password = "passwd"; $database = "compusage";
mysql_connect(localhost,$username,$password);
#mysql_select_db($database) or die( "Unable to select database");
$inUseQuery = "SELECT location, COUNT(1) as inUseComps
FROM compusage.computers
INNER JOIN compusage.compuse ON computers.compname = compuse.compname
WHERE logofftime IS NULL
GROUP BY LOCATION";
$totCompsQuery="SELECT location, COUNT(compname) as totComps
FROM compusage.computers
GROUP BY LOCATION";
$result = mysql_query($inUseQuery);
$inUseNum = mysql_numrows($result);
$totCompsResult = mysql_query($totCompsQuery);
$totCompsNum = mysql_numrows($totCompsResult);
mysql_close();
$i=0;
while ($i < $inUseNum) {
$numCompsInUse=mysql_result($result,$i,"inUseComps");
$inUseLocation=mysql_result($result,$i,"location");
$inUseArray[$inUseLocation] = $numCompsInUse;
$i++;
}
$i=0;
while ($i < $totCompsNum) {
$totComps=mysql_result($totCompsResult,$i,"totComps");
$totCompsLocation=mysql_result($totCompsResult,$i,"location");
$totCompsArray[$totCompsLocation] = $totComps;
$i++;
}
while($totCompsKey = key($totCompsArray)) {
if (array_key_exists($totCompsKey, $inUseArray)) {
$availFloor = $totCompsArray[$totCompsKey] - $inUseArray[$totCompsKey];
if ($availFloor == "1") {
printf("<li>%s: %s computer available.</span></li>", $totCompsKey, $availFloor);
}
else {
printf("<li>%s: %s computers available.</span></li>", $totCompsKey, $availFloor);
}
}
else {
printf("<li>%s: all computers in use.</span></li>", $totCompsKey);
}
next($totCompsArray);
}
?>

SELECT LOCATION, COUNT(compID) as Available
FROM COMPUTERS C1
INNER JOIN COMPUSE C2 ON C1.COMPNAME = C2.COMPNAME WHERE LOGOFF TIME IS NOT NULL
GROUP BY LOCATION

Related

How to Have a Single Query to LEFT JOIN with IF condition Like This?

I have this table, named profit_loss :
+--------------------+------------+----------+-------------+------------------+
| timestamp | fee | fee_unit | profit_loss | profit_loss_unit |
+--------------------+------------+----------+-------------+------------------+
| lm83-1526098952020 | 0.00750007 | BNB | 0.09672160 | USDT |
| lm83-1526098952020 | 0.00750007 | BNB | 0.00000000 | BNB |
| lm83-1526098952020 | 0.00750007 | BNB | 0.00000050 | BTC |
+--------------------+------------+----------+-------------+------------------+
and also have this, named trading_price :
+--------------------+-----------+---------------+---------------+
| timestamp | pair_name | bid_price | ask_price |
+--------------------+-----------+---------------+---------------+
| lm83-1526098952020 | NEOUSDT | 63.14000000 | 63.20000000 |
| lm83-1526098952020 | NEOBTC | 0.00749700 | 0.00749900 |
| lm83-1526098952020 | NEOETH | 0.09287900 | 0.09319500 |
| lm83-1526098952020 | NEOBNB | 4.95100000 | 4.96700000 |
| lm83-1526098952020 | BNBUSDT | 12.73850000 | 12.74580000 |
| lm83-1526098952020 | BNBBTC | 0.00151130 | 0.00151190 |
| lm83-1526098952020 | BNBETH | 0.01873500 | 0.01876000 |
| lm83-1526098952020 | LTCBNB | 10.73000000 | 10.77000000 |
| lm83-1526098952020 | BCCBNB | 107.73000000 | 108.37000000 |
| lm83-1526098952020 | LTCUSDT | 136.80000000 | 137.14000000 |
| lm83-1526098952020 | LTCBTC | 0.01625800 | 0.01627000 |
| lm83-1526098952020 | LTCETH | 0.20172000 | 0.01627000 |
| lm83-1526098952020 | BCCUSDT | 1372.01000000 | 1374.11000000 |
| lm83-1526098952020 | BCCBTC | 0.16314900 | 0.16315100 |
| lm83-1526098952020 | BCCETH | 2.02004000 | 2.02785000 |
| lm83-1526098952020 | BTCUSDT | 8412.13000000 | 8412.14000000 |
| lm83-1526098952020 | ETHUSDT | 677.88000000 | 678.55000000 |
| lm83-1526098952020 | ETHBTC | 0.08055000 | 0.08060500 |
+--------------------+-----------+---------------+---------------+
how to LEFT JOIN those tables so that the result will be like this?
+--------------------+------------+----------+-------------+------------------+-----------+---------------+---------------+
| timestamp | fee | fee_unit | profit_loss | profit_loss_unit | pair_name | bid_price | ask_price |
+--------------------+------------+----------+-------------+------------------+-----------+---------------+---------------+
| lm83-1526098952020 | 0.00750007 | BNB | 0.09672160 | USDT | BNBUSDT | 12.73850000 | 12.74580000 |
| lm83-1526098952020 | 0.00750007 | BNB | 0.00000000 | BNB | BNBBNB | 1 | 1 |
| lm83-1526098952020 | 0.00750007 | BNB | 0.00000050 | BTC | BNBBTC | 0.00151130 | 0.00151190 |
+--------------------+------------+----------+-------------+------------------+-----------+---------------+---------------+
please keep in mind that I only need trading_price.pair_name based on profit_loss.fee_unit and profit_loss.profit_loss_unit combined.
but with if condition like this :
profit_loss.fee_unit and profit_loss.profit_loss_unit
combined is not exist, then try the opposite way :
profit_loss.profit_loss_unit and profit_loss.fee_unit
how to have a single query to LEFT JOIN with IF condition like this?
We could use two left join operations, to attempt to get both of the matching rows, and then use expressions in the SELECT list that test whether a matching row was found.
SELECT p.timestamp
, ...
, CASE WHEN t.timestamp IS NOT NULL
THEN t.pairname
ELSE r.pairname
END AS pairname
, CASE WHEN t.timestamp IS NOT NULL
THEN t.bidprice
ELSE r.bidprice
END AS bidprice
, IF(t.timestamp IS NULL, r.askprice, t.askprice) AS askprice
FROM profit_loss p
LEFT
JOIN trading_price t
ON t.timestamp = p.timestamp
AND t.pairname = CONCAT(p.fee_unit,p.profit_loss_unit)
LEFT
JOIN trading_price r
ON t.timestamp IS NULL
AND r.timestamp = p.timestamp
AND r.pairname = CONCAT(p.profit_loss_unit,p.fee_unit)
WHERE ...
ORDER BY ...
In the LEFT JOIN to r, the condition on t.timestamp will check whether we found a matching row from t. If we found a matching row, then this condition will evaluate to FALSE, so no rows from r will match. Conversely, if no matching row from t, then this condition will evaluate to TRUE, so we will return any matching rows from r.
If there are multiple rows matched in t, this query will return multiple copies of the row from p, a copy for each matching row from t. (If no rows matched in t, then same issue with r.) (We mention this because don't see any guarantee that there won't be more than one matching row.)
This is an example of just one approach; there are other query patterns that will achieve an equivalent result.
EDIT
NOTES:
The query will return a row from p when there are no matching rows in t or r. If the requirement is that a row from p be returned only if a matching row is found, then we could handle that condition in a HAVING clause, immediately before the ORDER BY, a condition that tests whether a row was returned
HAVING (t.pairname IS NOT NULL OR r.pairname IS NOT NULL)
If we have a guarantee that askprice and bidprice will not be NULL, then we could simplify the expressions in the SELECT list
, IFNULL(t.pairname,r.pairname) AS pairname
, IFNULL(t.bidprice,r.bidprice) AS bidprice
, IFNULL(t.askprice,r.askprice) AS askprice
There's a variety of expressions we can use in the SELECT list to achieve an equivalent result.

sql query is taking long time to execute

I wrote this sql query and it works but it is taking long time to be executed
SELECT trans_files.id, trans_files.game_name, trans_files.file_name,
COUNT(en_txt.id) as txt_num, COUNT(ar_txt.id) as n_txt_num
FROM trans_files
LEFT JOIN en_txt ON en_txt.file_id = trans_files.id
LEFT JOIN ar_txt ON ar_txt.en_text_id = en_txt.id
&& ar_txt.date = (SELECT MAX(ar_txt.date)
FROM ar_txt
WHERE en_text_id = en_txt.id)
GROUP BY trans_files.id
ORDER BY trans_files.id DESC, trans_files.game_name ASC, trans_files.file_name ASC
..
mysql> select * from ar_txt limit 3;
+----+------------+---------+----------------+---------------------+
| id | en_text_id | user_id | text | date |
+----+------------+---------+----------------+---------------------+
| 1 | 16 | 3 | Ϻ┘äÏ▓Ï╣┘è┘à | 2017-01-24 19:10:19 |
| 2 | 18 | 3 | Ϻ┘äϡϻϺϻ | 2017-01-24 19:13:36 |
| 3 | 3 | 3 | Ϻ┘äÏÀÏ¿┘èÏ¿┘è | 2017-01-24 19:15:48 |
+----+------------+---------+----------------+---------------------+
mysql> select * from en_txt limit 3;
+----+---------+------------------+
| id | file_id | text |
+----+---------+------------------+
| 1 | 2 | Apothecary Cheng |
| 2 | 2 | Blacksmith Ho Li |
| 3 | 2 | Apothecary Sung |
+----+---------+------------------+
mysql> select * from trans_files limit 3;
+----+-----------+-----------+
| id | game_name | file_name |
+----+-----------+-----------+
| 1 | drb | skills |
| 2 | drb | npcs |
| 3 | drb | test |
+----+-----------+-----------+
in this case i am using PDO and query to execute it
PHP code
so why does it take a long time?

Codeigniter join multiple tables with where clauses

I have four tables that I need to join together, with one of those tables having two different records I need to grab. The guild and party tables I'm getting the name of those so that I can display the name instead of ID to the user, and the charlog table has the char_id's creation date and last login date that I want to show as well. Here are the tables:
char table:
----------------------------------------------------
| char_id | name | guild_id | party_id |
|---------------------------------------------------
| 150000 | char1 | 3 | 3 |
| 150001 | char2 | 2 | (NULL) |
| 150002 | char3 | (NULL) | 1 |
| 150003 | char4 | 1 | 2 |
----------------------------------------------------
guild table:
-------------------------
| guild_id | name |
-------------------------
| 1 | guild_1 |
| 2 | guild_2 |
| 3 | guild_3 |
-------------------------
party table:
-------------------------
| party_id | name |
-------------------------
| 1 | party_1 |
| 2 | party_2 |
| 3 | party_3 |
-------------------------
charlog table:
----------------------------------------------------
| time | char_id | char_msg |
----------------------------------------------------
| 2015-02-14 06:45:32 | 150000 | make new char |
| 2015-02-14 06:45:58 | 150000 | char select |
| 2015-02-15 12:32:19 | 150001 | make new char |
| 2015-02-15 16:54:01 | 150000 | char select |
| 2015-02-15 19:23:54 | 150001 | char select |
| 2015-02-16 01:32:13 | 150002 | make new char |
| 2015-02-16 01:33:01 | 150003 | make new char |
| 2015-02-16 04:45:43 | 150000 | char select |
| 2015-02-16 07:43:22 | 150003 | char select |
----------------------------------------------------
As mentioned, I need to get the make new char entry from the charlog table to display when the character was created and as well the LAST (by date) char select entry to display when the character was played, all of this with one single char_id.
All in all, I'd be looking for a table that looks like this:
---------------------------------------------------------------------------------------------------------------------
| char_id | name | guild_id | guild_name | party_id | party_name | create_time | lastlogin_time |
---------------------------------------------------------------------------------------------------------------------
| 150000 | char1 | 3 | guild_3 | 3 | party_3 | 2015-02-14 06:45:32 | 2015-02-16 04:45:43 |
I'm using the following active record lines in Codeigniter to attempt to get the data I need. It returns the create_date correctly but the lastlogin_time is not returned (it's blank):
function get_char_info($cid) {
$this->db->select('char.*,guild.guild_id,guild.name AS guild_name,party.party_id,party.name AS party_name,charlog1.time AS create_time,charlog2.time AS lastlogin_time');
$this->db->from('char');
$this->db->where('char.char_id', $cid);
$this->db->join('guild', 'char.guild_id = guild.guild_id', 'left');
$this->db->join('party', 'char.party_id = party.party_id', 'left');
$this->db->join('charlog AS charlog1', 'char.char_id = charlog1.char_id AND charlog1.char_msg = "make new char"', 'left');
$this->db->join('charlog AS charlog2', 'char.char_id = charlog2.char_id AND charlog2.char_msg = (SELECT max(charlog.time) FROM charlog WHERE char_msg = "char select")', 'left');
$query = $this->db->get();
return $query->row();
}
As mentioned, the guild_name, party_name and create_time come through correctly, but the lastlogin_time is blank, no error.
I've tried jumbling some things around in the active record clauses but can't get the lastlogin_time to show. Any help would be appreciated.
The join on your subquery is not correct :
It should be charlog2.time = (SELECT....) not charlog2.char_msg = (SELECT....)

pulling from a specific data from a row and column in a database

My data base looks like this.
its ordered ascending by NO#
And col2 is the start of the database NO# is basically invisible and only used as a reference as to row number
so lets say I wanted to display on a web page the text in col8, row 5. What would the php code be?
PS. the connect code is seperate and not an issue hence i did not include itI
-|NO#|col2|col3|col4|col5|col6|col7|col8|col9|col10
---------------------------------------------------
|1 | | | | | | | | | |
---------------------------------------------------
|2 | | | | | | | | | |
---------------------------------------------------
|3 | | | | | | | | | |
---------------------------------------------------
|4 | | | | | | | | | |
---------------------------------------------------
|5 | | | | | | |2012| | |
---------------------------------------------------
|6 | | | | | | | | | |
---------------------------------------------------
|7 | | | | | | | | | |
---------------------------------------------------
|8 | | | | | | | | | |
---------------------------------------------------
|9 | | | | | | | | | |
---------------------------------------------------
|10 | | | | | | | | | |
---------------------------------------------------
Here is my code but it whites out the page when I try to load it.
<?php
//selects row
$query = "SELECT * FROM `Inventory` WHERE NO# = '5'";
//select column
$col8 = $row['col8'];
// fetch the results
WHILE($row = mysql_fetch_array($query):
$row = mysql_fetch_array($result);
// display the results
<div id="year">echo "$col8";</div>
?>
I would probably do something like what's below. I have not tested this code, though.
<?php
$result = mysql_query( "SELECT `col8` FROM `Inventory` WHERE `NO#` = '5' LIMIT 1" );
$row = mysql_fetch_assoc( $result );
?>
<div id="year"><?php echo $row['col8']; ?></div>
Hopefully that'll help you out a bit.

My table in postgresql is truncating these strings

I have a table in VMobjects like this
MGRCONFIG_DB=# select * from vmobjects;
guid | ipaddress | username | password | hostid | vmname | guestostype | guestos
name
-----------------------------------+---------------+----------+----------+----------+-----------------+-------------+--------
-----
7728235734dcd25700e7c02.96324791 | gsdag | gsdasd | | Physical | rag | windows |
3642656604dcd343d3bcd11.54875889 | fsd | | | Physical | derde | windows |
17714467484dcd35dd0fa677.27764184 | dsf | | | Physical | fdsfd | windows |
1837080764dcd362fafe404.83675706 | fgf | | | Physical | fgf | windows |
2791118544dcd363df11bf1.21924610 | fdghhg | | | Physical | $%^ | windows |
7716352574dcd365c9eb777.30236042 | dsffd | | | Physical | ^ | windows |
10753160514dcd366631f5b6.48505657 | gfdgd | | | Physical | # | windows |
8253046164dcd366f177bc3.85542378 | ghgfdhg | | | Physical | ############## | windows |
9126180214dcd367a5b42e0.23605256 | fsdfdsfdsf | | | Physical | fdsaj;( | windows |
11086632854dcd36f62f7e79.14470771 | dfsdfsd | | | Physical | ^ | windows |
Now I have a php page addvm.php, when I add username/ip/password/ or anything it gets truncated
gets truncated on entering data as '~!##$%^&*()_+=-`{}|\][:"';<>?/.,' for all fields.
After using pg_escape_string
i am able to insert '~!##$%^()_=-`{}|][:"';<>?/. all strings except + and &.
#Emil Vikström: say that i have to use urlencode for this. but i don't no, How & whr it is used?
Use pg_escape_string on the data before entering it into your SQL query:
$data = '~!##$%^&*()_+=-';
$data_escaped = pg_escape_string($data);
$query = 'INSERT INTO table (data) VALUES("'. $data_escaped .'");';

Categories