Running query on results of a join statement - mysql

I'm trying to figure out how I can run a query on the results of a join statement I'm doing between two tables. Basically, I need to get all the entries from More_Info that match the ID of Source_Table between a certain time, and then calculate the difference between Number where PartID = certain things.
Consider the following two tables:
Source_Table
UniqueID | TimeIn |
1 | 051010|
2 | 051545|
3 | 055412|
More_Info
UniqueID | PartID | Number |
1 | 500 | 5 |
1 | 505 | 10 |
1 | 510 | 40 |
2 | 500 | 10 |
2 | 505 | 15 |
2 | 510 | 25 |
4 | 500 | 30 |
6 | 505 | 10 |
So I know I can run select * from Source_Table left join More_Info using(UniqueID) which will return:
UniqueID | PartID | Number |
1 | 500 | 5 |
1 | 505 | 10 |
1 | 510 | 40 |
2 | 500 | 10 |
2 | 505 | 15 |
2 | 510 | 25 |
From this, what I need is to get 'Number' where PartID = 500 or 505, and get the difference, where the results would be like:
UniqueID | Difference |
1 | 5 |
2 | 5 |
Having a big of difficulty wrapping my head around this, so any help would be appreciated.

You could use a couple of subquery eg:
select t1.UniqueId, t2.NUmber - t1.Number from (
select * from Source_Table left join More_Info using(UniqueID)
) t1
INNER JOIN (
select * from Source_Table left join More_Info using(UniqueID)
) t2 on t1.UniqueID = t2.UniqueID and t1.PartID = 500 and t2.partId = 505

Related

How to subtract a value from a sum of total in MySql LEFT JOIN Query

I have 2 tables.
SELECT * FROM purchases;
+------+---------+-----------+
|purid | total_q | dstatus |
+------+---------+-----------+
| 1 | 45 | DELIVERED |
| 2 | 50 | LOADING |
| 3 | 24 | DELIVERED |
| 4 | 15 | DELIVERED |
| 5 | 10 | DELIVERED |
+------+---------------------+
SELECT * FROM warehouse;
+------+-------+---------+
| wid | purid | total_q |
+------+-------+---------+
| 4 | 1 | 45 |
| 5 | 4 | 15 |
| 9 | 3 | 10 |
| 12 | 3 | 5 |
+------+-------+---------+
I want to get "delivered" purchases with its amounts which are not already included in warehouse table. Here is the demo where I stuck: DEMO
The query which I use is:
SELECT p.purid as purid, (p.total_q - IFNULL(w.total_q,0)) as ntq
FROM `purchases` as p
LEFT JOIN `warehouse` as w ON p.purid=w.purid
WHERE p.dstatus = "DELIVERED" AND (p.total_q - IFNULL(w.total_q,0)) > 0
My desired output:
+-------+------+
| purid | ntq |
+-------+------+
| 5 | 10 |
| 3 | 9 |
+------+-------+
The problem is I could not subtract "total_q (24) from purchases table" from "sum total_q(10+5) from warehouse table".
You can try to use subquery aggregate warehouse by purid before join otherwise you might get multiple rows.
Query #1
SELECT p.purid as purid,
p.total_q - IFNULL(w.total_q,0) as ntq
FROM `purchases` as p
LEFT JOIN (
SELECT purid,SUM(total_q) total_q
FROM warehouse
GROUP BY purid
) as w ON p.purid=w.purid
WHERE p.dstatus = "DELIVERED"
AND p.total_q - IFNULL(w.total_q,0) > 0;
purid
ntq
3
9
5
10
View on DB Fiddle

Having two MySQL tables, get the last result for each value of first table key

