How get results only if the endDate NOT greater than today - mysql

I need only the ids where the endDate is not greater than today
or all endDates of the id are expired
table 1 t1
id |
---
1
2
3
4
table 2 t2
id | t1_id | endDate
-----------------------
1 | 2 | 2019-01-01
2 | 3 | 2019-01-01
3 | 3 | 2020-01-01
4 | 3 | 2025-01-01
Query
SELECT t1.id ,t2.endDate
FROM table_1 t1
LEFT JOIN table_2 t2 ON t2.t1_id = t1.id
WHERE NOT(t2.endDate > CURDATE())
AND ???
I need this result:
t1.id | t2.endDate
-----------------------
2 | 2019-01-01

If I understand your requirement correctly you can use NOT EXISTS:
SELECT t1.id, t2.endDate
FROM table_1 t1
INNER JOIN table_2 t2 ON t2.t1_id = t1.id
WHERE NOT EXISTS
(
SELECT 1
FROM table_2 t
WHERE t.t1_id = t2.t1_id AND t.endDate > CURDATE()
)
Demo here

Related

Join table group by with sort desc

I have 2 table
Table 1
id | value
-----------
1 | a
2 | b
3 | c
4 | d
Table 2
id | table1_id | date
------------------------
1 | 1 | 01-01-2020 1:00:00
2 | 1 | 01-01-2020 2:00:00
3 | 1 | 05-01-2020 1:00:00 (*)
4 | 2 | 05-01-2020 1:00:00
5 | 3 | 06-01-2020 1:00:00
6 | 3 | 06-01-2020 2:00:00 (*)
7 | 2 | 07-01-2020 1:00:00 (*)
I want to join table 1 to table 2. get row of table 2 is max value date and group by table1_id
Like exxample, i want get data like this
id | value | table1_id | date
-------------------------------------------------
1 | a | 1 | 05-01-2020 1:00:00
2 | b | 2 | 07-01-2020 1:00:00
3 | c | 1 | 06-01-2020 2:00:00
4 | d | NULL | NULL
I tryed like this, but not work true
SELECT tb1.*, tb2.* FROM table1 AS tb1
LEFT JOIN
( SELECT * FROM table2 ORDER BY date DESC ) AS tb2
ON tb1.id = tb2.table1_id
GROUP BY table1_id
Can someone help me ? Thanks all <3
The old school way of doing this in MySQL might be to join to a subquery which finds the maximum date in the second table for each table1_id:
SELECT
t1.id,
t1.value,
t2.table1_id,
t2.date
FROM table1 t1
LEFT JOIN
(
SELECT t2.table1_id, t2.date
FROM table2 t2
INNER JOIN
(
SELECT table1_id, MAX(date) AS max_date
FROM table2
GROUP BY table1_id
) t
ON t.table1_id = t2.table1_id AND
t.max_date = t2.date
) t2
ON t2.table1_id = t1.id;
Demo
You can try this:
SELECT id, value, table1_id, max(date) date
FROM
(SELECT t1.id, t1.value, t2.table1_id, t2.date
FROM table1 t1 LEFT JOIN table2 t2
ON t1.id = t2.table1_id
) qry
GROUP BY id, value, table1_id
You can also use window function as below
SELECT tb1.*, tb2.table1_id, tb2.date
FROM table1 AS tb1
LEFT JOIN
( SELECT table2.*,
row_number() over(partition by table1_id ORDER BY date DESC) as seq_num
FROM table2 ) AS tb2
ON tb1.id = tb2.table1_id
Where tb2.seq_num = 1 ;
Here is a demo - https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=f52a5a930411dcc04900a1a5bacfe6e9. The demo contains both NULL and not NULL versions.
I strongly recommend that you use window functions for this -- assuming you want mulple columns. This looks like:
select t1.*, t2.*
from table1 t1 left join
(select t2.*,
row_number() over (partition by table1_id order by date DESC) as seqnum
from table2 t2
) t2
on t1.id = t2.table1_id and seq_num = 1 ;
However, if you just want one column -- and the table1_id is redundant so I see no need to include it -- then a correlated subquery is often the fastest method:
select t1.*,
(select max(t2.date) from table2 t2 where t1.id = t2.table1_id)
from table1 t1;
In particular, this can take advantage of an index on table2(table1_id, date).

