subtract last two rows and write result to new table MySQL - php

Hi I have try to follow couple of examples how to solve my problem but with no success.
So here is the situation
I have a table with the following ( the table will increase with each month)
mysql> DESCRIBE poraba;
+------------+------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------+------+-----+-------------------+-----------------------------+
| mesec | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| voda_mrzla | varchar(5) | NO | | NULL | |
| voda_topla | varchar(5) | NO | | NULL | |
+------------+------------+------+-----+-------------------+-----------------------------+
With the following vaules
mysql> SELECT * FROM poraba;
+---------------------+------------+------------+-----------+
| mesec | voda_mrzla | voda_topla | id_poraba |
+---------------------+------------+------------+-----------+
| 2014-03-03 16:19:08 | 5985 | 3417 | 1 |
| 2014-04-03 20:57:51 | 5978 | 3412 | 2 |
I would like to perform the following. Always only on last entry. So I get the difference between current and previous month.
Eg.:
voda_mrzla (from 2014-04-03) - voda_mrzla (from 2014-03-03) = difference_cold
voda_topla (from 2014-04-03) - voda_topla (from 2014-03-03) = difference_hot
in to
mysql> DESCRIBE usage_per_month;
+-----------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+-------+
| difference_cold | varchar(10) | NO | | NULL | |
| difference_hot | varchar(10) | NO | | NULL | |

It looks like poor database design. You should at least have an id column with an incremental value as a key. That way the (nonetheless cumbersome) query would be a little easier. Given your current design, what you need to do is this (very, very slow and inefficient):
insert into usage_per_month
select a.voda_mrzla - b.voda_mrzla, a.voda_topla - voda_topla
from ( select * from poraba where mesec = ( select max(mesec) from poraba) ) as a,
( select * from poraba where mesec = ( select max(mesec) from poraba where mesec <> (select max(mesec) from poraba) ) ) as b;
Yes, it's this ugly.

Changing all "varchar" in to "int" adding ID to all tables and executing the following solved my problem
INSERT INTO usage_per_month (difference_cold, difference_hot)
SELECT p1.voda_mrzla - p2.voda_mrzla AS poraba_mrzla1, p1.voda_topla - p2.voda_topla AS poraba_topla1 FROM poraba p1
LEFT JOIN poraba p2 ON p2.`id_poraba` = (
SELECT MAX(`id_poraba`) FROM poraba p3 WHERE p3.`id_poraba` < p1.`id_poraba`
) ORDER BY p1.id_poraba DESC LIMIT 1
Tnx for help!

Related

How to display a "foreign key" value in an array in PHP?

I have a current problem, I tried to search in the documentations and the answers already given in the same site, but none of the answers helped me.
In fact I have a database, and two tables.
-> gpscoordonnee
MariaDB [leguideduflaneur]> DESCRIBE gpscoordonnee;
+--------------+----------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+----------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| Nom_Commerce | int(11) | NO | MUL | NULL | |
| date | datetime | NO | | current_timestamp() | |
+--------------+----------+------+-----+---------------------+----------------+
3 rows in set (0.017 sec)
-> marchantpart
MariaDB [leguideduflaneur]> DESCRIBE marchantpart;
+---------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| Nom | varchar(200) | NO | | NULL | |
| Adresse | varchar(300) | NO | | NULL | |
| Tel | int(11) | NO | | NULL | |
| Email | varchar(100) | NO | | NULL | |
+---------+--------------+------+-----+---------+----------------+
5 rows in set (0.016 sec)
In the gpscoordonnee table, the Nom_Commerce field is a foreign Keys of Name of the marchantpart table.
I want by displaying the Nom_Commerce that it displays the contents of Nom
AND NOT 1
I have already tried all these methods but nothing is displayed, not even an error :
SELECT n.Nom
from gpscoordonnee us
LEFT JOIN marchantpart ON us.NID = n.Nom
OR
SELECT gpscoordonnee, marchantpart.Nom AS Nom_Commerce
FROM gpscoordonnee
JOIN marchantpart ON marchantpart.Nom=gpscoordonnee.Nom_Commerce
I don't want this :
Result that displays integers instead of names
But i want this :
Result with names
I find my error.
I use SELECT Nom FROM gpscoordonnee t1 INNER JOIN marchantpart t2 ON t1.Nom_Commerce=t2.id and my result is this
RESULT
Thanks for all the people who help me.

MySQL table optimization to speed up queries

