Select corresponding value from second table (Mysql) - mysql

Struggling with some sql, would appreciate some guidance.
Have two tables logs and sense
logs –
assetid ts nodeid status
1 2017-10-26 14:00:10 73 240
2 2017-10-26 14:00:06 21 160
3 2017-10-26 14:00:04 18 230
4 2017-10-26 14:00:02 19 400
5 2017-10-26 14:00:00 21 190
1 2017-10-26 13:20:08 18 20
2 2017-10-26 13:06:10 20 160
3 2017-10-26 13:03:04 17 230
sense –
status value
20 5
160 37
190 39
230 56
240 58
400 90
Trying to find the correct syntax to only show the latest record (in datetime) of each assetid and then show the corresponding value from the sense table (based on the matching status in both tables) to produce –
assetid ts nodeid status value
1 2017-10-26 14:00:10 73 240 58
2 2017-10-26 14:00:06 21 160 37
3 2017-10-26 14:00:04 18 230 56
4 2017-10-26 14:00:02 19 400 90
5 2017-10-26 14:00:00 21 190 39
Have tried –
Select assetid, ts, nodeid, status, value
From
logs
Join sense X on X.status = logs.status
Group by assetid
Order by ts DESC
But this only outputs 1 row (instead of 5)
assetid ts nodeid status value
1 2017-10-26 14:00:10 73 240 58
Removing
Join sense X on X.status = logs.status
of course outputs all records but that is not required.
Thoughts appreciated.
Regards
Active

Actually your query is returning 5 rows, 1 for each id. But it won't return rows with latest ts for each id. You can verify this by clicking on the link for demo. You can compare results of both queries.
To achieve this task,following query will help you:
Select l.assetid, l.ts, logs.nodeid, X.status, X.value
From
logs
inner Join sense X on X.status = logs.status
inner join (select assetid, max(ts) as ts from logs group by assetid) l
on l.assetid = logs.assetid and logs.ts = l.ts
Group by l.assetid
Order by l.ts DESC;
Click here for Demo
EDIT:
If dataype of ts is string then replace max(ts) in above query with:
max(str_to_date(ts,'%d%m%y'))
Feel free to ask any doubts.
Hope it helps!

Try this
Select a1.assetid, MAX(a1.ts), a1.nodeid, a1.status, X.value
From
logs a1
inner join sense X on X.status = a1.status
Group by assetid, a1.nodeid, a1.status, X.value
Order by ts DESC

Use GROUP BY to find minimum for each assetid and then JOIN with the logs and sense
Select *
FROM logs l
JOIN sense s ON s.status = l.status
JOIN
(
Select assetid, max(ts) maxts
From logs
Group by assetid
) t ON t.assetid = l.assetid and l.ts = t.maxts
demo

On MY SQL 8.0.2
WITH CTE as
(
Select A.assetid, A.ts, A.nodeid, A.status, B.value, row_number() over(PARTITION BY A.assetid ORDER BY A.ts DESC) AS rn
from logs as A
inner join sense B ON A.status=B.status
)
SELECT *
FROM CTE
WHERE rn='1';

Related

USING OF SUBQUERY

below is database and table details.
database name - mis_v1
table 1 name - trips
table 2 name - client
i tried below queries
Query 1
select cl.client_name CLIENT
, count(t.trip_type) TRIPS
, count(distinct t.vehicle_reg_no) VEHICLES
from mis_v1.trips t
JOIN mis_v1.client cl
ON cl.id = t.client_id
group
by cl.client_name;
Query 1 result
CLIENT TRIPS VEHICLES
anz-ABlr 118 16
citrix-CBlr 159 15
dxc-DBlr 26 5
Eps-Blr 116 24
goc-GocHyd 191 10
Unisys-BLR 192 55
Wipro-Ncr 86 33
Wipro-Pnq 10 5
Query 2
select cl.client_name CLIENT
, count(t.trip_delay_reason) LATE_TRIPS
FROM mis_v1.trips t
JOIN mis_v1.client cl
ON cl.id = t.client_id
where t.trip_delay_reason = "DRIVER"
group
by cl.client_name;
Query 2 result
CLIENT LATE_TRIPS
anz-ABlr 53
citrix-CBlr 25
dxc-DBlr 1
Wipro-Ncr 1
goc-GocHyd 17
I need result as below
CLIENT TRIPS VEHICLES LATE_TRIPS
anz-ABlr 118 16 53
citrix-CBlr 159 15 25
dxc-DBlr 26 5 1
Eps-Blr 116 24 -
goc-GocHyd 191 10 17
Unisys-BLR 192 55 -
Wipro-Ncr 86 33 1
Wipro-Pnq 10 5 -
Kindly give me solution.Thanks in advance
If I understood you correctly, you need something like this:
select cl.client_name CLIENT
, count(t.trip_type) TRIPS
, count(distinct t.vehicle_reg_no) VEHICLES
, coalesce(cast(count(case when t.trip_delay_reason = "DRIVER" then 1 else null end) as char), '-') LATE_TRIPS
from mis_v1.trips t
JOIN mis_v1.client cl
ON cl.id = t.client_id
group
by cl.client_name;
So, please read more about COUNT aggreagate function and probably CASE operator

