There are three tables:
events, users, and subscriptions
I am trying to query the database to extract some fields (see select statement).
Users table relationships:
Linked to subscriptions by user_id (not every user has a subscription_id)
Linked to events by user_id (not every user has an event)
The problem is that not every user has a corresponding entry in the subscriptions table. I would like to display all users that have an event - whether they have a subscription or not.
SELECT subscriptions.plan, subscriptions.created_at, subscriptions.expires_at, users.first_name, events.subdomain, events.heading
FROM users
LEFT OUTER JOIN subscriptions ON users.id = subscriptions.user_id
LEFT OUTER JOIN events ON users.id = events.user_id
UNION
SELECT subscriptions.plan, subscriptions.created_at, subscriptions.expires_at, users.first_name, events.subdomain, events.heading
FROM users
RIGHT OUTER JOIN subscriptions ON users.id = subscriptions.user_id
RIGHT OUTER JOIN events ON users.id = events.user_id
This query takes a while to run, but seems to yield double results for some events.
Currently it returns all users, and sometimes duplicate entries per event (which is not the case in the actual DB). Any help is appreciated!
Related
Im trying to show a full list of all users in my DB aswell as extra information from a second table depending on whether they have a record in the second table
Im using MySQL, ive tried a few left join/right join union combos but nothing i have works
SELECT users.id, users.name, success.URL_ID, success.docreqid FROM users
LEFT JOIN success ON users.id = success.userid
where docreqid IS NULL
union
SELECT users.id, users.name, success.URL_ID, success.docreqid FROM users
RIGHT JOIN success ON users.id = success.userid
where docreqid = 1;
I have a small table of 10 users. Only one user in my db has a record in the success tbl against docreqid '1'.
I want a table of ALL users and the URL_ID for their form if they have submitted it.
The above code works perfectly for this.
If i change the last line to:
where docreqid = 2;
I only get 9 results (the user with a record for docreqid '1' is missing).
I would like this table to show all 10 users and 'NULL' in the URL_ID & docreqid columns until they have completed the required action.
A left join should do what you want:
SELECT u.id, u.name, s.URL_ID, s.docreqid
FROM users u LEFT JOIN
success s
ON u.id = s.userid AND s.docreqid = 1;
The LEFT JOIN returns all rows in the first table -- no WHERE is filtering results. The ON only matches rows in success that meet the additional condition in the ON clause.
I wanna have a bidirectional relationship between my two tables that are related by a one to many relationship.
So, i have a User table, with columns such as user_id, and transaction_id etc (and other user datails columns).
I have another table called transaction which has columns like transaction_id and user_id (to refer to the user this particular transaction belongs to).
Now, the issue is, a particular user can have multiple transactions attached to them, which means, this transaction table can have multiple rows for the same user. This makes it easy for me to get user details via join query. But I want to make this relationship bi-directional.
As in, if all i have is user details, i should be able to get the transaction details of that person. but since, a user can have multiple transactions at once, I'm not able to write a join query.
As such, I am yet to figure out how to store two transaction id's for a particular user, keeping in mind that i should be able to make a join query having the user details (I could always store transaction id's in the form of an array, but that won't let my join query happen).
Assuming this table structures :
transactions
id
user_id
tdate
amount
user
id
name
email
you seem to be already aware that you can list all transactions of a user, along with his information, with :
SELECT
u.id,
u.name,
u.email,
t.id,
t.tdate,
t.amount
FROM
users u
INNER JOIN transactions t ON t.user_id = u.id
WHERE
u.id = ?
ORDER BY
u.id,
t.tdate
The question mark represents the id of the user whose transactions you want to see. This returns one record for each transaction of the user.
If you are looking to, for a given transaction, list all other transactions of the same user, then one solution is to add another join to the query : basically, this would first retrieve the given transaction by id (t0), and then list all transactions by the same user (t).
SELECT
u.id,
u.name,
u.email,
t.id,
t.tdate,
t.amount
FROM
users u
INNER JOIN transactions t0 ON t0.user_id = u.id
INNER JOIN transactions t ON t.user_id = u.id
WHERE
t0.id = ?
ORDER BY
u.id,
t.tdate
I manage a property website. I have a table with banned users (small table) and a table called advert_views which keeps track of each listing that each user views (currently 1.3m lines and growing). The advert_views table alsio takes note of the IP address for every advert viewed).
I want to get the IP addresses used by the banned users and check if any of these banned users have opened new accounts. I ran the following query:
SELECT adviews.user_id AS 'banned user_id',
adviews.client_ip AS 'IPs used by banned users',
adviews2.user_id AS 'banned users that opened a new account'
FROM banned_users
LEFT JOIN users on users.email_address = banned_users.email_address #since I don't store the user_id in banned_users
LEFT JOIN advert_views adviews ON adviews.user_id = users.id AND adviews.user_id IS NOT NULL # users may view listings when not logged in but they have restricted access to the information on the listing
LEFT JOIN (SELECT client_ip,
user_id
FROM advert_views
WHERE user_id IS NOT NULL
) adviews2
ON adviews2.client_ip = adviews.client_ip
WHERE banned_users.rec_status = 1 and adviews.user_id <> adviews2.user_id
GROUP BY adviews2.user_id
I applied an index on the advert_views table and the users table as per below:
enter image description here
My query takes half an hour to execute. Is there a way how to improve my query speed?
Thanks!
Chris
First of all: Why do you outer join the tables? Or better: Why do you try to outer join the tables? A left join is meant to get data from a table even when there is no match. But then your results could contain rows with all values null. (That doesn't happen though, because adviews.user_id <> adviews2.user_id in your where clause dismisses all outer-joined rows.) Don't give the DBMS more work to do than necessary. If you want inner joins, then don't outer join. (Though the difference in execution time won't be huge.)
Next: You select from banned_users, but you only use it to check existence. You shouldn't do this. Use an EXISTS or IN clause instead. (This is mainly for readability and in order not to produce duplicate results. This probably won't speed things up.)
SELECT av1.user_id AS 'banned user_id',
av2.client_ip AS 'IPs used by banned users',
av2.user_id AS 'banned users that opened a new account'
FROM adviews av1
JOIN adviews av2 ON av2.client_ip = av1.client_ip AND av2.user_id <> av1.user_id
WHERE av1.user_id IN
(
SELECT user_id
FROM users
WHERE email_address IN (select email_address from banned_users where rec_status = 1)
)
GROUP BY av2.user_id;
You may replace the inner IN clause with a join. It's mostly a matter of personal preference, but it is also that in the past MySQL sometimes didn't perform well on IN clauses, so many people made it a habit to join instead.
WHERE av1.user_id IN
(
SELECT u.user_id
FROM users u
JOIN banned_users bu ON bu.email_address = u.email_address
WHERE bu.rec_status = 1
)
At last consider removing the GROUP BY clause. It reduces your results to one row per reusing user_id, showing one of its related banned user_ids (arbitrarily chosen in case there is more than one). I don't know your tables. Are you getting many records per reusing user_id? If not, remove the clause.
As to indexes I suggest:
banned_users(rec_status, email_address)
users(email_address, user_id)
adviews(user_id, client_ip)
adviews(client_ip, user_id)
So I have three tables; users, events and user_events.
Users-table stores all the information about user, events table will store all the events which can be viewed by all the users plus a foreign key row of user's id so that the app can know who created that particular event. Last table, user_events, stores event_id and user_id. I need to do join these three tables together so that i can get a result if that particular user is attending into that particular event.
So far I've tried with this query without any luck:
SELECT events.*, user_events.user_id AS attending FROM events
LEFT JOIN users ON users.user_id = events.creatoruserid
LEFT JOIN user_events ON user_events.user_id = users.user_id;
The concept is that I need to do a check within my app and check if user is attending in that particular event and if so, he/she can remove the attendance and vice versa.
It looks like the event creator is getting mixed into the query while you are trying to grab the attendees. It also seems like you don't need to join with the users table, since none of the fields are used.
SELECT events.*, user_events.user_id AS attending FROM events
LEFT JOIN user_events ON user_events.event_id = events.event_id;
Edit:
If you want only the events for a single user
SELECT events.*, user_events.user_id AS attending FROM events
LEFT JOIN user_events ON user_events.event_id = events.event_id
WHERE user_events.user_id = ?1;
AND events.event_id = ?2;
Where ?1 is the id of the user you want to check and ?2 is the id of the event you want to see if the user is attending
I have a dilemma.
Let's assume(for simplicity's sake) I have four tables, with different numbers of columns and rows, they are: users, mail, events and service.
When I receive a request, I have an ID that links on three of those tables, but with different columns it matches to.
Let's say, users matches on user_id, mail matches on user_ref and events matches on user_ref as well.
That would've been a fine query for me to write up, even with single, multiple or even all IDs.
The problem arrives on the next step I have to take, and that's the *service table.
The service table doesn't conform to the same standards of the others, thus it does not have an user_id, or user_ref that can be pulled.
What it has instead, is a *mail_ref* column, and it has the potential to contain duplicates.
My current method is trying to use an IN() method, but it only works for selecting a single user/row.
Here's my current query:
SELECT
u.Name as Name,
COUNT(m.user_ref) AS Mail_total,
e.mail_id,
COUNT(e.user_ref) AS Event_total,
COUNT(s.mail_ref) AS service_total
FROM
users u
LEFT JOIN
mail m ON m.user_ref = u.user_id
LEFT JOIN
service s ON s.mail_ref IN(e.mail_id)
LEFT JOIN
events e ON e.user_ref = u.user_id
WHERE u.user_id IN(my,list,of,ids)
GROUP BY s.mail_ref
The problem I have with it currently, is that although it's selecting the correct data, it's not selecting unique data for every id I specify.
It works marginally fine when given a single id, but as mentioned above, not when it has to retrieve multiple rows.
If anyone could help me out it would be much appreciated.
Do a subquery in the left join for service. Instead of:
LEFT JOIN
service s ON s.mail_ref IN(e.mail_id)
Try
LEFT JOIN
(select TOP 1 mail_ref from server) as S on s.mail_ref = e.mail_id
See if that works.
SELECT
u.Name as Name,
(select count(*) from mail m where m.user_ref = u.user_id) AS Mail_total,
e.mail_id,
(select count(*) from events e where e.user_ref = u.user_id) AS Event_total,
(select count(*) from
events e
inner join services s on s.mail_ref = e.mail_id
where
e.user_ref = u.user_id) as service_total
FROM
users u
WHERE u.user_id IN(my,list,of,ids)