I have a big mysql table ('d_operations') with more than 2 million records (and more to come). I have written a PHP webpage that shows a chart with the number of operations in a day for each half an hour (0:00 0:30 1:00 1:30 ... 23:59).
It works great but takes too much time to get the results so I am wondering if my table and queries could be optimized.
For each half an hour in a day I do a select query asking MySQL for the number of operations done in that period of time.
This takes more than a minute to finish!
This is the table schema:
mysql> describe d_operations;
+-----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+----------------+
| idx | int(11) unsigned | NO | PRI | NULL | auto_increment |
| system_id | int(11) | YES | | NULL | |
| dev_id | varchar(17) | YES | | NULL | |
| name | varchar(17) | YES | | NULL | |
| nond | smallint(6) | YES | | NULL | |
| is_new | smallint(6) | YES | | NULL | |
| tstamp | int(10) unsigned | YES | | NULL | |
+-----------+------------------+------+-----+---------+----------------+
I have a auto_increment primary key, that doesn't seem to help in the queries. The rest of the fields can be repeated (a device can do several operations in that period of time and it can be rows with the same tstamp).
tstamp is UNIX timestamp
This is how I do the queries in PHP:
for($i=$GLOBALS['init_hour'];$i<=($GLOBALS['end_hour']-1800);$i+=1800){
$n=$i+1800;
$sql="SELECT count(*) as num from d_operations where (tstamp >= $i and tstamp < $n);";
$r=mysqli_query($GLOBALS['con'],$sql);
$row = mysqli_fetch_row($r);
$values = ($i == $GLOBALS['init_hour']) ? $row[0] : $values.",".$row[0];
$GLOBALS['a_average'][$i]=$row[0];
}
In the worst case, I loop through every half an hour in that day, that is 48 queries.
This is the MySQL explain command:
mysql> explain select count(*) as num from d_operations where (tstamp >= 1464739200 and tstamp < 1464825599);
+----+-------------+--------------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | d_operations | ALL | NULL | NULL | NULL | NULL | 2215384 | Using where |
+----+-------------+--------------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)
Is there a more efficient way for doing this? (table definition, MySQL query optimization...)
Thanks
As Jon Stirling and Mark Baker suggested, the solution was as simple as creating an index for the tstamp column:
ALTER TABLE d_operations ADD INDEX ts_index(tstamp);
Thanks!

Mysql one to many relationship. Order by number of rows in second table

I have created a voting system in php and mysql. When a user votes on an id, a record is inserted in "votes" referencing the FK media_id. When I then display the entries I use this query to get the number of votes for each entry:
$sql = "SELECT COUNT(*) FROM insta_votes WHERE media_id ='".$mediaid."'";
if ($res = $db->query($sql)) {
return $res->fetchColumn();
}
return 0;
This works fine, but I want to be able to sort the results by the number of votes they have. Preferably using just one query. How can I achieve this?
The tables are structured like this:
votes table
+-----------+--------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| media_id | varchar(255) | NO | | NULL | |
| ip | varchar(20) | NO | | NULL | |
| c_time | timestamp | NO | | CURRENT_TIMESTAMP | |
| sessionid | varchar(30) | NO | | NULL | |
+-----------+--------------+------+-----+-------------------+----------------+
entries table
+---------------+--------------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+-------------------+-------+
| page_id | int(11) | NO | MUL | NULL | |
| media_id | varchar(255) | NO | PRI | NULL | |
| url | varchar(255) | NO | | NULL | |
| c_time | datetime | NO | | NULL | |
| likes | int(11) | YES | | NULL | |
| deleted | tinyint(1) | NO | | 0 | |
| inserted_time | timestamp | YES | | CURRENT_TIMESTAMP | |
| numReports | int(11) | NO | | 0 | |
+---------------+--------------+------+-----+-------------------+-------+
Thank you!
If I understand the tables correctly (and I may not), each entries row may reference multiple votes rows. In that case, the query you need will go something like this:
SELECT
entries.page_id,
COUNT(*) AS VoteCount
FROM entries
INNER JOIN votes ON entries.media_id = votes.media_id
GROUP BY entries.page_id
ORDER BY VoteCount
If you add additional entries columns to the SELECT list, be sure to add them to the GROUP BY list as well.
Addendum: #JuanPabloCalifano pointed out, correctly, that this query won't include entries with zero votes. Here's how to include them:
SELECT
entries.page_id,
COALESCE(COUNT(votes.id), 0) AS VoteCount
FROM entries
LEFT JOIN votes ON entries.media_id = votes.media_id
GROUP BY entries.page_id
ORDER BY VoteCount
SELECT COUNT(*) as CNT, `media_id` FROM `insta_votes` GROUP BY `media_id` order by 1;
SELECT COUNT(*), media_id FROM insta_votes
GROUP BY media_id
ORDER BY COUNT(*);"

In MySQL, how to select empty records