MySQL-how to make query for selecting opening recd issued closingbalance rate from two different table one is purchase and another is issued [duplicate]

This question already has answers here:
What's the most efficient way to select the last n rows in a table without changing the table's structure?
(8 answers)
Closed 4 years ago.
I want to make a query that retrieve data from two table i.e one is purchase and another is issue.
both tables have same fields i.e icode,qty,rate,purdate and issuedate.
query of purchase is:-SELECT Dry_Purchase.Icode, Sum(Dry_Purchase.Qty) AS SumOfQty, Dry_Purchase.Rate
FROM Dry_Purchase
WHERE (((Dry_Purchase.PurDate) Between DateSerial(Year(Date()),(Month(Date())-1),21) And DateSerial(Year(Date()),Month(Date()),20)))
GROUP BY Dry_Purchase.Icode, Dry_Purchase.Rate;
output of purchase query is:
Icode SumOfQty Rate
11 10 13.5
11 39.5 14
19 75 79.75
19 22 80
21 54 87.45
23 15 218
24 10.5 650
8 79 33.25
8 13 34
query of issue is :- SELECT Dry_Expense.Icode, Sum(Dry_Expense.Qty) AS SumOfQty, Dry_Expense.Rate
FROM Dry_Expense
WHERE (((Dry_Expense.ExpDate) Between DateSerial(Year(Date()),(Month(Date())-1),21) And DateSerial(Year(Date()),Month(Date()),20)))
GROUP BY Dry_Expense.Icode, Dry_Expense.Rate;
output of this query is
Icode SumOfQty Rate
11 11.55 13
11 8.55 13.5
11 10.8 14
19 2.35 80
21 54 87.45
8 15.9 33.25
after combining above both query the output should like this
rptdate icode opening recd issued closingbal rate
19/09/18 11 0 10 8.550 1.450 13.50
19/09/18 11 0 39.5 10.800 28.700 14.00
19/09/18 19 0 75 0.000 75 79.75
19/09/18 19 0 22 2.350 72.650 80.00
19/09/18 21 0 54 54 0 87.45
19/09/18 23 0 15 0 15 218.00
19/09/18 24 0 10.5 0 10.500 650.00
19/09/18 8 0 79.0 15.900 63.100 33.25
19/09/18 8 0 13.0 0 13.000 34.00
19/09/18 8 11.550 0 11.550 0 13.00
please help me how to make query for this output
i am trying this query
SELECT A.icode,A.qty,A.rate,A.recd as recd,B.Issued as Issue
FROM (SELECT icode,rate,purdate,SUM(Abs(qty)) AS recd
FROM Dry_Purchase GROUP BY icde,rate ) A,
(SELECT icode,rate,expdate,(SUM(Abs(qty)) AS Issue
FROM Dry_Expense GROUP BY icode,rate) B
WHERE A.icode=B.icode AND A.rate=B.rate AND
(A.purdate Between DateSerial((Year(Date()),(Month(Date())-1),21)) And DateSerial(Year(Date()),Month(Date()),20))
AND B.expdate Between DateSerial((Year(Date()),(Month(Date())-1),21) And DateSerial(Year(Date()),Month(Date()),20));
please help me
Use a sub-select to locate the minimum date, then join to the to get the row matching that date.
SELECT
a.`Purdate` AS a.`Date1`, a.`Qty`, a.`Rate`
FROM `TableName` a
JOIN (SELECT MIN(`PurDate`) as `minDate`
FROM `TableName`
WHERE `Icode` = '1') b
ON b.`minDate` = a.`PurDate`
WHERE a.`Icode` = '1'
Since you don't need grouping you can just order by the date column and get the first two rows.
SELECT PurDate, Qty, Rate FROM TableName WHERE Icode = '1' ORDER BY PurDate LIMIT 2
use corelated sub query and union
select A.* from
(
select * from tablename t1 #1st min date will return
where t1.purdate in
(select min(purdate) from
tablename t2 where t2.icode=t1.icode
)
union
select t1.* from tablename t1 inner join
(SELECT
Icode
, Purdate
FROM (
SELECT
#row_num :=IF(#prev_value=Icode,#row_num+1,1) AS rn
, mp.Icode
, mp.Purdate
, #prev_value := Icode
FROM tablename mp
CROSS JOIN (SELECT #row_num :=1, #prev_value :='') vars
ORDER BY
mp.Icode
, mp.Purdate DESC
) d
WHERE rn = 2
) t2
on t1.Icode=t2.Icode and t1.Purdate=t2.Purdate
) as A where A.Icode in (......)

Join two tables using mysql

table:tab1
id date_time zoneid accountid slotid trequest bidder width height
_50832 2017-09-04 15:41:06 153 1654 153x468x60 10 aaa 468 60
_50832 2017-09-04 15:41:06 152 1654 152x468x60 10 bbb 468 60
table:tab2
id date_time zoneid accountid slotid bidder count
_50832 2017-09-04 15:41:06 152 1654 152x468x60 bbb 6
_50832 2017-09-04 15:41:06 152 1654 152x468x60 bbb 4
_50832 2017-09-04 15:41:06 153 1654 153x468x60 aaa 9
_50832 2017-09-04 15:41:06 153 1654 153x468x60 aaa 1
below is my query:
SELECT SUM(req.trequest) as REQ, SUM(win.count) as IMP
FROM tab1 as req
JOIN tab2 as win ON (req.id=win.id AND req.zoneid=win.zoneid)
GROUP BY req.zoneid
I get below result,
REQ IMP
20 10
20 10
IMP count is correct but I get wrong REQ count. My expected result is
REQ IMP
10 10
10 10
How to get my expected result?
Lets find the sum of trequest and count separately based on zoneid and id.Then use these two results ( t1 and t2 ) in the inner join.
Count mismatch problem shown in the question occur due to multiple rows satisfying the joining conditions.
In this solution we will only have one entry for each zoneid in both the results ( t1 and t2 ). So the problem is avoided.
Note: You can remove the id column from the GROUP BY clause if it doesn't make any difference.
SELECT t1.id, t1.zoneid, t1.REQ, t2.IMP FROM
(SELECT id,zoneid,SUM(trequest) as REQ
FROM tab1 GROUP BY zoneid,id ) t1
INNER JOIN
(SELECT id,zoneid SUM(win.count) as IMP
FROM tab2 GROUP BY zoneid,id ) t2
ON t1.id = t2.id
AND t1.zoneid = t2.zoneid
Let's try first sumwin.count and group records in sub-query, after it join tables. Try in following:
SELECT SUM(req.trequest) as REQ, SUM(win.count) as IMP
FROM tab1 as req
JOIN (
SELECT SUM(win.count) as IMP, win.zoneid, win.id
FROM tab2 as win
GROUP BY win.zoneid, win.id) AS win ON req.id=win.id AND req.zoneid=win.zoneid
GROUP BY req.zoneid
Instead of req.zoneid. You should try win.zoneid. What seems is that the rows in table 1 are counted multiple times as zoneid in table 2 comes twice. So win.zoneid would group it and avoid the repetition.
Updated: The solution posted by #mayur panchal is the correct one as you don't need to SUM the rows in first table as they belong to different zoneid. If you SUM them you will obviously get the 20 repeated twice.

Mysql best students in every class in a school

In MySql I need to select top student in every class in a school in termid=10 to get discount for next term enrollment .
Please notice that total is not in table(I put in below for clearing problem)
I have this workbook table for all students workbook:
id studentid classid exam1 exam2 total termid
1 2 11 20 40 60 10
2 1 22 40 20 60 10
3 4 11 40 20 60 10
4 5 33 10 60 70 10
5 7 22 10 40 50 10
6 8 11 10 30 40 10
7 9 33 20 45 65 10
8 11 11 null null null 10
9 12 54 null null null 02
10 13 58 null null null 02
1st challenge is : exam1 and exam2 are VARCHAR and total is not in table (as i explained).
2nd challenge is : as you can see in id=8 std #11 has not numbers
3rd challenge is : may be two students have top level so they must be in result.
I need result as :
id studentid classid exam1 exam2 total termid
1 2 11 20 40 60 10
3 4 11 40 20 60 10
4 5 33 10 60 70 10
2 1 22 40 20 60 10
i have this query but not work good as i mention.
SELECT DISTINCT id,studentid,classid,exam1,exam2,total,termid ,(CAST(exam1 AS DECIMAL(9,2))+CAST(exam2 AS DECIMAL(9,2))) FROM workbook WHERE ClassId = '10';
You can get the total for the students by just adding the values (MySQL will convert the values to numbers). The following gets the max total for each class:
select w.classid, max(coalesce(w.exam1, 0) + coalesce(w.exam2, 0)) as maxtotal
from workbook w
group by w.classid;
You can then join this back to the original data to get information about the best students:
select w.*, coalesce(w.exam1, 0) + coalesce(w.exam2, 0) as total
from workbook w join
(select w.classid, max(coalesce(w.exam1, 0) + coalesce(w.exam2, 0)) as maxtotal
from workbook w
group by w.classid
) ww
on w.classid = ww.classid and (coalesce(w.exam1, 0) + coalesce(w.exam2, 0)) = ww.maxtotal;
Another approach is to join the table with itself. You find out the max for each class and then join all students of this class which match the class max:
max for each class (included in the final statement already):
SELECT classid, MAX(CAST(exam1 AS UNSIGNED) + CAST(exam2 AS UNSIGNED)) as 'maxtotal'
FROM students
WHERE NOT ISNULL(exam1)
AND NOT ISNULL(exam2)
GROUP BY classid
The complete statement:
SELECT s2.*, s1.maxtotal
FROM (SELECT classid, MAX(CAST(exam1 AS UNSIGNED) + CAST(exam2 AS UNSIGNED)) as 'maxtotal'
FROM students
WHERE NOT ISNULL(exam1)
AND NOT ISNULL(exam2)
GROUP BY classid) s1
JOIN students s2 ON s1.classid = s2.classid
WHERE s1.maxtotal = (CAST(s2.exam1 AS UNSIGNED) + CAST(s2.exam2 AS UNSIGNED));
SQL Fiddle: http://sqlfiddle.com/#!2/9f117/1
Use a simple Group by Statement:
SELECT
studentid,
classid,
max(coalesce(exam1,0)) as max_exam_1,
max(coalesce(exam2,0)) as max_exam_2,
sum(coalesce(exam1,0) + coalesce(exam2,0)) as sum_exam_total,
termid
FROM
workbook
WHERE
termid=10
GROUP BY
1,2
ORDER BY
5
Try something like this:
SELECT id,studentid,classid,exam1,exam2,(CAST(exam1 AS DECIMAL(9,2))+CAST(exam2 AS DECIMAL(9,2))) AS total,termid FROM `workbook` WHERE ((CAST(exam1 AS DECIMAL(9,2))+CAST(exam2 AS DECIMAL(9,2)))) > 50
Thanks all my friends
I think combine between 2 answer in above is best :
SELECT s2.*, s1.maxtotal
FROM (SELECT ClassId, MAX(
coalesce(exam1,0)+
coalesce(exam2,0)
) as 'maxtotal'
FROM workbook
WHERE
(
termid = '11'
)
GROUP BY ClassId) s1
JOIN workbook s2 ON s1.ClassId = s2.ClassId
WHERE s1.maxtotal = (
coalesce(exam1,0)+
coalesce(exam2,0)
) AND (s1.maxtotal >'75');
last line is good for s1.maxtotal=0 (some times student scores have not be entered and all equals 0 so all will shown as best students) or some times we need minimum score (to enroll in next term).
So thanks all

Write SQL query to find rows that are near min() value

I have about 5000 rows of data as follow:
id date temperature room
--------------------------------------
0 2013-07-15 76 A
1 2013-08-15 72 A
2 2013-09-15 74 B
3 2013-02-15 71 B
4 2013-03-15 72 B
5 2013-04-15 70 A
...
...
...
5000 2013-08-01 68 A
I can use the query from below to find min temperature in each room.
select room, min(temperature) from table_record group by room.
Now, I need to find all rows that are close to the the min temperature for each room.
I have try using "join" on the same table as below, but it cannot be run.
select t1.room, min(t1.temperature) from table_record t1
join on table_record t2 on
t2.room = t1.room and
t2.temperature * 0.95 (less_or_equal) min(t1.temperature)
group by room
You need to do this in two steps.
SELECT
*
FROM
(
SELECT room, MIN(temperature) AS min_temp FROM TABLE_RECORD GROUP BY room
)
AS ROOM_TEMP
INNER JOIN
TABLE_RECORD
ON TABLE_RECORD.room = ROOM_TEMP.room
AND TABLE_RECORD.temperature <= ROOM_TEMP.min_temp / 0.95
Provided that you have an index on (room, temperature) this should be pretty quick.
Also, note that I use x <= y / 0.95 rather than x * 0.95 <= y. This is to make the lookup faster (manipulate the search criteria once, rather than the searched field on every row).