How can I get a record which has two corresponding columns which are multiple in SQL?

For example, I have two tables:
ID | Name
------------
1 | test 1
2 | test 2
ID2| ID | Age
--------------
1 | 1 | 18
2 | 1 | 18
3 | 1 | 19
4 | 2 | 18
5 | 2 | 19
I want to have all records that have columns which are multiple in name with age but I don't know how to do that.
I want an output like this:
Name | Age
--------------------
test 1 | 18
test 1 | 18
Can anyone help me?
Try following query:
Select t1.*, t2.*
from table1 t1
join table2 t2
on t1.id = t2.id
join (select id, age
from table2
group by id, age
having count(*) > 1
) t3
on t1.id = t2.id and t2.id = t3.id and t2.age = t3.age
Use exists:
select t.*
from t
where exists (select 1
from t t2
where t2.name = t.name and t2.age = t.age and
t2.id <> t.id
);
With an index on (name, age, id), this should be the fastest approach.
You can also use an IN on tupples.
And a GROUP BY can be combined with a HAVING to only get those that have duplicate (name, age).
SELECT t1.Name, t2.Age
FROM YourTable2 t2
LEFT JOIN YourTable1 t1 ON t1.ID = t2.ID
WHERE (t2.ID, t2.Age) IN (
SELECT ID, Age
FROM YourTable2
GROUP BY ID, Age
HAVING COUNT(*) > 1
);

mysql max function in group by

I try to get items in mysql, I need to remove from result t2 items, that have status_id = 17 and status_change_date less then max date_created for this t1
t1:
-----
|id |
-----
| 1 |
-----
t2:
---------------------------------------------------------------
| id | t1_id | status_change_date | status_id | date_created |
---------------------------------------------------------------
| 1 | 1 | 2006-02-12 | 17 | 2004-02-12 |
| 2 | 1 | 2006-02-12 | 17 | 2006-02-12 |
| 3 | 1 | 2010-02-12 | 17 | 2007-02-12 |
| 4 | 1 | 2006-02-12 | 17 | 2008-02-12 |
---------------------------------------------------------------
so in result I should to see only item with id 3, cause only in this case status_change_date is after max date_created for items, that have reference to t1 item with id 1
SELECT t1.*, t2.*
FROM t1 JOIN
(
SELECT t2.*,
MAX(date_created) AS max_date FROM t2 WHERE t2.id NOT IN
(
SELECT t2.id FROM t2
WHERE
status_id = 17
and status_change_date < max_date
)
GROUP BY t1_id
) t2 ON t1.id = t2.t1_id
But i got error cause sql don't know what is max_date. How I should to get this value?
From what I understand of joins, your 'from' should come AFTER your 'select' statements.
select *,left(name,1) as L1 from artists order by name limit 5;
You can store value to temporary variable and use to compare:
SELECT t1.*, t2.*
FROM t1 JOIN
(
SELECT t2.*,
#max_date:=MAX(date_created) AS max_date FROM t2 WHERE t2.id NOT IN
(
SELECT t2.id FROM t2
WHERE
status_id = 17
and status_change_date < #max_date
)
GROUP BY t1_id
) t2 ON t1.id = t2.t1_id
You can go with anyone of the following queries:
SELECT t1.*,
t2.*,
Max(date_created) AS max_date
FROM t1
JOIN t2
ON t1.id = t2.t1_id
WHERE status_id = 17
GROUP BY status_change_date
HAVING status_change_date > max_date;
Or
SELECT t1.*,
t2.*
FROM t1
JOIN t2
ON t1.id = t2.t1_id
WHERE status_id = 17
AND status_change_date > (SELECT Max(date_created)
FROM t2);