I have the following MySQL Table Structure:
mysql> desc customers;
+---------------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+-------------+------+-----+---------+-------+
| hash | varchar(32) | NO | PRI | NULL | |
| date_joined | date | NO | | NULL | |
| agent_code | int(5) | NO | UNI | | |
+---------------------+-------------+------+-----+---------+-------+
mysql> desc persons;
+--------------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+-------------+------+-----+---------+-------+
| agent_code | int(5) | NO | UNI | | |
| team_id | int(2) | YES | | 0 | |
| hash | varchar(32) | NO | PRI | NULL | |
+--------------------+-------------+------+-----+---------+-------+
mysql> desc teams;
+--------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | YES | | NULL | |
| leader | varchar(32) | NO | UNI | NULL | |
+--------+-------------+------+-----+---------+----------------+
And I'd wish to generate a report of sales by Team.
The SQL Query that I'm using is the following:
SELECT COUNT(`customers`.`agent_code) AS `customer_count`, `teams`.`name`
FROM `customers`
JOIN `persons` ON `customers`.`agent_code` = `persons`.`agent_code`
JOIN `teams` ON `persons`.`team_id` = `teams`.`id`
GROUP BY `teams`.`name`
And it shows the following information:
+----------------+--------+
| customer_count | name |
+----------------+--------+
| 3 | Team 1 |
+----------------+--------+
However I'd like to see the "customer_count" of all the teams in the database, even if the customer_count is null (or zero) for a given team. I have 15 teams in my database, so I'd like to see something like:
+----------------+--------+
| customer_count | name |
+----------------+--------+
| 3 | Team 1 |
| 0 | Team 2 |
| 0 | Team 3 |
| 0 | Team 4 |
+----------------+--------+
I have tried to execute some variants of the following Query, but I always get an error saying that the syntax of OUTER JOIN is incorrect, even though I've read the documentation, and it is correct.
SELECT COUNT( `customers`.`agent_code` ) AS `customer_count` , `teams`.`name`
FROM `customers`
LEFT JOIN `persons` ON `customers`.`agent_code` = `persons`.`agent_code`
LEFT OUTER JOIN `teams` ON `persons`.`team_id` = `teams`.`id`
GROUP BY `teams`.`name`
How can I alter my current query in order to display such result?
You have mistake get main table is person - I suggest your main table is team
SELECT COUNT(`customers`.`id`) AS `customer_count` , `teams`.`name`
FROM `teams`
JOIN `persons` ON `persons`.`team_id` = `teams`.`id`
LEFT JOIN `customers` ON `customers`.`agent_code` = `persons`.`agent_code`
GROUP BY `teams`.`name`
Update: if you do have empty teams, than you need to set left join on persons
SELECT COUNT(`customers`.`id`) AS `customer_count` , `teams`.`name`
FROM `teams`
LEFT JOIN `persons` ON `persons`.`team_id` = `teams`.`id`
LEFT JOIN `customers` ON `customers`.`agent_code` = `persons`.`agent_code`
GROUP BY `teams`.`name`

MySQL: i need to pull the same column name from multiple rows into single query based on same conditions

I want to combine the following queries into a single query:
SELECT val FROM resource WHERE facet="all" and urlId="1234"
SELECT val FROM resource WHERE facet="your" and urlId="1234"
SELECT val FROM resource WHERE facet="base" and urlId="1234"
Oh -- there are multiple "facets" for each urlId. But only one row per "facet". This table was setup by somebody else. We are migrating away. Obviously it would be better to have a column for each "facet" and a single row, but it's too late for that.
I can do this with multiple queries, but would like to have a faster/better solution.
<pre>
mysql> describe resource;
+-------------+-------------------------------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------------------------------+------+-----+-------------------+-----------------------------+
| resId | int(11) unsigned | NO | PRI | NULL | auto_increment |
| urlId | int(11) | NO | MUL | NULL | |
| sectionId | int(3) | YES | | NULL | |
| mode | enum('archive','live','edit','dev') | NO | | edit | |
| facet | varchar(50) | NO | MUL | NULL | |
| typeId | int(1) | NO | | 1 | |
| val | mediumtext | NO | | NULL | |
| itemOrder | tinyint(2) | NO | | 1 | |
| editorId | varchar(30) | NO | | NULL | |
| created | datetime | NO | | NULL | |
| lastUpdated | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------------+-------------------------------------+------+-----+-------------------+-----------------------------+
11 rows in set (0.05 sec)
</pre>
Remember: in soviet russia, SQL queries you.
This is my preferred method which will use your indexes:
SELECT resource.val FROM
( (SELECT "all" AS name) UNION (SELECT "your") UNION (SELECT "base") ) AS facets
LEFT JOIN resource ON( resource.facet = facets.name AND resource.urlId = "1234" )
You can use the mysql IN() comparison operator.
E.g:
SELECT `val` FROM `resource` WHERE `urlId` = "1234" AND `facet` IN("all", "your", "base");
Result in three columns:
SELECT (SELECT val FROM resource WHERE facet="all" and urlId="1234"),
(SELECT val FROM resource WHERE facet="your" and urlId="1234"),
(SELECT val FROM resource WHERE facet="base" and urlId="1234")
But I personally don't recommend this, it's not scalable. Go with my other answer.
SELECT val
FROM resource
WHERE urlId = '1234'
AND facet IN (
SELECT "all", "your", "base";
)
SELECT val
FROM resource
WHERE urlId = '1234'
AND facet IN ('all', 'your', 'base');
SELECT val
FROM resource
WHERE (facet = "all" or facet = "your" or facet = "base")
AND urlId = "1234"
or
SELECT val
FROM resource
WHERE facet in ("all", "your", "base")
AND urlId = "1234"

Categories