MySQL query sub query or grouping - mysql

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

Related

MYSQL Join only on max row with data from multiple tables

I have a query that selects properties, and I need to join them to get the most recent activity on each one, where that activity_status = 3 (closed deal). when I get that, I need to get the bank that closed the deal (banks.is_reward = 1)
Problem is that the data is spread over many tables, so when I join to get all the results, and then try to limit to the max(activity_date), I need to group the results, and then I don't get the correct data from the other columns.
Here is a SQL Fiddle
I can do
Select * from properties
join
(SELECT deal_properties.property_id, activity.deal_id, activity.activity_date, banks.bank_id
FROM deal_properties
JOIN activity on activity.deal_id = deal_properties.deal_id
AND activity.activity_status = 3
JOIN banks ON banks.deal_id = activity.deal_id
AND banks.is_rewarded = 1) a
on a.property_id = properties.property_id;
and that will get me all the closed properties, with the rewarded banks, but I cant seem to limit that by the max(activity_date).
Option 1
The following gives what you're looking for following your current line of thought:
SELECT LastActivities.property_id, ActivityDetails.bank_id, LastActivities.activity_date
FROM (
SELECT p.property_id, MAX(a.activity_date) AS activity_date
FROM properties p
JOIN deal_properties dp
ON dp.property_id = p.property_id
JOIN activity a
ON a.deal_id = dp.deal_id AND a.activity_status = 3
GROUP BY p.property_id
) LastActivities
JOIN(
SELECT a.activity_date, dp.property_id, b.bank_id
FROM deal_properties dp
JOIN activity a
ON a.deal_id = dp.deal_id AND a.activity_status = 3
JOIN banks b
ON b.deal_id = a.deal_id AND b.is_rewarded = 1
) ActivityDetails
ON ActivityDetails.property_id = LastActivities.property_id
AND ActivityDetails.activity_date = LastActivities.activity_date
Here is the fiddle: HERE
Option 2
Below is another way to get the same results... This should be a bit more efficient as it only has one derived table instead of two.
SELECT p.property_id, b.bank_id, a.activity_date
FROM activity a
JOIN banks b
ON b.deal_id = a.deal_id AND b.is_rewarded = 1
JOIN deal_properties dp
ON dp.deal_id = a.deal_id
JOIN properties p
ON p.property_id = dp.property_id
JOIN(SELECT p.property_id, max(a.activity_date) AS activity_date
FROM activity a
JOIN deal_properties dp
ON dp.deal_id = a.deal_id
JOIN properties p
ON p.property_id = dp.property_id
GROUP BY p.property_id
) latest
ON latest.activity_date = a.activity_date AND latest.property_id = p.property_id
WHERE a.activity_status = 3
Here is the fiddle for option 2: HERE
looking to your sample seems you need
Select * from properties p
inner join
( SELECT deal_properties.property_id as property_id , max(activity.activity_date) max_date
FROM deal_properties
INNER JOIN activity on activity.deal_id = deal_properties.deal_id
AND activity.activity_status = 3
INNER JOIN banks ON banks.deal_id = activity.deal_id AND banks.is_rewarded = 1
group by property_id
) a on a.property_id = p.property_id;

Adding a subquery to a join

I've been using the following join, to pull rows of users whom have volunteered for various project positions.
SELECT p.id, up.position_id, title, max_vol, current_datetime, IF(up.id IS NULL, "0", "1") volunteered
FROM positions AS p
LEFT JOIN users_positions AS up
ON p.id = up.position_id
AND up.user_id = 1
AND up.calendar_date = '2016-10-03'
WHERE
p.project_id = 1
AND p.day = 1
...but in a change of functionality, I have to now account for the date of the latest edit to a project. In another query, I solved it like so
SELECT *
FROM positions
WHERE
current_datetime = (SELECT MAX(current_datetime)
FROM positions
WHERE
project_id = 1 AND day = 1)
Which works fine, but now I have to also incorporate the return of rows which match the latest datetime in the left join query.
I just can't seem to wrap my head around it. Any suggestions? Thanks.
Use a sub query, like this:
SELECT
p.id,
up.position_id,
title,
max_vol,
current_datetime,
IF(up.id IS NULL,
"0",
"1") volunteered
FROM
( SELECT
*
FROM
positions
WHERE
current_datetime = (
SELECT
MAX(current_datetime)
FROM
positions
WHERE
project_id = 1
AND day = 1
)
) AS p
LEFT JOIN
users_positions AS up
ON p.id = up.position_id
AND up.user_id = 1
AND up.calendar_date = '2016-10-03'
WHERE
p.project_id = 1
AND p.day = 1

(My)SQL JOIN - get teams with exactly specified members