I have two tables:
TABLE_01
-------------------------------
| ID | Key1 | Key2 |
-------------------------------
| 1 | 504 | 101 |
| 2 | 504 | 102 |
| 3 | 505 | 101 |
| 4 | 505 | 103 |
| 5 | 508 | 101 |
| 6 | 510 | 104 |
| 7 | 509 | 101 |
-------------------------------
TABLE_02
----------------------------------------
| ID | T_01 | timestamp | data |
----------------------------------------
| 1 | 1 | ts_01 | ..abc.. |
| 2 | 1 | ts_02 | ..dfg.. |
| 3 | 2 | ts_03 | ..hij.. |
| 4 | 3 | ts_04 | ..klm.. |
| 5 | 1 | ts_05 | ..nop.. |
| 6 | 4 | ts_06 | ..qrs.. |
| 7 | 3 | ts_07 | ..tuv.. |
| 8 | 5 | ts_08 | ..wxy.. |
| 9 | 2 | ts_09 | ..z.... |
| 10 | 4 | ts_10 | ..abc.. |
----------------------------------------
On both table, ID is the Primary Incremental Key
In TABLE_01, the columns key1 + key2 are Unique Key (Can't be more than one Key1 Key2 couple)
In TABLE_02, the column T_01 makes reference on TABLE_01.ID
My goal is that given a key1 value, be able to get the last entry of TABLE_02 for each TABLE_01.ID with the correspondent timestamp on DESC ORDER.
For example, if I give 505, the output should be:
KEY1 | KEY2 | TIMESTAMP
---------------------------
505 | 103 | ts_10 ---> FROM TABLE_01.Id = 4
505 | 101 | ts_07 ---> FROM TABLE_01.Id = 3
As you can see, It only shows the last entry on the case of TABLE_01.ID = 4 (which is 505 | 103)
I have tried to do something like this:
SELECT `t1`.`Key1`, `t1`.`key2`, `t2`.`timestamp`
FROM `TABLE_02` AS t2
INNER JOIN `TABLE_01` AS t1
WHERE `t1`.`key1` = '505'
ORDER BY `t2`.`ID`
DESC LIMIT 100
The problem with this query is that since I am using t2.timestamp, I am receiving all the results instead of only ONE for EACH. Also, I'm not using correctly the TABLE_01.ID on TABLE_02.
If you just want the latest timestamp in the second table per combination of keys in the first table, you can join and aggregate:
select t1.key1, t1.key2, max(t2.timestamp) max_t2_timestamp
from table_01 t1
inner join table_02 t2 on t2.t_01 = t1.id
group by t1.key1, t1.key2
If you want the entire row of the second table, then I would recommend window functions:
select *
from (
select t1.key1, t1.key2, t2.*,
row_number() over(partition by t1.key1, t1.key2 order by t2.timestamp desc) rn
from table_01 t1
inner join table_02 t2 on t2.t_01 = t1.id
group by t1.key1, t1.key2
) t
where rn = 1

select all but the last record from grouped record in a table

I am trying to select all but the last row of grouped data from a table.
+----+--------+--------+ +----+--------+--------+
| id | userID | amount | | id | userID | amount |
+----+--------+--------+ +----+--------+--------+
| 1 | 20 | 400 | | 1 | 20 | 400 |
| 2 | 20 | 200 | | 2 | 20 | 200 |
| 3 | 21 | 100 | => | 3 | 21 | 100 |
| 4 | 11 | 500 | | 4 | 11 | 500 |
| 5 | 11 | 250 | | 6 | 21 | 50 |
| 6 | 21 | 50 |
| 7 | 20 | 100 |
| 8 | 21 | 200 |
+----+--------+--------+
I have tried to use the query
SELECT *
FROM table
WHERE userID != (SELECT MAX(userID) FROM table)
GROUP
BY userID
but it only fetches one unique row of data even though there are more left
You have not aggreagtion function so you don't need group by
SELECT *
FROM table
WHERE userID != (
SELECT MAX(userID) FROM table
)
This can happen with mysql version <5.7 for mysql version > 5.7 (by default setting) this use of group by raise an error
E.g....
SELECT a.*
FROM my_table a
LEFT
JOIN
( SELECT MAX(id) id
FROM my_table
GROUP
BY userid
) b
ON b.id = a.id
WHERE b.id IS NULL

solve mysql query

Today I have been asked a question by an interviewer that stated
we have three tables named as table A, B, and C.
Those tables are like this
A B C
------------------ -------------------------- ----------------------------
| ID | ProjectID | | ID | LocationID | aID | | ID | points | LocationID |
------------------ -------------------------- ----------------------------
| 1 | 15 | | 1 | 131 | 1 | | 1 | 123333 | 131 |
| 2 | 15 | | 2 | 132 | 1 | | 2 | 123223 | 132 |
| 3 | 15 | | 3 | 133 | 1 | | 3 | 522 | 211 |
| 4 | 12 | | 4 | 134 | 2 | | 4 | 25 | 136 |
------------------ | 5 | 136 | 2 | | 5 | 25 | 133 |
| 6 | 137 | 3 | | 6 | 25 | 134 |
| 7 | 138 | 1 | | 7 | 25 | 135 |
-------------------------- ----------------------------
now he told me to write a query that sums the points of those locations whose project is 15.
First i wrote the query to get ID's from table A like this
SELECT ID from A where projectID = 15
then i pass this result in table b query just like this
SELECT LocationID FROM B WHERE aID IN ( SELECT ID from A where projectID = 15 )
Then i calculate the sum of these locations just like this
SELECT SUM(points) from C where LocationID IN(SELECT LocationID FROM B WHERE aID IN ( SELECT ID from A where projectID = 15))
My Result is fine and query is correct. But he rejected my answer by saying that this nested IN Clause will slow down the whole process as when we have thousands of records.
Then he gave me another chance to review my answer but i couldn't figure it out.
Is there anyway to optimize this or is there some other way to do the same.
Any help? Thanks
Try this it may solve your problem.
Select SUM(C.points) FROM C JOIN B ON C.LocationID = B.LocationID JOIN A ON B.aID = A.ID where A.ProjectID = 15 GROUPBY A.ProjectID
Try with this....i hope it will work
select sum(c.points) as sum_points
from A a,B b,C c where
a.ID=b.aID and
b.LocationID=c.LocationID
and a.projectID=15

Select the name and value of a colmun using 2 different inner joined columns' values

I'm not sure if MySQL is capable of doing something like this. I'm no MySQL master by any means but to me this seems to be like it might be an example of a Pivot Table?
I've looked at other Pivot Table example and I find them confusing at best and I'm still not quite sure if it's relevant in my case.
Here's an example of the data and tables in question:
Foo Table:
RowID | col_one | col_two | col_three
------|---------|---------|-----------
1 | 2 | 34 | 64
2 | 6 | 53 | 23
3 | 8 | 22 | 45
Foo_Meta Table:
RowID | FooID | MetaName | MetaValue
------|-------|----------|-----------
1 | 1 | This | 302
2 | 1 | That | 466
3 | 1 | Other | 132
4 | 2 | This | 222
5 | 2 | That | 87
6 | 2 | Other | 400
7 | 3 | This | 732
8 | 3 | That | 55
9 | 3 | Other | 690
Here's an example of the select I'm using but isn't quite what I'm looking for:
Select:
SELECT
t.col_one,
t.col_two,
t.col_three,
m.MetaName,
m.MetaValue
FROM
foo t
INNER JOIN
foo_meta m ON t.RowID = m.FooID
Here's an example of the table I'm trying to Select:
Select:
RowID | col_one | col_two | col_three | This | That | Other
------|---------|---------|---------------------------------
1 | 2 | 34 | 64 | 302 | 466 | 132
2 | 6 | 53 | 23 | 222 | 87 | 400
3 | 8 | 22 | 45 | 732 | 55 | 690
Yes, you are pivoting foo_meta fields - at least some versions of Oracle do that, I'm quite certain MySQL doesn't.
Generally, to "fake" a pivot in MySQL, you do multiple joins. Something like:
SELECT
t.col_one,
t.col_two,
t.col_three,
mthis.this,
mthat.that,
mother.other
FROM
foo t
INNER JOIN
(select fooid, MetaValue as This from foo_meta where MetaName = 'This') mthis ON t.RowID = mthis.FooID
INNER JOIN
(select fooid, MetaValue as That from foo_meta where MetaName = 'That') mthat ON t.RowID = mthat.FooID
INNER JOIN
(select fooid, MetaValue as Other from foo_meta where MetaName = 'Other') mother ON t.RowID = mother.FooID
You might have to use left outers depending on how your data is populated.