I'm currently working on a query that looks like this. There are two tables - members and member_gathering.
SELECT id, city_id, name FROM members
WHERE "id" = "member_id" IN
(
SELECT "member_id" from member_gathering
GROUP BY "member_id"
HAVING COUNT(DATEDIFF("visited","joined">=365))>=5
ORDER BY "member_id"
)
ORDER BY id*1;
The goal is to have an output of all IDs satisfying the condition of being in more than 5 groups, in which a member is active for more than a year. Being active means having a difference between "visited" and "joined" columns (both are TIMESTAMP) for more than a year (I set that as 365 days).
However, after running, this code shows all the rows in a members table (though manual check of both tables shows that some rows do not satisfy both conditions at the same time).
Any ideas on how to improve the code above? I'm not sure if I can use 'nested' condition inside COUNT(), but all other variants used before show either NULL values or returned all rows in the table, which is obviously not right. Also, I was thinking that problem might be with DATEDIFF function.
All suggestions are welcome: I'm a newbie to MySQL, so I'm not that familiar with it.
UPD: data sample:
1) members
id city_id name
2 980 Joey
5 980 Carl
10 1009 Louis
130 1092 Andrea
2) member_gathering
member_id gathering_id joined visited
2 1 2010-01-01 00:00:00 2010-02-01 00:00:00
2 2 2010-01-01 00:00:00 2010-02-01 00:00:00
5 2 2010-01-01 00:00:00 2010-02-01 00:00:00
10 3 2010-01-01 00:00:00 2010-02-01 00:00:00
130 1 2010-02-01 00:00:00 2013-02-01 00:00:00
130 2 2010-02-01 00:00:00 2013-02-01 00:00:00
130 3 2010-02-01 00:00:00 2014-02-01 00:00:00
130 4 2010-02-01 00:00:00 2018-02-01 00:00:00
130 5 2010-02-01 00:00:00 2015-02-01 00:00:00
Expected result would be only ID 130, thus: 130, 1092, Andreana.
I believe you first need to find all records where datediff is 365 days or more. Then find members who have 5 or more such instances. This needs both WHERE and HAVING clause:
SELECT id, city_id, name
FROM members
WHERE id IN (
SELECT member_id
FROM member_gathering
WHERE DATEDIFF(visited, joined) >= 365
GROUP BY member_id
HAVING COUNT(*) >= 5
)
You could use this way
SELECT id, city_id, name FROM members
WHERE member_id IN
(
SELECT member_id from member_gathering
GROUP BY member_id
HAVING SUM(DATEDIFF(visited, joined) >= 365)>=5
ORDER BY member_id
)
You should use separated expression for count differente category of datediff and remmeber that count work for not null values so if you want obtain the totale for true values you should sue SUM
Related
If I have the following table,
Name
Date
Liam
2020-05-05 12:00:00
John
2020-12-15 03:45:00
Ross
2021-03-20 02:00:00
Ross
2021-03-20 02:05:00
Ross
2021-03-20 04:00:00
Ross
2021-03-20 04:30:00
Ross
2021-03-20 03:00:00
Jane
2021-03-20 02:00:00
Assume that NOW() gives 2021-03-20 10:00:00.
I want to remove all rows other than first three(based on time) if the same person has more than 3 entries in the last 24 hours from right now.
So this table becomes,
Name
Date
Liam
2020-05-05 12:00:00
John
2020-12-15 03:45:00
Ross
2021-03-20 02:00:00
Ross
2021-03-20 02:05:00
Ross
2021-03-20 03:00:00
Jane
2021-03-20 02:00:00
I assume that table name is tbl_dates.
So delete every rows which exists in today except the last rows after the first 3 rows (Nested select).
delete from tbl_dates as d1 where not exists (
select tbl_tmp.`Date` from (
select d2.`Date` from tbl_dates as d2 where d2.`Name`=d1.`Name` and date(d2.`Date`)=current_date() order by d2.`date` asc limit 0,3
) as tbl_tmp where tbl_tmp.`Date`=d1.`Date`
) and date(d1.`Date`)=current_date()
tbl_tmp: This subquery acted as a table for the first 3 rows of a person in today.
not exists (select ...): This subquery acted as a condition to equal current delete statement row with the first 3 rows of a person in today.
Updated:
if You want to select in this condition you can use this:
select * from tbl_dates as d1 where exists (
select tbl_tmp.`Date` from (
select d2.`Date` from tbl_dates as d2 where d2.`Name`=d1.`Name` and date(d2.`Date`)=current_date() order by d2.`date` asc limit 0,3
) as tbl_tmp where tbl_tmp.`Date`=d1.`Date`
) or date(d1.`Date`)<>current_date()
MySql version which I Tested: 8.0.18
I want to create a stored procedure in MySQL, but first, I want to get the query right. However, I keep getting the problem that I can't seem to get the correct id back from my query that correspond with the DateTime stamps that I get back.
this is the table I am trying to get the result from:
id EventId start end
1 1 2019-04-05 00:00:00 2019-04-07 00:00:00
2 2 2020-04-03 00:00:00 2020-04-03 00:00:00
3 3 2020-04-02 00:00:00 2020-04-02 00:00:00
7 1 2020-06-11 00:00:00 2020-06-11 00:00:00
9 2 2020-06-18 00:00:00 2020-06-18 00:00:00
10 3 2020-06-11 00:00:00 2020-06-11 00:00:00
11 3 2020-06-07 00:00:00 2020-06-07 00:00:00
query:
SELECT DISTINCT Eventid, MIN(start), id
from date_planning
WHERE `start` >= NOW()
GROUP BY Eventid
this gives me the following result
EventId Min(start) id
1 2020-06-11 00:00:00 3
2 2020-06-18 00:00:00 9
3 2020-06-07 00:00:00 10
but these are the correct ids that belong to those DateTimes:
EventId Min(start) id
1 2020-06-11 00:00:00 7
2 2020-06-18 00:00:00 9
3 2020-06-07 00:00:00 11
You want the row with the minimum "future" date for each eventId. To solve this greatest-n-per-group problem, you need to filter rather than aggregate. Here is one option using a correlated subquery:
select dt.*
from date_planning dt
where dt.start = (
select min(dt1.start)
from date_planning dt1
where dt1.eventId = dt.eventId and dt1.start >= now()
)
For performance, you need an index on (eventId, start).
I have two tables:
Table 1: planA
ID Date Count
3 2017-01-01 10
2 2017-02-03 15
10 2017-01-30 8
Table 2: planB
ID Date Value
3 2017-01-02 11
2 2017-02-04 12
21 2017-01-30 3
3 2017-02-03 33
What I want to do is to join the two tables on (ID and Date) columns.
However, on Date, I want to use the next day to the date on the table 1.
Therefore, the joined table should look like the following:
PlanA.ID PlanA.Date PlanB.Date PlanA.Count PlanB.Value
3 2017-01-01 2017-01-02 10 11
2 2017-02-03 2017-02-04 15 12
Is this even possible?
Any suggestion would be appreciated!
Yes it is possible:
select
PlanA.ID,
PlanA.Date,
PlanB.Date,
PlanA.Count,
PlanB.Value
from
PlanA inner join PlanB
on (
PlanA.ID = PlanB.ID
and
PlanA.Date + INTERVAL 1 DAY = PlanB.Date
)
if Date is a column of type date, + INTERVAL 1 DAY will return the next day of the one given, and then you can perform the join.
I have seen variations of this question asked but either they didn't apply or I didn't understand the answer/s.
I have two tables one table with charges types with additional cost and one of charges. I want to join them to get the appropriate values. I want to join the tables where the charge is between the startDate and the endDate and on the types. If there is not a match I want it to choose the type -1 (same condition for dates). If there is not a match I don't want it to show up in the results.
I initially was was going to do a normal left join ordered by 'type' desc and then group by 'type' believing that it would only leave me with the first type but I read that MySQL advises against this because the group by can be unpredictable and not always return the first match.
Tables:
startDate | endDate | type | addCost
--------------------------------------
2010-01-01 2010-12-31 1 100
2010-01-01 2010-12-31 2 200
2010-01-01 2010-12-31 -1 50
2011-01-01 2012-02-20 3 350
2011-01-01 2012-02-20 1 150
2011-01-01 2012-02-20 -1 75
chargeDate | type | cost
---------------------------
2010-10-01 1 10
2010-11-01 2 20
2010-12-01 4 40
2011-02-01 3 60
2011-03-01 2 25
2011-04-01 4 25
Desired Results:
chargeDate | type | cost | addCost
---------------------------------
2010-10-01 1 10 100
2010-11-01 2 20 200
2010-12-01 4 40 50
2011-02-01 3 60 350
2011-03-01 2 25 75
I'm using a subquery where I am trying to join charges with charges_types. If the join doesn't succeed, type is null and with coalesce I set type_c as -1, otherwise I set it to type. Then I join this subquery with charges_types again, and on the join clause i use type_c instead of type:
select c.chargeDate, c.type, c.cost, ct.addCost
from
(select
charges.chargeDate,
charges.type,
coalesce(charges_types.type, -1) as type_c,
charges.cost
from
charges left join charges_types
on charges.chargeDate between charges_types.startDate and charges_types.endDate
and charges.type = charges_types.type) c
inner join charges_types ct
on c.chargeDate between ct.startDate and ct.endDate
and c.type_c = ct.type
I've a user table (MySQL) with the following data
id email creation_date
1 bob#mail.com 2011-08-01 09:00:00
2 bob#mail.com 2011-06-24 02:00:00
3 john#mail.com 2011-02-01 04:00:00
4 john#mail.com 2011-08-05 20:30:00
5 john#mail.com 2011-08-05 23:00:00
6 jill#mail.com 2011-08-01 00:00:00
As you can see we allow email duplicates so its possible to register several accounts with the same email address.
Now I need to select all adresses ordered by the creation_date but no duplicates. This is easy (i think)
SELECT * FROM (SELECT * FROM users ORDER BY creation_date) AS X GROUP BY email
Expected result:
id email creation_date
2 bob#mail.com 2011-06-24 02:00:00
6 jill#mail.com 2011-08-01 00:00:00
3 john#mail.com 2011-02-01 04:00:00
But then I also need to select all other adresses, ie. all that are not present in the result from the first query. Duplicate are allowed here.
Expected result:
id email creation_date
1 bob#mail.com 2011-08-01 09:00:00
4 john#mail.com 2011-08-05 20:30:00
5 john#mail.com 2011-08-05 23:00:00
Any ideas? Perfomance is important because the real database is very huge
SELECT * FROM a
FROM users a
LEFT JOIN (SELECT email, MIN(creation_date) as min_date GROUP BY email)x ON
(x.email = a.email AND x.min_date=a.creation_date)
WHERE x.email IS NULL
In SQL server we would do a Select statement using a rank.
Here are some MYSQL samples:
How to perform grouped ranking in MySQL
http://thinkdiff.net/mysql/how-to-get-rank-using-mysql-query/
I hope this helps.