mysql select if datediff is greater than - mysql

I would like to query users from lat 3 years only if the time diffrence of date_start and date_end is greater than 3 months. I have tried a lot of things but nothing works. This is the statment i made until now :
SELECT accounts.account_id, accounts.name, accounts.active_club_id,
accounts.phone, MIN(shifts_accounts.date_start) as 'datestart', MAX(shifts_accounts.date_end) as 'dateend'
FROM `shifts_accounts`
JOIN accounts ON shifts_accounts.account_id = accounts.account_id
JOIN accounts_groups ON accounts.account_id = accounts_groups.account_id
WHERE accounts_groups.group_id = 7
AND DATEDIFF('dateend', 'datestart') > 90
AND accounts.active_club_id != 1
AND shifts_accounts.date_start > '2014-11-28'
AND shifts_accounts.date_start < '2017-11-28' GROUP BY accounts.account_id

The following is an example of a valid query. I don't think there's enough information to say whether it's what you want or not...
SELECT a.account_id
, a.name
, a.active_club_id
, a.phone
, MIN(sa.date_start) datestart
, MAX(sa.date_end) dateend
FROM shifts_accounts sa
JOIN accounts a
ON a.account_id = sa.account_id
JOIN accounts_groups ag
ON ag.account_id = a.account_id
WHERE ag.group_id = 7
AND a.active_club_id != 1
AND sa.date_start BETWEEN '2014-11-28' AND '2017-11-28'
GROUP
BY a.account_id
HAVING DATEDIFF(dateend, datestart) > 90;
For further help, see: Why should I provide an MCVE for what seems to me to be a very simple SQL query?

Try with this,
SELECT accounts.account_id, accounts.name, accounts.active_club_id,
accounts.phone, MIN(shifts_accounts.date_start) as 'datestart', MAX(shifts_accounts.date_end) as 'dateend'
FROM `shifts_accounts`
JOIN accounts ON shifts_accounts.account_id = accounts.account_id
JOIN accounts_groups ON accounts.account_id = accounts_groups.account_id
WHERE accounts_groups.group_id = 7
AND DATEDIFF('dateend', 'datestart') > 90
AND accounts.active_club_id != 1
AND shifts_accounts.date_start < DATE_SUB(NOW(),INTERVAL 3 YEAR) GROUP BY accounts.account_id

Related

How can I GROUP BY SELECT subquery aggregates?

first time on here, hoping for help. (MySQL) I tried to use subqueries in a SELECT statement but when I GROUP BY, the single aggregate value outputs of the subqueries just produce the one same value for all rows in the table. This implies they are not GROUPED, right? How close am I to getting this right? Thanks
SELECT
c.name, ca.name, DATE_FORMAT(sp.created,'%Y%m') AS yr_month,
ss.signup_source, count(sp.seller_profile_id) AS No_seller_profiles,
(SELECT SUM(seller_invoice.gbp_value)/100
FROM seller_invoice JOIN seller_profile
ON seller_invoice.seller_profile_id = seller_profile.seller_profile_id
WHERE seller_invoice.created BETWEEN seller_profile.created AND ADDDATE(seller_profile.created, INTERVAL 30 DAY)),
(SELECT count(project_response.project_response_id)
FROM project_response JOIN seller_profile
ON project_response.seller_profile_id = seller_profile.seller_profile_id
WHERE project_response.created BETWEEN seller_profile.created AND ADDDATE(seller_profile.created, INTERVAL 30 DAY) AND project_response.is_visible_to_seller = 1)
FROM seller_profile AS sp
JOIN country AS c ON sp.country_id = c.country_id
JOIN seller_category AS sc ON sp.seller_profile_id = sc.seller_profile_id
JOIN category AS ca ON sc.category_id = ca.category_id
JOIN seller_signup_source AS ss ON sp.seller_profile_id = ss.seller_profile_id
WHERE sp.created BETWEEN '2018-11-01' AND '2018-12-31'
GROUP BY 1,2,3,4;

Buyers structure by registration date query optimisation