Assume tables
team: id, title
team_user: id_team, id_user
I'd like to select teams with just and only specified members. In this example I want team(s) where the only users are those with id 1 and 5, noone else. I came up with this SQL, but it seems to be a little overkill for such simple task.
SELECT team.*, COUNT(`team_user`.id_user) AS cnt
FROM `team`
JOIN `team_user` user0 ON `user0`.id_team = `team`.id AND `user0`.id_user = 1
JOIN `team_user` user1 ON `user1`.id_team = `team`.id AND `user1`.id_user = 5
JOIN `team_user` ON `team_user`.id_team = `team`.id
GROUP BY `team`.id
HAVING cnt = 2
EDIT: Thank you all for your help. If you want to actually try your ideas, you can use example database structure and data found here: http://down.lipe.cz/team_members.sql
How about
SELECT *
FROM team t
JOIN team_user tu ON (tu.id_team = t.id)
GROUP BY t.id
HAVING (SUM(tu.id_user IN (1,5)) = 2) AND (SUM(tu.id_user NOT IN (1,5)) = 0)
I'm assuming a unique index on team_user(id_team, id_user).
You can use
SELECT
DISTINCT id,
COUNT(tu.id_user) as cnt
FROM
team t
JOIN team_user tu ON ( tu.id_team = t.id )
GROUP BY
t.id
HAVING
count(tu.user_id) = count( CASE WHEN tu.user_id = 1 or tu.user_id = 5 THEN 1 ELSE 0 END )
AND cnt = 2
Not sure why you'd need the cnt = 2 condition, the query would get only those teams where all of users having the ID of either 1 or 5
Try This
SELECT team.*, COUNT(`team_user`.id_user) AS cnt FROM `team`
JOIN `team_user` ON `team_user`.id_team = `team`.id
where `team_user`.id_user IN (1,5)
GROUP BY `team`.id
HAVING cnt = 2

MySQL Query, how to select data based on a condition in a different record in the same table?

Having some trouble getting my here around this query & wondering if anyone can help:
I'm trying to select all the tvv.value[s] from the modx_site_tmplvar_contentvalues where the tvv.tmplvarid = 1 and the tvv.value of tvv.tmplvarid = 3 is a date greater then or equal to today.
So basically each modx_site_content.id that is published an has a parent of '24' will have at least 2 entries in the modx_site_tmplvar_contentvalues table one with an tmplvarid of '1' whose value will be a comma separated list and another with a tmplvarid of '3' which will be a datestamp.
I need to select all the values from the modx_site_tmplvar_contentvalues table where the tmplvarid is '1' [the comma separated list], where the second entry tmplvarid equaling '3' is a date greater than equal to today and the modx_site_content conditions are published = '1' and parent = '24'
Here is my query [that does not work]
SELECT sc.id, sc.pagetitle, tvv.value, tvv.tmplvarid, tvv.id
FROM modx_site_content sc
left join modx_site_tmplvar_contentvalues tvv on tvv.contentid = sc.id
where published = '1'
and parent = '24'
and (tvv.tmplvarid = '3' or tvv.tmplvarid = '1')
and tvv.value >= curdate()
group by sc.id
order by sc.id
Any help?
If my understanding is correct, you want to get data based on 2 conditions:
- tmplvarid = '1'
- tmplvarid = '3' and value >= curdate()
If so, try this:
SELECT sc.id, sc.pagetitle, tvv.value, tvv.tmplvarid, tvv.id
FROM modx_site_content sc
left join modx_site_tmplvar_contentvalues tvv on tvv.contentid = sc.id
where published = '1'
and parent = '24'
and ((tvv.tmplvarid = '3' and tvv.value >= curdate()) or (tvv.tmplvarid = '1'))
order by sc.id
Correct me if I misunderstand your question.

Combining two queries in mySQL

I'm trying to combine the results of two queries. I'm not very proficient in mysql so I'm here for some help.
The first query is as follows:
select count(roomtypeid) as bookedrooms, day
from event_guest_hotel
where hotelid = 1 and roomtypeid = 1
group by day;
This returns:
The second query:
SELECT ehr.reservationid, ehr.day, h.name AS hotelname,
ehr.totalrooms as requested_rooms, r.name AS roomname
FROM event_hotel_reservation ehr
INNER JOIN hotel_room_type r
ON ehr.roomtypeid = r.roomtypeid
INNER JOIN hotel h
ON ehr.hotelid = h.hotelid
WHERE totalRooms != 0
AND reservationID = '1'
This returns:
Can I combine the first query with the second one, so I get the results of the first one in another resultcolumn next to 'roomname'? That way I know how many rooms are already booked and how many were originally requested from one single query.
Try:
SELECT ehr.reservationid, ehr.day, h.name AS hotelname,
ehr.totalrooms as requested_rooms, r.name AS roomname,
egh.bookedrooms
FROM event_hotel_reservation ehr
INNER JOIN hotel_room_type r ON ehr.roomtypeid = r.roomtypeid
INNER JOIN hotel h ON ehr.hotelid = h.hotelid
left outer join (
select hotelid, count(roomtypeid) as bookedrooms, day
from event_guest_hotel
where roomtypeid = 1
group by hotelid, day
) egh on h.hotelid = egh.hotelid and ehr.day = egh.day
WHERE totalRooms != 0
AND reservationID = '1'