Find values C that exists in every B from A

I have a table with 3 fields ID,A,B.
I want to find every B that occurs in every A from some ID
For example:
ID | A | B |
----------------------
1 | 10 | 22 |
1 | 10 | 24 |
1 | 11 | 22 |
| | |
2 | 12 | 31 |
2 | 13 | 33 |
| | |
3 | 14 | 34 |
Should return:
ID | B |
-------------
1 | 22 |
3 | 34 |
because for every different value of A from ID 1 , B = 22 occurs.
Same for id 3.
Any idea how I can do it?
Thank you in advance.
Sql Fiddle Demo
You can use this query to validate what rows your need.
SELECT T1.B, T1.ID, COUNT(DISTINCT A), T2.total_id_a
FROM Table1 T1
JOIN (SELECT ID , COUNT(DISTINCT A) as total_id_a
FROM Table1
GROUP BY ID) T2
ON T1.ID = T2.ID
GROUP BY B, ID;
But this will provide the result you want.
SELECT ID, B
FROM (
SELECT T1.ID, T1.B, COUNT(DISTINCT A), T2.total_id_a
FROM Table1 T1
JOIN (SELECT ID , COUNT(DISTINCT A) as total_id_a
FROM Table1
GROUP BY ID) T2
ON T1.ID = T2.ID
GROUP BY B, ID
HAVING COUNT(DISTINCT A) = T2.total_id_a
) T
OUTPUT
| ID | B |
|----|----|
| 1 | 22 |
| 3 | 34 |
# For case ID=1 and B=22 for example above
SELECT DISTINCT t1.ID, t1.B
FROM yourtable AS t1
INNER JOIN yourtable AS t2
ON t2.B = t1.B
AND t2.A <> t1.A
AND t1.ID = t2.ID
UNION
# For case ID=3 and B=34 for example above
SELECT DISTINCT t1.ID, t1.B
FROM yourtable AS t1
INNER JOIN yourtable AS t2
ON t2.B = t1.B
AND t2.A = t1.A
AND t1.ID = t2.ID
LEFT JOIN yourtable AS t3
ON t3.ID = t1.ID
AND (t3.A <> t1.A OR t3.B <> t1.B)
WHERE t3.ID IS NULL

Combine two selects into one

I have a couple of tables. I'll try to make it simple: Table_1 ID is unique. Table_2 ID is not unique. The table_2 stores the ID from a row on table_1 and a value, resulting in, for instance, this:
table_1
ID | A
------
1 | a
2 | b
3 | c
table_2
ID | B
------
1 | x
1 | y
3 | z
I want to count how many of each ID is there on table_2, so I do
select t1.id, count(*)
from table_1 t1
group by t1.id
id | count
----------
1 | 2
3 | 1
And I want to list every row on table_2 and its corresponding value on table_1.A, so I do
select t1.id, t1.A, t2.B
from table_2 t2
left join table_1 t1
on t1.id = t2.id
ID | A | B
----------
1 | a | x
1 | a | y
3 | c | z
Is there a way to combine those 2 selections into one, to get a result like this?
ID | A | B | count
------------------
1 | a | x | 2
1 | a | y | 2
3 | c | z | 1
You can combine the results by joining the count result.
Fiddle with sample data
select t1.id, t1.A, t2.B, x.cnt as count
from t2
left join t1
on t1.id = t2.id
join (select t2.id, count(*) as cnt
from t2
group by t2.id
) x
on x.id = t1.id
Besides the generic Derived Table solution posted by #vkp you might also utilize a Scalar Subquery to return a single value:
select t1.id, t1.A, t2.B,
(select count(*)
from t2 as x
where x.id = t2.id
) cnt
from t2
http://www.sqlfiddle.com/#!9/07a3a/6