MySQL left join and select - mysql

I have two tables, mytable1 and mytable2. I get results from mytable1 and left join with mytable2.
CREATE TABLE mytable1
( userid int,
type int,
datetime1 DATETIME );
CREATE TABLE mytable2
( userid int,
name varchar(20),
day2 DATE,
time2 TIME );
SELECT x.*, d.name, d.day2, d.time2
FROM ( SELECT * FROM mytable1 WHERE TYPE=1 ORDER BY userid ASC LIMIT 0,50) x
LEFT JOIN mytable2 d
ON x.userid = d.userid
But I need to filter the results, so I will get only results if "mytable2.day2 mytable2.time2" is bigger than 2 days ago. For example let datetime be "2014.03.27 21:00:00". I will get results if mytable2 record is newer than "2014.03.27 21:00:00"
You can check sql fiddle here inital: http://sqlfiddle.com/#!2/a5364/2
My tryout: http://sqlfiddle.com/#!2/a5364/5

Here is what the query will look like :-
select x.*, d.name, d.day2, d.time2
from ( SELECT * FROM mytable1 WHERE type=1 ORDER BY userid ASC LIMIT 0,50) x
left join mytable2 d
on x.userid = d.userid
where ( convert(CONCAT(d.day2,' ',d.time2),datetime) >= SUBDATE(curdate(),INTERVAL 2 DAY))
Use convert() to get the datetime and then use subdate() to find the date before 2 days.
Verify it on the SQL Fiddle you provided.

The question is: if there are no records at all in mytable2 that match a record in mytable1, do you still want to see the mytable1 record? If so, move the condition to the on clause:
select x.*, d.name, d.day2, d.time2
from (SELECT *
FROM mytable1
WHERE type = 1
ORDER BY userid ASC
LIMIT 0, 50
) x left join
mytable2 d
on x.userid = d.userid and
(d.day2 + d.time2) >= DATE_SUB(NOW(), INTERVAL 2 DAY);
Otherwise, you can change the join to an inner join:
select x.*, d.name, d.day2, d.time2
from (SELECT *
FROM mytable1
WHERE type = 1
ORDER BY userid ASC
LIMIT 0, 50
) x join
mytable2 d
on x.userid = d.userid
where (d.day2 + d.time2) >= DATE_SUB(NOW(), INTERVAL 2 DAY);

Related

Rewrite 2 select statements as one JOIN Statement

I've been strugling with a JOIN statement which I can't figure out.
I want to get the latest(newest) entry in two different tables and join the result in the output.
The 2 Select statements look like this and they work as expected but I can't seem to get the right result when I try to rewite them as a JOIN statement.
Please help, Thanks.
SELECT MaxNum
FROM table1
WHERE UserID = 4
ORDER BY Date DESC
LIMIT 1
SELECT MinNum
FROM table2
WHERE UserID = 4
ORDER BY Date DESC
LIMIT 1
I'm not sure that a join necessarily makes sense here. However, you can slightly modify what you currently have to be one query:
SELECT
(SELECT MaxNum FROM table1 WHERE UserID = 4 ORDER BY Date DESC LIMIT 1) AS MaxNum,
(SELECT MinNum FROM table2 WHERE UserID = 4 ORDER BY Date DESC LIMIT 1) AS MinNum
Since each of these queries only returns one row, one dirty trick you can use is to cross join the results:
SELECT MaxNum, MinNum
FROM (SELECT MaxNum
FROM table1
WHERE UserID = 4
ORDER BY Date DESC
LIMIT 1) t
CROSS JOIN (SELECT MinNum
FROM table2
WHERE UserID = 4
ORDER BY Date DESC
LIMIT 1) s
select TOP 1 table1.MaxNum, table2.MinNum
FROM table1 INNER JOIN table2
ON table1.UserID = table2.UserID
WHERE table1.UserID = 4
ORDER BY table1.Date DESC
If you want to display result as one row then use your queries as subqueries in FROM clause.
SELECT *
FROM
(SELECT MaxNum FROM table1 WHERE UserID = 4 ORDER BY `Date` DESC LIMIT 1) AS q1,
(SELECT MinNum FROM table2 WHERE UserID = 4 ORDER BY `Date` DESC LIMIT 1) AS q2;

