Select SQL query from two different tables but same database - php

i would like to select an sql query from two different tables. but both tables are in the same database.
this is my sql code and "air, temp, humidity, mq2" are from one table known as the "pi_sensors_network" while "Dust" is from another table known as "pi_dust_sensor". may i know how to go about selecting air, temp, humidity, mq2, Dust from 2 different tables but the same database? Thanks!
on a side note, there is no relation between both the tables. i just want to fetch the data from two different tables.
$sql = "SELECT air, temp, humidity, mq2, Dust FROM pi_sensors_network ORDER BY time DESC LIMIT 1";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row

Just use an alias for each table:
SELECT t1.air, t1.temp, t1.humidity, t1.mq2, t1.Dust As Dust1, t2.Dust As Dust2
FROM pi_sensors_network t1,
pi_dust_sensor t2
ORDER BY time DESC LIMIT 1";

You left a few things out in your schema description and query. Do you have a field in one of the tables that refers to the equivalent record in the other table (i.e. a foreign key)? If so, you can use a JOIN. You didn't mention which table has the time field.
Here is my stab at your desired query, but making assumptions on the unanswered questions. I assumed that you had a field pi_sensors_network.id that is a primary key for the pi_sensors_network table. I also assumed that there was a field pi_dust_sensor.fkid that connected the rows in the pi_dust_sensor table with the rows in the pi_sensors_network table.
SELECT air, temp, humidity, mq2, Dust
FROM pi_sensors_network INNER JOIN
pi_dust_sensor ON pi_sensors_network.id = pi_dust_sensor.fkid
ORDER BY time DESC LIMIT 1
Hopefully that will point you in the right direction. If you can answer my questions, I will be happy to update my answer.

you can combine data of two table in one object and can use after that how you want the output look like:
SELECT *
(
SELECT air, temp, humidity, mq2, '' As Dust,[time]
FROM pi_sensors_network
union all
select '' as air, '' as temp, '' as humidity, '' as mq2, Dust As Dust,[time]
from pi_dust_sensor
)base
ORDER BY [TIME] DESC

Related

Query two tables ORDER BY date

