I have a table of members and a table of venues.
I currently have this select statement:
SELECT VenueName, VenueID
FROM Venue
WHERE active='Y'
ORDER BY VenueName
The result of this statement is used to populate a drop down list with venue names, which works. I'll call it "ORIGINAL SELECT".
I want to change this so the dropdown list only shows venue names linked to the member:
SELECT Venue.VenueName, Venue.VenueID, members.id, members.venueid
FROM Venue, members
WHERE Venue.VenueID = members.venueid
AND members.id='$userid'
This also works. I'll call it "NEW SELECT".
I have two superadmins whose members.venueid is all rather than a venue id number, so I would like to create a statement that runs the NEW SELECT else if members.id='all' then run ORIGINAL SELECT.
Can anyone point me in the right direction? I've tried various things.
You could try something similar to the following:
SELECT Venue.VenueName, Venue.VenueID
FROM Venue, members
WHERE
(
Venue.VenueID = members.venueid
AND $userid <> 'all'
AND members.id = 'all'
)
OR
(
Venue.VenueID = members.id
AND $userid = 'all'
AND members.id = 'all'
)
Thanks #Chris you pointed me in the right direction, below is the final version that I got working:
SELECT DISTINCT Venue.VenueName, Venue.VenueID
FROM Venue, members
WHERE (
'$userid' = 'all'
AND active = 'Y'
)
OR (
Venue.VenueID = members.venueid
AND members.id = '$userid'
)
ORDER BY VenueName
Related
I've a SELECT which checks a status of active alarms (icinga).
This select joins different tables and until here all ok.
On the result I've as value/column an object_id as well. I would like to add a column to that select that could be empty or not, because, searching that 'object_id' on a different table, I could get a value or not. This accessory table is structured having: object_id, varname, varvalue.
So, i.e., my SELECT returns those values:
`name`, `object_id`, `status`
`Hello`, `123456`, `OK`
I would add the column City that should compared to a table having:
`object_id`, `varname`, `varvalue`
`123456`, `city`, `Rome`
`123456`, `lake`, `Garda`
`789789`, `city`, `Milano`
So that if the second table has object_id = 123456 AND city = Rome the result should be:
`name`, `object_id`, `status`, `city`
`Hello`, `123456`, `OK`, `Rome`
Otherwise the result should be:
`Hello`, `123456`, `OK`, `UNKNOWN`
How to do that?
Hope I've explained it well :-)
Thanks!
* EDIT *
It's better I explain with real example. My query actually is the following:
select icinga_objects.object_id, icinga_objects.name1 as host_name, icinga_objects.name2 as ServiceName, "service" as Type, icinga_servicestatus.last_check as LastCheckTime, icinga_servicestatus.last_hard_state_change as LastStateChange, TIMEDIFF(now(), icinga_servicestatus.last_hard_state_change) AS SinceTime,
CASE
WHEN icinga_servicestatus.current_state = 0 THEN '0'
WHEN icinga_servicestatus.current_state = 1 THEN '2'
WHEN icinga_servicestatus.current_state = 2 THEN '3'
ELSE '3'
END AS state
FROM icinga_objects, icinga_servicestatus, icinga_services WHERE icinga_servicestatus.service_object_id IN
(SELECT service_object_id FROM icinga_services WHERE icinga_services.host_object_id IN
(SELECT host_object_id FROM icinga_hostgroup_members WHERE hostgroup_id IN
(SELECT hostgroup_id FROM icinga_hostgroups WHERE alias = 'MY-HOSTGROUP-TO-FILTER')
)
)
AND icinga_servicestatus.service_object_id NOT IN
(SELECT service_object_id FROM icinga_services WHERE icinga_services.service_object_id IN (
SELECT object_id FROM icinga_objects WHERE icinga_objects.is_active = 1 AND icinga_objects.object_id IN
(SELECT object_id FROM icinga_customvariables WHERE varvalue = '8x5')
)
)
AND icinga_servicestatus.last_check > NOW() - INTERVAL 3 HOUR
AND icinga_servicestatus.state_type = 1
AND icinga_servicestatus.scheduled_downtime_depth = 0
AND icinga_objects.object_id = icinga_services.service_object_id
AND icinga_servicestatus.service_object_id = icinga_services.service_object_id
AND icinga_servicestatus.current_state = 2
AND icinga_servicestatus.problem_has_been_acknowledged = 0
This gives me as result, in example:
`object_id`, `host_name`, `ServiceName`, `Type`, `LastCheckTime`, `LastStateChange`, `SinceTime`, `State`
`123456`, `myHostName`, `myServiceName`, `service`, `2020-04-29 17:19:21`, `2020-04-28 14:50:27`, `26:32:51`, `3`
Here I would like to add the column.
So, now if I search object_id into icinga_customvariables I could find entries, or not. In Example, searching object_id = 123456 I have 4 records, but ONLY one having varname = NAME_IM_SEARCHING and so I need to add to the above result the corresponding of varvalue searching icinga_customvariables.object_id = '123456' AND varname = NAME_IM_SEARCHING. IF there are NO results, then the added cloumn should be UNKNOWN, otherwise the added column should be = icinga_customvariables.varvalue.
How to add it? :-)
You can place your query into a "table expression" so it becomes simpler to join it to the other_table. For example:
select
q.*,
coalesce(o.varvalue, 'UNKNOWN') as city
from (
-- your existing query here
) q
left join other_table o on o.object_id = q.object_id and o.varname = 'city'
EDIT: Joining multiple times
As requested if you need to extract more city names using another column, or if you want to extract against another table altogether, you can add an extra LEFT JOIN. For example:
select
q.*,
coalesce(o.varvalue, 'UNKNOWN') as city,
coalesce(o2.varvalue, 'UNKNOWN') as lake
from (
-- your existing query here
) q
left join other_table o on o.object_id = q.object_id and o.varname = 'city'
left join other_table o2 on o.object_id = q.object_id and o2.varname = 'lake'
I am trying to achieve the comment (title) written on the most recent day (review_date) from each user (username) in the database
My code is :
select tb1.*, tb2.* from
(select username, via_mobile as pc, max(review_date) as pcdate from tripadvisor where username != "" and via_mobile='false' group by username) tb1
join
(select username, via_mobile as mobile, max(review_date) as mobile from tripadvisor whereusername != "" and via_mobile='true' group by username) tb2
on tb1.username = tb2.username;
The problem is I cannot get the right review for the right date.
For example :
username; review_date; title
Alan; 2012-12-18 ;"If..."
But it should display Alan; 2012-12-18; "Nice hotel"
Can you help me to fix the code.
Your question is a little unclear, but if I understand correctly, you're looking for each full row with the highest date, selected distinctly/grouped by username? This should give you that:
SELECT
username,
review_date,
title
FROM
tripadvisor AS ta
INNER JOIN (
SELECT
username,
max(review_date) AS review_date
FROM
tripadvisor
GROUP BY
username
) AS max_table
ON ta.username = max_table.username
AND ta.review_date = max_table.review_date;
WHERE
username != ''
-- any extra where clauses go here
See: How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?
If the goal is to return the most recent review title for "mobile" and for "pc", I'd do something like this:
SELECT q.username
, MAX(q.pc_date) AS pc_date
, MAX(p.title) AS pc_title
, MAX(q.mobile_date) AS mobile_date
, MAX(r.title) AS mobile_title
FROM ( SELECT t.username
, MAX(IF(t.via_mobile='false',t.review_date,NULL) AS pc_date
, MAX(IF(t.via_mobile='true',t.review_date,NULL) AS mobile_date
FROM tripadvisor t
WHERE t.username <> ''
AND t.via_mobile IN ('true','false')
GROUP
BY t.username
) q
LEFT
JOIN tripadvisor p
ON p.username = q.username
AND p.review_date = q.pc_date
AND p.via_mobile = 'false'
LEFT
JOIN tripadvisor r
ON r.username = q.username
AND r.review_date = q.mobile_date
AND r.via_mobile = 'true'
GROUP
BY q.username
If the user has only "mobile" reviews and no "pc" reviews, this query will return a row, but with NULL values for the "pc" columns. Similarly, the query will return NULL values for the "mobile" columns for a user that has only "pc" reviews.
The query could easily be changed to only returns rows for users that have both "mobile" and "pc" reviews, to be closer to the original using the INNER JOIN.
If the goal is simpler, just to return just the most recent review...
SELECT r.username
, r.review_date
, MAX(r.title) AS title
, MAX(r.via_mobile) AS via_mobile
FROM ( SELECT t.username
, MAX(t.review_date) AS max_review_date
FROM tripadvisor t
WHERE t.username <> ''
AND t.via_mobile IN ('true','false')
GROUP
BY t.username
) q
JOIN tripadvisor r
ON r.username = q.username
AND r.review_date = q.max_review_date
AND r.via_mobile IN ('true','false')
GROUP
BY r.username
, r.review_date
The results of this query are somewhat indeterminate when a username has multiple rows with identical (most recent) review_date. This guarantees a single row will be returned, but the title and via_mobile may not be from the same row.
Your question could be expressed as an existence test: show the rows for which the review date matches the latest review date for that user.
Existence is tested with EXISTS in a correlated subquery:
SELECT * FROM tripadvisor as T
where exists (
select 1 from tripadvisor
where username = T.username
group by username
having MAX(review_date) = T.review_date
);
I have 3 tables; events, memberEvents, and members.
Events: eventId, eventName, eventDivision
memberEvents: memberID, eventOne, eventTwo, eventThree, eventFour, eventFive
member: memberID, memberFirstName, memberLastName
I am trying to get it to display events.eventName followed by the memberFirstName & memberLastName of members that are doing that event
This is the query I have been trying:
SELECT * FROM events, memberEvents, members
WHERE events.eventDivision = 'C'
RIGHT JOIN memberEvents.memberID
ON events.eventID = memberEvents.eventOne
OR events.eventID = memberEvents.eventTwo
OR events.eventID = memberEvents.eventThree
OR events.eventID = memberEvents.eventFour
OR events.eventID = memberEvents.eventFive
When I run this i get "#1066 - Not unique table/alias: 'memberEvents'"
Try:
SELECT ev.*, me.* FROM events ev
RIGHT JOIN memberEvents me
ON (ev.eventID = me.eventOne
OR ev.eventID = me.eventTwo
OR ev.eventID = me.eventThree
OR ev.eventID = me.eventFour
OR ev.eventID = me.eventFive)
WHERE ev.eventDivision = 'C'
Did you specifically want to limit the number of events per member to five? Why not just have a memberEvent table that has a primary key made up of foreign keys to member and event?
memberEvent: memberId, eventId
Then your query would be
SELECT
event.eventName,
member.memberFirstName,
member.memberLastName
FROM
event
INNER JOIN
memberEvent
ON
memberEvent.eventID = event.eventId
INNER JOIN
member
ON
memberEvent.memberId = member.memberId
WHERE
event.division = 'C';
Maybe you have a good reason for the table structure you have chosen but it is a denormalised design and if you ever need to increase the number of events per member you'll need to modify your schema and code to suit.
I think you should have a closer look at the defenition
JOIN Syntax
It seems that you have misunderstood the JOIN syntax.
SELECT *
FROM table1 t1 right join
table2 t2 on t1.key1 = t2.key1
and t1.key2 = t2.key2
where t1.somecolumn = somevalue
I have three tables:
$sTable = a table of songs (songid, mp3link, artwork, useruploadid etc.)
$sTable2 = a table of projects with songs linked to them (projectid, songid, project name etc.)
$sTable3 = a table of song ratings (songid, userid, rating)
All this data is output to a JSON array and displayed in a table in my application to provide a list of songs, combined with the projects and ratings data.
What I want to be able to do is check to see if the "logged in user" has voted on a particular song so that I can add a class of 'voted' to the parent element of the returned data.
I would lke to do this in the most permance optimal way which I would guess would be to return a boolean value (1 or 0) with 1 being voted and 0 being returned otherwise.
I can then use javascript to apply the class client side.
The 'logged in user id' is stored in my PHP script as $loggedin_ID so I need to simply check this variable against the column 'userid' of $sTable3 for a given songid and return a new column (I would imagine using AS) with a result of 1 if there is a matching entry for that songid and 0 if there is not.
How would I go about modifying my query to add this?
The above are just my thoughts and there may indeed be a far better/more effecient method. If so please do not hesitate to provide what you think might be a better solution to achieving this functionality.
Below is my current query. Thanks.
$sQuery = "SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
FROM $sTable b
LEFT JOIN (
SELECT COUNT(*) AS projects_count, a.songs_id
FROM $sTable2 a
GROUP BY a.songs_id
) bb ON bb.songs_id = b.songsID
LEFT JOIN (
SELECT AVG(rating) AS rating, COUNT(rating) AS ratings_count,c.songid
FROM $sTable3 c
GROUP BY c.songid
) bbb ON bbb.songid = b.songsID
May be you are looking for something like this:
select s.songid, s.userid,
case when exists
(
select songid
from sTable3
where songid = $songid
) Then 'Voted'
else
(
'Not Voted'
)
end
as 'Voted or Not'
from sTable3 s
where s.userid = $userid
I have the logic worked out, just not sure how to best write this query.
the logic is
we have a deal ID of 1
a deal is linked to multiple regions
a deal is linked to multiple interests
a user is linked to multiple regions
a user is linked to multiple interests
we want all users where....
the user is linked to the same region as a deal
userRegionLink url, dealRegionLink drl
url.regionId is in drl.regionId where drl.dealId = 1
the user is linked to the same interest as a deal
userInterestLink uil, dealInterestLink dil
uil.interestId is in dil.interestId where dil.dealId = 1
this would give us a list of the users
now we need to select distinct from the list so we only end up sending each user a single email
But I have no idea what the best way to write this query would be.
We are dealing with a few tables here
We have
users which has all the user Information in it userId and other columns not important
userInterestLink which has userId and interestId
dealInterestLink which has dealId and interestId
userRegionLink which has userId and regionId
dealRegionLink which has dealId and regionId
so what we are wanting in the end is all the user info which matches.
I take RC's answer and modify it
SELECT u.userId, uil.interestId, url.regionId FROM users u
JOIN userInterestLink uil ON (uil.userId = u.userId)
JOIN userRegionLink url ON (url.userId = u.userId)
WHERE interestId IN (
SELECT DISTINCT interestId FROM dealInterestLink WHERE dealId = 1
) AND regionId IN (
SELECT DISTINCT regionId FROM dealRegionLink WHERE dealId = 1
)
as there is no need for LEFT JOIN if I exclude the NULL rows afterwards.
A more "symmetric" version without subqueries and with USING would be
SELECT u.userId, uil.interestId, url.regionId FROM users u
JOIN userInterestLink uil USING (userId)
JOIN userRegionLink url USING (userId)
JOIN dealInterestLink dil USING (interestId)
JOIN dealRegionLink drl USING (regionId, dealId)
WHERE dealId = 1
Untested as well.
Something like:
SELECT u.userId, uil.interestId, url.regionId FROM users u
LEFT JOIN userInterestLink uil ON (uil.userId = u.userId)
LEFT JOIN userRegionLink url ON (url.userId = u.userId)
WHERE uil.interestId IS NOT NULL AND uil.interestId IN (
SELECT DISTINCT interestId FROM dealInterestLink WHERE dealId = 1
) AND url.regionId IS NOT NULL AND url.regionId IN (
SELECT DISTINCT regionId FROM dealRegionLink WHERE dealId = 1
)
? If result is OK, you can then SELECT DISTINCT u.userId FROM users u -- ...
(not tested)
SELECT `u`.*
FROM `users` AS `u`
JOIN `userRegionLink` `userReg` USING ( `userId` )
JOIN `userInterestLink` `userInt` USING ( `userId` )
JOIN `dealInterestLink` `dealInt` USING ( `interestId` )
JOIN `dealRegionLink` `dealReg` USING ( `regionId` )
JOIN `deal` `d` ON ( `dealInt`.`dealId` && `dealReg`.`dealId` && `d`.`dealId` = 1 )
GROUP BY `u`.`userId`
Tested locally using dummy data and presumed schema. Worked OK.