I would like to show buyers structure by their registration date e.g.:
H12016 10.000 buyers
from which
2.000 registered in H12014
4.000 registered in H22014
etc.
I have two queries for that:
Number 1 (buyers from H12016 (about 50k records)):
SELECT DISTINCT
r.idUsera as id_usera
FROM
rezerwacje r
WHERE
r.dataZalozenia between '2016-01-01' and '2016-07-01'
and r.`status` = 'zabookowana'
ORDER BY
id_usera
Number 2 (users_ids and their registration (insert) date (about 3,8M users)):
SELECT
m.user_id,
date(m.action_date) as data_insert
FROM
mwids m
WHERE
m.`type` = 'insert'
Both queries separately run fine, but when I try to combine them like so:
SELECT DISTINCT
r.idUsera as id_usera,
t1.data_insert
FROM
rezerwacje r
LEFT JOIN
(
SELECT
m.user_id,
date(m.action_date) as data_insert
FROM
mwids m
WHERE
m.`type` = 'insert'
) t1 ON t1.user_id = r.idUsera
WHERE
r.dataZalozenia between '2016-01-01' and '2016-07-01'
and r.`status` = 'zabookowana'
ORDER BY
id_usera
this query runs "indefinetely" and I have to kill it after some time.
I do not belive it should run that long. If the query Number 2 was smaller i.e. about 1M users I could combine results in Excel in matter of seconds. So why is it not possible inside the database? What am I doing wrong?
SELECT DISTINCT
r.idUsera as id_usera,
t1.data_insert
FROM
rezerwacje r
INNER JOIN
(
SELECT
m.user_id,
date(m.action_date) as data_insert
FROM
mwids m
WHERE
m.`type` = 'insert'
) t1 ON t1.user_id = r.idUsera
WHERE
r.dataZalozenia between '2016-01-01' and '2016-07-01'
and r.`status` = 'zabookowana'
ORDER BY
id_usera
Try with INNER JOIN.
Query 1 needs
INDEX(status, dataZalozenia, id_usera)
Query 3: Rewrite thus:
If there is only one row in mwids for 'insert' per user:
SELECT r.idUsera as id_usera, DATE(m.action_date) AS data_insert
FROM rezerwacje r
LEFT JOIN mwids m ON m.user_id = r.idUsera
AND m.`type` = 'insert'
WHERE r.dataZalozenia >= '2016-01-01'
AND r.dataZalozenia < '2016-01-01' + 12 MONTH
and r.`status` = 'zabookowana'
ORDER BY r.idUsera
with
INDEX(status, dataZalozenia, isUsera) -- on r
INDEX(type, user_id, action_date) -- on m
If there can be multiple rows, do this:
SELECT r.idUsera as id_usera,
( SELECT DATE(m.action_date)
FROM mwids m
WHERE m.user_id = r.idUsera
AND m.`type` = 'insert'
LIMIT 1
) AS data_insert
FROM rezerwacje r
LEFT JOIN mwids m ON m.user_id = r.idUsera
AND m.`type` = 'insert'
WHERE r.dataZalozenia >= '2016-01-01'
AND r.dataZalozenia < '2016-01-01' + 12 MONTH
and r.`status` = 'zabookowana'
ORDER BY r.idUsera
But you will be getting a random action_date. So maybe you want MIN() or MAX()?

Using two different measures in a having statement

I am including the code I am trying to use. What I want is to get a count of encounter id's for each doctor. I want to capture patients who have had at least 2 visits or who have had one preventive visit. I don't know how to make this work using the having statement. thanks for any assistance.
SELECT e.doctorID, COUNT(DISTINCT e.encounterID) AS VisitCount
FROM enc e
JOIN users u ON e.patientID = u.uid
Left JOIN diagnosis d ON e.encounterID = d.encounterID
LEFT JOIN items it ON d.itemID = it.itemID
LEFT JOIN itemdetail id ON it.itemID = id.itemID
WHERE e.encType = 1 AND e.status = 'CHK' AND e.deleteFlag = 0 AND
e.date BETWEEN DATE_ADD((LAST_DAY(DATE_ADD(CURDATE(),INTERVAL -2 MONTH))), INTERVAL 1 DAY) AND LAST_DAY(DATE_ADD(CURDATE(),INTERVAL -1 MONTH))
AND FLOOR(DATEDIFF(NOW(),u.ptdob)/365.25) >= 18 AND e.doctorID = e.resourceID
GROUP BY e.doctorID, id.value
HAVING
COUNT(e.patientid)>=2 OR
id.value in ('Z00.00', 'Z00.01')
You dont need to include id.value in grp by clause. Try to give valid condition in having clause with id.value
select e.doctorID,
COUNT(distinct e.encounterID) as VisitCount from enc e join users u on e.patientID = u.uid
left join diagnosis d on e.encounterID = d.encounterID left join items it on
d.itemID = it.itemID left join itemdetail id on
it.itemID = id.itemID where e.encType = 1 and e.status ='CHK' and e.deleteFlag = 0 and
e.date between DATE_ADD((LAST_DAY(DATE_ADD(CURDATE(), INTERVAL - 2 MONTH))), INTERVAL 1 DAY)
and LAST_DAY(DATE_ADD(CURDATE(), INTERVAL - 1 MONTH))
and
FLOOR(DATEDIFF(NOW(), u.ptdob) / 365.25) >= 18
and e.doctorID = e.resourceID group by e.doctorID
having COUNT(e.patientid) >= 2
or sum(case when id.value in ('Z00.00','Z00.01') then 1
else 0 end)>=1

Select in Select MySQL

