I have table A
| id | Name |
_________________________
| 1 | ABC |
_________________________
| 2 | BCD |
_________________________
Table B
| id | a_id | Status | timestamp |
__________________________________________________________
| 1 | 1 | 1 | timestamp |
__________________________________________________________
| 2 | 1 | 2 | timestamp |
__________________________________________________________
| 3 | 1 | 3 | timestamp |
__________________________________________________________
| 4 | 2 | 1 | timestamp |
__________________________________________________________
In above example I only want to pick
| name | a_id | Status | timestamp |
__________________________________________________________
| BCD | 2 | 1 | timestamp |
So with any record that has ONLY and ONLY latest STATUS as 1, I want to pick that record.. If the LATEST STATUS is 2 or 3, I don't want ot pick them...
If possible I don't want to use sub-query because I am using Codeigniter which doesn't really like subqueries.
Please help
So that will be:
SELECT
A.name,
B.*
FROM
(SELECT
a_id,
MAX(`timestamp`) AS max_timestamp
FROM B
GROUP BY a_id) AS latest
LEFT JOIN B
ON
B.a_id=latest.a_id
AND
B.`timestamp`=latest.max_timestamp
LEFT JOIN A
ON B.a_id=A.id
WHERE
B.status=1
As for subquery - I doubt you can retrieve desired information without that in single query. That is because you need to use row set, which is a result of grouping by one column, in reference to another column. And so you need to group that first, and then apply JOIN to result row set.
Thanks to #Strawberry for pointing to this article, I figured a way to do it for this example.
select a.name
,b1.a_id
,b1.status
,b1.`timestamp` AS b1Time
FROM TableA a
JOIN TableB b1 ON b1.a_id = a.id
LEFT JOIN TableB b2 ON b2.a_id = b1.a_id AND b1.`timestamp` < b2.`timestamp`
WHERE b2.`timestamp` IS NULL
AND b1.status = 1
See this Fiddle.
Related
I have two tables 'property' and 'bookings'. I want to find out property for city, checkin and checkout when bookings table is empty.
when bookings table empty, for city = 'bali' and checkin = '2020-07-20' and checkout = '2020-07-30', expected output is property id 1 and 2.
when bookings table not empty, for city = 'bali' and checkin = '2020-07-20' and checkout = '2020-07-30', expected output is property id 1.
Query should work both when bookings table is empty / not empty.
property:
+----+---------+------+
| id | city | type |
+----+---------+------+
| 1 | bali | 1 |
| 2 | bali | 1 |
| 3 | bangkok | 1 |
+----+---------+------+
bookings:
+----+-------------+------------+------------+
| id | property_id | checkin | checkout |
+----+-------------+------------+------------+
| 1 | 1 | 2020-07-18 | 2020-07-19 |
| 2 | 2 | 2020-07-20 | 2020-07-25 |
| 3 | 3 | 2020-07-20 | 2020-07-30 |
+----+-------------+------------+------------+
What will be best approach subquery or left join? I tried both approach but unable to get the expected result.
As #Strawberry suggested, I am able to make it work:
SELECT property.id FROM property
LEFT JOIN bookings
ON bookings.checkin < '2020-08-30'
AND bookings.checkout > '2020-08-20'
AND bookings.property_id = property.id
WHERE city = 'bali'
AND bookings.id IS NULL
Try this:
SELECT *
FROM property
LEFT JOIN bookings ON bookings.property_id = property.id
WHERE city='bali'
AND IF(bookings.id IS NULL, 1, bookings.checkin = '2020-07-18')
AND IF(bookings.id IS NULL, 1, bookings.checkout = '2020-07-19')
If there doesn't exists any record in the bookings table then simply apply the filter on the city only otherwise filter will be applied ont eh checkin and checkout as well.
I have 2 tables:
A table: (where every code is unique, occurs only one time)
id | code | datetime |
1 | 2574857458745 | 2017-05-20 20:15:30 | - update this code datetime
2 | 6554995949445 | 2017-07-13 11:17:40 |
3 | 8214687655556 | 2017-04-27 21:26:55 |
4 | 3354551848451 | 0000-00-00 00:00:00 |
B table: (where codes occurs many times)
id | code | datetime |
26 | 2574857458745 | 2018-07-14 16:24:20 | - occurs here 2 times
47 | 6554995949445 | 2018-09-06 17:35:44 |
64 | 8214687655556 | 2018-03-09 22:06:12 |
57 | 2574857458745 | 2018-11-12 23:57:35 | - update only with the latest datetime
So the table A first row to be:
id | code | datetime |
1 | 2574857458745 | 2018-11-12 23:57:35 |
and so on, search every code and if exist in the B table then update with the latest datetime
It is possible to achieve this with mysql update with join? If yes then how? Or other ideas?
you can use update with join:
UPDATE tablea a
JOIN (SELECT code, MAX(datetime) as maxdt FROM tableb GROUP BY code) b
ON a.code = b.code
SET a.datetime = b.maxdt;
Note: If tableA's datetime is higher than tableB's latest datetime, this will update anyway
Use subquery and join:
update tableA a
inner join
(select code, max(datetime) as d
from tableB
group by code)b on a.code=b.code
set a.datetime = b.d
I am working on a product sample inventory system where I track the movement of the products. The status of each product can have a status of "IN" or "OUT" or "REMOVED". Each row of the table represents a new entry, where ID, status and date are unique. Each product also has a serial number.
I need help with a SQL query that will return all products that are currently "OUT". If I simply just select SELECT * FROM table WHERE status = "IN", it will return all products that ever had status IN.
Every time product comes in and out, I duplicate the last row of that specific product and change the status and update the date and it will get a new ID automatically.
Here is the table that I have:
id | serial_number | product | color | date | status
------------------------------------------------------------
1 | K0T4N | XYZ | silver | 2016-07-01 | IN
2 | X56Z7 | ABC | silver | 2016-07-01 | IN
3 | 96T4F | PQR | silver | 2016-07-01 | IN
4 | K0T4N | XYZ | silver | 2016-07-02 | OUT
5 | 96T4F | PQR | silver | 2016-07-03 | OUT
6 | F0P22 | DEF | silver | 2016-07-04 | OUT
7 | X56Z7 | ABC | silver | 2016-07-05 | OUT
8 | F0P22 | DEF | silver | 2016-07-06 | IN
9 | K0T4N | XYZ | silver | 2016-07-07 | IN
10 | X56Z7 | ABC | silver | 2016-07-08 | IN
11 | X56Z7 | ABC | silver | 2016-07-09 | REMOVED
12 | K0T4N | XYZ | silver | 2016-07-10 | OUT
13 | 96T4F | PQR | silver | 2016-07-11 | IN
14 | F0P22 | DEF | silver | 2016-07-12 | OUT
This query will give you all the latest records for each serial_number
SELECT a.* FROM your_table a
LEFT JOIN your_table b ON a.serial_number = b.serial_number AND a.id < b.id
WHERE b.serial_number IS NULL
Below query will give your expected result
SELECT a.* FROM your_table a
LEFT JOIN your_table b ON a.serial_number = b.serial_number AND a.id < b.id
WHERE b.serial_number IS NULL AND a.status LIKE 'OUT'
There are two good ways to do this. Which way is best,in terms of performance, can depend on various factors, so try both.
SELECT
t1.*
FROM table t
LEFT OUTER JOIN table later_t
ON later_t.serial_number = t.serial_number
AND later_t.date > t.date
WHERE later_t.id IS NULL
AND t.status = "OUT"
Which column you check from later_t for IS NULL does not matter, so long as that column is declared NOT NULL in the table definition.
The other logically equivalent method is:
SELECT
t.*
FROM table t
INNER JOIN (
SELECT
serial_number,
MAX(date) AS date
FROM table
GROUP BY serial_number
) latest_t
ON later_t.serial_number = t.serial_number
AND latest_t.date = t.date
WHERE t.status = "OUT"
For each of these queries, I strongly suggest the following index:
ALTER TABLE table
ADD INDEX `LatestSerialStatus` (serial_number,date)
I use this type of query a lot in my own work, and have the above index as the primary key on tables. Query performance is extremely fast in such cases, for these type of queries.
See also the documentation on this query type.
I have a basic table:
+-----+--------+------+------+
| id, | name, | cat, | time |
+-----+--------+------+------+
| 1 | jamie | 1 | 100 |
| 2 | jamie | 2 | 100 |
| 3 | jamie | 1 | 50 |
| 4 | jamie | 2 | 150 |
| 5 | bob | 1 | 100 |
| 6 | tim | 1 | 300 |
| 7 | alice | 4 | 100 |
+-----+--------+------+------+
I tried using the "Left Joining with self, tweaking join conditions and filters" part of this answer: SQL Select only rows with Max Value on a Column but some reason when there are records with a value of 0 it breaks, and it also doesn't return every unique answer for some reason.
When doing the query on this table I'd like to receive the following values:
+-----+--------+------+------+
| id, | name, | cat, | time |
+-----+--------+------+------+
| 1 | jamie | 1 | 100 |
| 4 | jamie | 2 | 150 |
| 5 | bob | 1 | 100 |
| 6 | tim | 1 | 300 |
| 7 | alice | 4 | 100 |
+-----+--------+------+------+
Because they are unique on name and cat and have the highest time value.
The query I adapted from the answer above is:
SELECT a.name, a.cat, a.id, a.time
FROM data A
INNER JOIN (
SELECT name, cat, id, MAX(time) as time
FROM data
WHERE extra_column = 1
GROUP BY name, cat
) b ON a.id = b.id AND a.time = b.time
The issue here is that ID is unique per row you can't get the unique value when getting the max; you have to join on the grouped values instead.
SELECT a.name, a.cat, a.id, a.time
FROM data A
INNER JOIN (
SELECT name, cat, MAX(time) as time
FROM data
WHERE extra_column = 1
GROUP BY name, cat
) b ON A.Cat = B.cat and A.Name = B.Name AND a.time = b.time
Think about it... So what ID is mySQL returning form the Inline view? It could be 1 or 3 and 2 or 4 for jamie. Hows does the engine know to pick the one with the max ID? it is "free to choose any value from each group, so unless they are the same, the values chosen are indeterminate. " it could pick the wrong one resulting in incorrect results. So you can't use it to join on.
https://dev.mysql.com/doc/refman/5.0/en/group-by-handling.html
If you want to use a self join, you could use this query:
SELECT
d1.*
FROM
date d1 LEFT JOIN date d2
ON d1.name=d2.name
AND d1.cat=d2.cat
AND d1.time<d2.time
WHERE
d2.time IS NULL
It is very simple
SELECT MAX(TIME),name,cat FROM table name group by cat
I want to copy the latest information from table 1 into table 2.
For the ID i used
insert into Table2(ID) (Select ID FROM Table2). That was not a problem.
CL1 contains the oldest data.
CL3 contains the newest data. So CL2 is between.
Insert into was probably the easiest way to copy the ID from Table1 to Table2
my problem with MySQL is the following.
Table 1
ID | CL1 | CL2 | CL3
A | 1 | 2 | 3
B | 1 | 2 | NULL
C | 1 | 2 | 3
D | 1 | NULL| NULL
E | 1 | 2 | 3
Table 2
ID | CLX
A |
B |
C |
D |
E |
Result should be:
Table 2
ID | CLX
A | 3
B | 2
C | 3
D | 1
E | 3
use GREATEST().
Assuming that CL1 is not nullable, and CL3 cannot have value unless CL2 is filled up.
INSERT INTO table2(ID, CLX)
SELECT ID, GREATEST(CL1, COALESCE(CL2, CL1), COALESCE(CL3, CL1))
FROM table1
SQLFiddle Demo
Thank you,
Coalesce was the function I need for my queries.
`Select ID, COALESCE(CL3,CL2,CL1) as latest from table1`