MySQL Subquery SUM Limit

I'm trying to do an subquery with SUM() and LIMIT. This works fine with the following code:
SELECT id,
(
SELECT SUM(number)
FROM (
SELECT number
FROM t2
WHERE u_id = '1'
ORDER BY time ASC
LIMIT 30
) AS temp
) AS test
FROM t1
But I want to do it of course dynamically and with the current row ID.
I changed the Query to the following:
SELECT id,
(
SELECT SUM(number)
FROM (
SELECT number
FROM t2
WHERE u_id = p.id
ORDER BY time ASC
LIMIT 30
) AS temp
) AS test
FROM t1 p
This will give the following error:
Unknown column 'p.id' in 'where clause'
Any ideas how to make it working?
Unfortunately, MySQL limits the scope of table aliases. Oracle is another database that does this.
You can phrase your query as a complicated join:
select t1.id, sum(t2.number)
from t1 p join
t2
on p.id = t2.u_id
where 30 >= (select count(*)
from t2 t22
where t22.u_id = t2.u_id and
t22.time <= t2.time
)
group by t1.id;
Or you can do this with variables:
select p.id, sum(number)
from t1 p join
(select t2.*,
#rn := if(#u = t2.u_id, #rn + 1, if((#u := t2.u_id) is not null, 1, 0)) as rn
from t2
(select #u := 0, #rn := 0) vars
order by t2.u_d, time
) t2
on p.id = t2.u_id
where rn <= 30
group by p.id;
why not just change p.id to t1.id? I'm pretty sure it's because you are aliasing t1 in the first select, and it isn't defined in the subquery. Try an inner join instead.
SELECT id,
(
SELECT SUM(number)
FROM (
SELECT number
FROM t2
INNER JOIN t1 p
on u_id = p.id
ORDER BY time ASC
LIMIT 30
) AS temp
) AS test
FROM t1 p
Try this:
SELECT id, temp2.sum_number as test
FROM t1 p
INNER JOIN
(
SELECT SUM(number) as sum_number, temp.u_id
FROM (
SELECT number, u_id
FROM t2
WHERE u_id = p.id
ORDER BY time ASC
LIMIT 30
) AS temp
) AS temp2 ON temp2.u_id = p.id
I moved subqueries in the join part, so i can access to p.id in the subquery.

How do I select items in range of a SQL query?

My database is in MySQL.
Assume I have the following table:
id number
1 45
2 25
3 66
4 43
......
......
......
30 54
31 21
etc ... etc.
I want to have a query like so:
select * from myTable where number = 25
but I want to also include 2 more items, one above it and one below it (based on ID).
the result set of my query would turn up with the following result set: 1, 2, 3.
If I selected the number 66, then the result set would include 2, 3, 4. Etc, etc.
The idea would be to range the query by saying, hey, I want anything that has an ID equal to 1 minus this queries' id, and also one plus this queries' id.
I hope this makes sense.
Any help would be great.
Thanks!
P.S.
The point of this is to capture events in a log so that I can see what happened before and after a certain event happened
SELECT t.*
FROM
myTable AS t
JOIN
( SELECT id
FROM myTable
WHERE number = 25
) AS my
ON t.id BETWEEN my.id - 1 AND my.id + 1 ;
Notice that this will not show 3 rows if your ids have gaps.
Also, if the number you choose (25 in the example) appears more than once (but k times), the result will be 3*k rows.
If there are gaps, as expected, in the id column, you can use this:
SELECT *
FROM
( SELECT t.*
FROM
myTable AS t
JOIN
( SELECT MIN(id) AS id
FROM myTable
WHERE number = 25
) AS my
ON t.id <= my.id
ORDER BY t.id DESC
LIMIT 2
) AS a
UNION ALL
SELECT *
FROM
( SELECT t.*
FROM
myTable AS t
JOIN
( SELECT MIN(id) AS id
FROM myTable
WHERE number = 25
) AS my
ON t.id > my.id
ORDER BY t.id ASC
LIMIT 1
) AS b ;
If there are gaps in the id column and the number is not unique so the parameter (25) can appear more than once (but say k times), you can have a query that returns 3*k rows (almost all the times):
SELECT t.*
FROM
myTable AS t
JOIN
( SELECT id
FROM myTable
WHERE number = 25
) AS ti
ON t.id =
( SELECT tt.id
FROM myTable AS tt
WHERE tt.id < ti.id
ORDER BY tt.id DESC
LIMIT 1
)
OR t.id = ti.id
OR t.id =
( SELECT tt.id
FROM myTable AS tt
WHERE tt.id > ti.id
ORDER BY tt.id ASC
LIMIT 1
) ;
Not sure if it will work (I remember there are some limitations on ORDER BY and LIMIT in UNIONed queries, but don't have mysql instance to check it), but what if you try:
(SELECT t2.id
FROM myTable t1
INNER JOIN myTable t2 ON t2.id > t1.id
WHERE t1.number = 25
ORDER BY t2.id
LIMIT 1)
UNION ALL
(SELECT t2.id
FROM myTable t1
INNER JOIN myTable t2 ON t2.id < t1.id
WHERE t1.number = 25
ORDER BY t2.id DESC
LIMIT 1)
SELECT * FROM table WHERE id IN (SELECT id, id-1, id+1 FROM table WHERE number=25)

Select 5th highest Value without using LIMIT

I am new to SQL and I want to fetch 5th highest value without using LIMIT. Here is the code I am trying but it is not working properly. It is showing the 5th lowest value instead of 5th highest value.
SELECT a . * FROM user AS a
WHERE 5 =
(SELECT count( DISTINCT b.id ) FROM user AS b WHERE b.id >= a.id ORDER BY a.id DESC)
Can anyone help me with this?
You could also do:
SET #nth := 5;
SELECT
a.*
FROM jos_modules AS a
WHERE #nth = (
SELECT
COUNT(b.id)
FROM user AS b
WHERE
a.id >= b.id
);
Try this
SELECT a . *
FROM user AS a
WHERE 5 = (
SELECT count( DISTINCT b.id )
FROM user AS b
WHERE a.id >= b.id ORDER BY a.id )
select * from (
select a.* , row_number() over (order by id asc) as RANK
from a ) where RANK=5 ;
If you are using a Teradata DB , you can use qualify statement :
select * from a
qualify row_number () over(order by id asc)=5;

SQL select the last 3 dates from a table

I have a table with lots of fields in mysql
I need a query to return (in the same raw!) the top last 3 dates (dates can have large gaps between them)
ie:
2012/01/20
2012/01/18
2012/01/12
2012/01/10
2012/01/04
etc...
Any help will be appreciated
I must get them in the same row!
This is the query I am trying to use with no success:
SELECT a.id, a.thedate, b.id AS id1, b.thedate AS thedate1, c.id AS id2, c.thedate as thedate2
FROM mytable AS a INNER JOIN mytable AS b ON a.id = b.id INNER JOIN mytable AS c ON b.id=c.id
WHERE c.thedate = SELECT MAX(thedate)
EDIT :
SELECT group_concat(date) FROM (SELECT date FROM my_table ORDER BY date DESC LIMIT 3) AS temp
Corrected-
SELECT group_concat(date) FROM ( select date from table_name order by date desc limit 3) as a
SELECT GROUP_CONCAT(a.date )
FROM (
SELECT date
FROM my_table
ORDER BY date DESC
LIMIT 3
) AS a