I have two queries, i'd like if is possible execute in only one query as a Select in Select.
The first one:
SELECT
users.id
FROM users
LEFT JOIN users_date ON users_date.user = users.id
LEFT JOIN users_varchar ON users_varchar.user = users.id
WHERE
abilitato = 1
AND users_date.key = 'birthday'
AND users_varchar.key = 'nation'
AND users_varchar.value = 'US'
AND (users.reg_date >= '2013-05-31' AND users.reg_date <= '2013-05-31')
AND (floor(DATEDIFF(NOW(), users_date.value) / 365) >= 19 AND floor(DATEDIFF(NOW(), users_date.value) / 365) <= 19)
it retrieve a list of user id (filtered by Age, Nation or Date of registration)
the second one:
SELECT count(`matches`.`id`) FROM `matches` WHERE (`matches`.`status_home` = 3 AND `matches`.`status_guest` = 3) AND (`matches`.`team_home` = 13 OR `matches`.`team_guest` = 13)
i need perform the second select for every ID retrieved by the one's.
for every perform i must replace the value 13 with the id retrieved.
it is possible perform all in a single query with a select in select?
thanks advance for your help
Try this sql.
SELECT count(`matches`.`id`)
FROM `matches` m
INNER JOIN ( SELECT users.id as id
FROM users
LEFT JOIN users_date ON users_date.user = users.id
LEFT JOIN users_varchar ON users_varchar.user = users.id
WHERE abilitato = 1
AND users_date.key = 'birthday'
AND users_varchar.key = 'nation'
AND users_varchar.value = 'US'
AND (users.reg_date >= '2013-05-31' AND users.reg_date <= '2013-05-31')
AND (floor(DATEDIFF(NOW(), users_date.value) / 365) >= 19 AND floor(DATEDIFF(NOW(), users_date.value) / 365) <= 19)) t
on t.id=m.team_guest
WHERE (`matches`.`status_home` = 3 AND `matches`.`status_guest` = 3)
AND (`matches`.`team_home` = 13 OR `matches`.`team_guest` = t.id)
GROUP BY t.id
You can express what you want to do as an explicit join. But the question asks for a select within a select. For that, you need a correlated subquery. Here is the final query:
select users.id,
(SELECT count(`matches`.`id`)
FROM `matches`
WHERE (`matches`.`status_home` = 3 AND `matches`.`status_guest` = 3) AND
(`matches`.`team_home` = user.id OR `matches`.`team_guest` = users.id)
) as cnt
FROM users LEFT JOIN
users_date
ON users_date.user = users.id LEFT JOIN
users_varchar
ON users_varchar.user = users.id
WHERE abilitato = 1 AND users_date.key = 'birthday' AND
users_varchar.key = 'nation' AND users_varchar.value = 'US' AND
(users.reg_date >= '2013-05-31' AND users.reg_date <= '2013-05-31') AND
(floor(DATEDIFF(NOW(), users_date.value) / 365) >= 19 AND
floor(DATEDIFF(NOW(), users_date.value) / 365) <= 19
)
(The formatting helps me understand the query better.)
Doing this without a correlated subquery is a bit challenging because of the or in the matching condition.

MySQL query sub query or grouping

Each modx_site_content record may have several records in modx_site_tmplvar_contentvalues.
I need to retrieve both modx_site_tmplvar_contentvalues.value where the tvv.tmplvarid = 3 AND the tvv.tmplvarid = 1. where tvv.tmplvarid is a future date, I need to return the tvv.value of tvv.tmplvarid 3 which is a comma separated list of tags.
This query does not return the values I need & I'm not sure how to get just what I want.
SELECT sc.id, sc.pagetitle, tvv.value, tvv.tmplvarid, tvv.id, tvv.value
FROM modx_site_content sc
left join modx_site_tmplvar_contentvalues tvv on tvv.contentid = sc.id
where published = '1'
and (tvv.tmplvarid = '3' and tvv.value >= curdate())
order by sc.id;
basically in the end I need to return only the list of tags (tvv.tmplvarid = 3) where the other associated record (tvv.tmplvarid = 1) is a date in the future.
Any thoughts, can this be done with grouping instead? I don't actually need anything from the modx_site_content table.
So you need to return the tags both rows in the modx_site_tmplvar_contentvalues table that has tmplvarid of 1 and 3 both related to the same modx_site_content, but only when the tmplvarid 3 row has a datetime field in the future?
I would do two separate joins to the modx_site_tmplvar_contentvalues tabe:
SELECT tOne.value, tThree.value
FROM modx_site_tmplvar_contentvalues tOne
INNER JOIN modx_site_content c ON tOne.contentid = c.id
INNER JOIN modx_site_tmplvar_contentvalues tThree ON tThree.contentid = c.id
WHERE c.published = 1
AND tOne.tmplvarid = 1
AND tThree.tmplvarid = 3 AND tThree.date > NOW()
SQL Fiddle: http://sqlfiddle.com/#!2/a4031/2
I figured it out. Amazing what you can do if you just read the docs ;)
select tv.contentid, tv.value as eventdate, sc.id, sc.pagetitle, tvv.value from
(
select * from modx_site_tmplvar_contentvalues cv
where cv.tmplvarid = 3
and cv.value >= curdate()
) as tv
left join modx_site_content sc on sc.id = tv.contentid
left join modx_site_tmplvar_contentvalues tvv on tvv.contentid = sc.id
where (tvv.tmplvarid = 1)
order by value asc