So I have two tables that displays values like a Facebook look-a-like feed. They both have a datetime column named date, but I want them to order them together by date DESC.
I think join is the correct way(?), but not quite sure. Can someone help me out?
Currently I have them in two different queries:
$status1 = "1";
$stmt1 = $link->prepare('
SELECT id
, ident_1
, ident_2
, date
, ident_1_points
, ident_2_points
FROM duel
WHERE active=?
ORDER
BY date
');
$stmt1-> bind_param('s', $status1);
and
$status2 = "OK";
$stmt2 = $link->prepare('SELECT id, ident, pp, date FROM sales WHERE status=? AND team IN (2, 3) ORDER BY date DESC LIMIT 20');
$stmt2->bind_param('s', $status2);
How should I do this?
If you want one continuous list containing data from both tables, and the whole thing ordered by date overall, then you might need a UNION query in a subquery, and then order the outer query, something like this:
SELECT *
FROM
(
SELECT id, ident_1, ident_2, date, ident_1_points, ident_2_points
FROM duel
WHERE active=?
UNION ALL
SELECT id, ident, pp, date, NULL, NULL
FROM sales
WHERE status=?
AND team IN (2, 3)
LIMIT 20
) list
ORDER BY date DESC
The requirement isn't 100% clear to be honest from your description (sample data and expected results always helps when asking SQL questions), but I think this is pretty close to what you need.
JOIN doesn't seem appropriate, unless you want a result set where items from each table are linked to each other by some common field, and you combine them such that you get all the columns side by side, showing the data from one table next to the data which matches from the other table.
If you're unsure, I suggest looking at tutorials / examples / documentation which show what JOIN does, and what UNION does.

SQL server : stored procedure

I have a table with 6 columns (id, deviceID, athleteName, fieldName, valueTx, dateTime).
So far when I call my function getSensors it display all rows.
However I want to display at each update of the table only the latest row, depending on dateTime and deviceID columns.
I've never used store procedure, so I'm wondering if is it the best to do ? If not what do you suggest me to do ?
Many thanks in advance!!!
You don't need a stored procedure for this. A simple query:
select t.*
from t
where t.datetime = (select max(t2.datetime) from t t2 where t2.deviceID = t.deviceID);
If you are given a deviceID, you can get the most recent record as:
select t.*
from t
where t.deviceID = v_deviceID
order by t.datetime desc
limit 1;

Pagination query mysql+php take 20-40 seconds

Hi I have pagination in angular js in my app, I send the data to my big query that includes the filters that the user set
UPDATE
SQL_CALC_FOUND_ROWS this is my problem. How do I count the rows of specific filters . It is took me 2 second for 100,000 rows I need the number for the pagination as a total number
UPDATE:
I have the following inner query that I missed here :
(select count(*) from students as inner_st where st.name = inner_st.name) as names,
when I remove above inner query is much faster
rows: 50,000
Users table : 4 rows
Classes table : 4 rows
indexes: only id as primary key
query time 20-40 seconds
tables: students.
columns : id, date ,class, name,image,status,user_id,active
table user
coloumn: id,full_name,is_admin
query
SELECT SQL_CALC_FOUND_ROWS st.id,
st.date,
st.image,
st.user_id,
st.status,
st,
ck.name AS class_name,
users.full_name,
(select count(*) from students AS inner_st where st.name = inner_st.name) AS names,
FROM students AS st
LEFT JOIN users ON st.user_id = users.user_id
LEFT JOIN classes AS ck ON st.class = ck.id
WHERE date BETWEEN '2018-01-17' AND DATE_ADD('2018-01-17', INTERVAL 1 DAY)
AND DATE_FORMAT(date,'%H:%i') >= '00:00'
AND DATE_FORMAT(date,'%H:%i') <= '23:59'
AND st.active=1
-- here I can concat filters from web like "and class= 1"
ORDER BY st.date DESC
LIMIT 0, 10
How can I make it faster? when I delete the order by and SQL_CALC_FOUND_ROWS it faster but i need them
I heard about indexes but only primary key is index
Few comments before recommending a different approach to this query:
Did you consider removing SQL_CALC_FOUND_ROWS and instead running two queries (one that counts and one that selects the data)? In some cases it might be quicker than joining them both to one query.
What is the goal of these conditions? What are you trying to achieve? Can we remove them (as it seems they might always return true?) - AND DATE_FORMAT(st.date, '%H:%i') >= '00:00' AND DATE_FORMAT(st.date, '%H:%i') <= '23:59'
You only need 10 results, but the database will have to run the "names" subquery for each of the results before the LIMIT (which might be a lot?). Therefore, I would recommend to extract the subquery from the SELECT clause to a temporary table, index it and join to it (see fixed query below).
To optimize the query, let's begin with adding these indexes:
ALTER TABLE `classes` ADD INDEX `classes_index_1` (`id`, `name`);
ALTER TABLE `students` ADD INDEX `students_index_1` (`active`, `user_id`, `class`, `name`, `date`);
ALTER TABLE `users` ADD INDEX `users_index_1` (`user_id`, `full_name`);
Now create the temporary table (originally this was a subquery in the SELECT clause) and index it:
-- Transformed subquery to a temp table to improve performance
CREATE TEMPORARY TABLE IF NOT EXISTS temp1 AS SELECT
count(*) AS names,
name
FROM
students AS inner_st
WHERE
1 = 1
GROUP BY
name
ORDER BY
NULL
-- This index is required for optimal temp tables performance
ALTER TABLE
`temp1`
ADD
INDEX `temp1_index_1` (`name`, `names`);
And the modified query:
SELECT
SQL_CALC_FOUND_ROWS st.id,
st.date,
st.image,
st.user_id,
st.status,
ck.name AS class_name,
users.full_name,
temp1.names
FROM
students AS st
LEFT JOIN
users
ON st.user_id = users.user_id
LEFT JOIN
classes AS ck
ON st.class = ck.id
LEFT JOIN
temp1
ON st.name = temp1.name
WHERE
st.date BETWEEN '2018-01-17' AND DATE_ADD('2018-01-17', INTERVAL 1 DAY)
AND st.active = 1
ORDER BY
st.date DESC LIMIT 0,
10
Give this a try first:
INDEX(active, date)
Is user_id the PK for users? Is class_id the PK for classes? If not, then they should be INDEXed.
Why are you testing the times separate?
Fix the test so it is obvious which table each column is in.
Do you really need LEFT JOIN? Or would JOIN suffice? In the latter case, there are more optimization options.
Give some realistic examples of other SELECTs; different index(es) may be needed.
Is the "first" page slow? Or only later pages? See this for pagination optimization -- by not using OFFSET.

Mysql - How to get a row number after Order by?

Let's say I have a table with the following columns:
p_id
userid
points
Let's say these columns have over 5000 records. So we actually have users with points. Each user has an unique row for their point record. Imagine that every user can get points on the website by clicking somewhere. When they click I update the database with the points they get.
So we have a table with over 5000 records of people who have points, right? Now I would like to order them by their points (descending), so the user with the most point will be at the top of the page if I run a MySQL query.
I could do that by simply running a query like this:
SELECT `p_id` FROM `point_table` ORDER BY `points` DESC
This query would give me all the records in a descending order by points.
Okay, here my problem comes, now (when it is ordered) I would like to display each user which place are they actually. So I'd like to give each user something like this: "You are 623 of 5374 users". The problem is that I cannot specify that "623" number.
I would like to run a query which is order the table by points it should "search" or count the row number, where their records are and than return that value to me.
Can anyone help me how to build a query for this? It would be a really big help. Thank you.
This answer should work for you:
SET #rank=0;
SELECT #rank:=#rank+1 AS rank, p_id FROM point_table ORDER BY points DESC;
Update: You might also want to consider to calculate the rank when updating the points and saving it to an additional column in the same table. That way you can also select a single user and know his rank. It depends on your use cases what makes more sense and performs better.
Update: The final solution we worked out in the comments looked like this:
SELECT
rank, p_id
FROM
(SELECT
#rank:=#rank+1 AS rank, p_id, userid
FROM
point_table, (SELECT #rank := 0) r
ORDER BY points DESC
) t
WHERE userid = intval($sessionuserid);
Row number after order by
SELECT ( #rank:=#rank + 1) AS rank, m.* from
(
SELECT a.p_id, a.userid
FROM (SELECT #rank := 0) r, point_table a
ORDER BY a.points DESC
) m
For some reason the accepted answer doesn't work for me properly - it completely ignores "ORDER BY" statement, sorting by id (primary key)
What I did instead is:
SET #rn=0;
CREATE TEMPORARY TABLE tmp SELECT * FROM point_table ORDER BY points DESC;
SELECT #rn:=#rn+1 AS rank, tmp.* FROM tmp;
Add a new column for position to the table. Run a cron job regularly which gets all the table rows ordered by points and then update the table with the positions in a while loop.

SQL order by, group by, having

I'm using a database to store results of an election with the columns id, candidate, post_time and result. Results are put in the database during 'counting the votes'. When a new update is available, a new entry will be inserted.
From this database, I would like to create a table with the most recent results (MAX post_time) per candidate (GROUP BY candidate), ordered by result (ORDER BY result).
How can I translate this to a working SQL-statement?
(I've tried mysql order and groupby without success)
I've tried:
SELECT *, MAX(time_post)
FROM [database]
GROUP BY candidate
HAVING MAX(time_post) = time_post
ORDER BY result
Assuming that you don't have multiple results per candidate at same time, next should work:
select r.candiate, r.result
from results r
inner join (
select candidate, max(post_time) as ptime
from results
group by candidate
) r2 on r2.candiate=r.candidate and r2.ptime=r.post_time
order by r.result
Note that MAX will not select the record with the maximum time, but it will select the maximum value from any record. So
SELECT MAX(a), MAX(b) FROM example
where exmple contains the two records a=1, b=2 and a=4, b=0, will result in a=4, b=2, which wasn't in the data. You should probably create a view with the latest votes only from each candidate, then query that. For performance, it may be sensible to use a materialized view.
Is the post_time likely to be the same for all the most recent results? Also does each candidate only appear once per post_time?
This could be achieved by just using a SELECT statement. Is there a reason you need the results in a new table?
If each candidate only appears once per post_time:
SELECT candidate, result
FROM table
WHERE post_time = (SELECT MAX(post_time) FROM table)
If you want to count how many times a candidate appears in the table for the last post_time:
SELECT candidate, count(result) as ResultCount
FROM table
WHERE post_time = (SELECT MAX(post_time) FROM table)
GROUP BY candidate
By what i see from ur attempts i'd think you should use this
SELECT MAX(post_time) FROM `table` GROUP BY candidate ORDER BY result
but the MAX statment only return a single value therefore i dont see why ORDER BY would be needed.
if you want multiple results try looking up the TOP statment
One way (tied results shown):
SELECT t.*
FROM tableX AS t
JOIN
( SELECT candidate
, MAX(time_post) AS time_post
FROM tableX
GROUP BY candidate
) AS m
ON (m.candidate, m.time_post) = (t.candidate, t.time_post)
ORDER BY t.result
and another one (no ties, only one row per candidate shown):
SELECT t.*
FROM
( SELECT DICTINCT candidate
FROM tableX
) AS d
JOIN
tableX AS t
ON t.PK = --- the Primary Key of the table, here
( SELECT ti.PK --- and here
FROM tableX AS ti
WHERE ti.candidate = d.candidate
ORDER ti.time_post DESC
LIMIT 1
)
ORDER BY t.result

Categories