mysql query using values (no subselect) - sql

Due to the permanent use of ORM I have no idea how to write this query, but I need to write it without ORM.
tables design:
users:
|id|username|...
ports:
|id|user_id|port|
My app gets a username, now I need to find all ports for the matching username using the id of the user to get the ports.

Do a JOIN to find the ports for the user specified by userparam (or whatever you call it.):
select u.id, u.username, p.id, p.user_id, p.port
from users u
join ports p on u.id = p.user_id
where u.username = :userparam
(You can remove the columns you don't need from the SELECT list.)

users:
id|username|...
ports:
id|user_id|port|
think about the SELECT line last. just put a place holder to begin
select count(*)
then actually begin. ask what tables do I need to get data FROM?
FROM users, ports
this is going to (conceptually) make a new table with rows that have every user matched up with every port.
how do I filter out all of the data in this new table that does not
apply to my query? ignore everything except WHERE you tell it to match
WHERE user.id == ports.user_id
you can think of this is as filtering for rows in the giant table made from all the rows of all the tables you put in the FROM clause.
Now that you have these rows of everything you can SELECT which columns from the new table you made that you are interested in.
lets say you want any port.id (s) returned.
SELECT port.id
FROM users, ports
WHERE user.id == ports.user_id
A nicer syntax that keeps the WHERE parts near their FROM parts
which gets important when you have lots of tables looks like this
SELECT port.id
FROM users join ports ON user.id == ports.user_id

Related

SQL query to exclude records that are part of a group

I can't believe this hasn't been answered elsewhere, but I don't seem to know the right words to convey what I'm trying to do. I'm using Ruby/Rails and PostgreSQL.
I have a bunch of Users in the DB that I'm trying to add to a Group based on a name search. I need to return Users that do not belong to a particular Group, but there is a join table as well (UserGroups, with the appropriate FKs).
Is there a simple way to use this configuration to perform this query without having to result to grabbing all the Users from which belong to the group and doing something like .where.not(id: users_in_group.pluck(:id)) (these groups can be pretty huge, so I don't want to send that query to the DB on a text search as the user types).
I need to return Users that do not belong to a particular Group
SELECT *
FROM users u
WHERE username ~ 'some pattern' -- ?
AND NOT EXISTS (
SELECT FROM user_groups ug
WHERE ug.group_id = 123 -- your group_id to exclude here
AND ug.user_id = u.id
);
See:
Select rows which are not present in other table

How to use joins to cross check data from multiple tables

I got a few tables which I need to query to crosscheck information.
All tables are in the same database.
First table is named Confirmedsitesv2 and contains a column named sites.
Sedond table is named Standardwithmail and contains three columns. sites, username and mail.
Third table named CDDump contains alot of columns but there is only three I am intrested in. Uid, employeenddate and company.
I need to query so I get site, username and mail based on the following criteria.
Site from standardwithmail matches site in confirmedsitesv2, username from standardwithmail matches uid in CDDUmp, while the employmentenddate = 0 and company is not like %test%. Mail should not be matched with anything as it only occurs in standardwithmail but will show for all the hits from the query.
So I tryed to get my head around this with left joins for nearly two hours.
Anyone experienced who can who can explain how I should use join in this situation? I done outer joins before for totaly different case and that worked easy and fine, but can't get my head around this even after alot of time on google.
If needed I can create some fake tables and upload pictures as I can't show the real data here.
Please try this:
SELECT cfrsites.sites standard.username,
standard.mail
FROM Confirmedsitesv2 cfrsites,
Standardwithmail standard,
CDDump cd
where cfrsites.sites = standard.site
and standard.username = cd.Uid
If you can edit your post, add the Table structure and add some insert statements that will be helpful
So why mail did not work was because it's in the the big table I only used for other information, I renamed that column in standardwithmail and I ran:
select site, username, mailaddress
from Standardwithmail
left join CDDump on CDDump.uid = dbo.Standardwithmail.Username where Site in (select Site from Confirmedsitesv2) and employmentEnd like '0' and companyName not like '%test%'
order by Site;
Try out the following query. You don't need outer join or left join, but just inner joins since you only want matching records.
SELECT swm.username,
swm.mail
FROM standardwithmail swm
INNER JOIN confirmedsitesv2 csv2
ON swm.sites = csv2.sites
INNER JOIN cddump cdd
ON swm.username = cdd.uid
WHERE cdd.employmentenddate = 0
AND
cdd.company NOT LIKE '‰test‰'

Select a user by their username and then select data from another table using their UID

Sorry if that title is a bit convoluted... I'm spoiled by an ORM usually and my raw SQL skills are really poor, apparently.
I'm writing an application that links to a vBulletin forum. Users authenticate with their forum username, and the query for that is simple (selecting by username from the users table). The next half of it is more complex. There's also a subscriptions table that has a timestamp in it, but the primary key for these is a user id, not a username.
This is what I've worked out so far:
SELECT
forum.user.userid,
forum.user.usergroupid,
forum.user.password,
forum.user.salt,
forum.user.pmunread,
forum.subscriptionlog.expirydate
FROM
forum.user
JOIN forum.subscriptionlog
WHERE
forum.user.username LIKE 'SomeUSER'
Unfortunately this returns the entirety of the subscriptionlog table, which makes sense because there's no username field in it. Is it possible to grab the subscriptionlog row using the userid I get from forum.user.userid, or does this need to be split into two queries?
Thanks!
The issue is that you are blindly joining the two tables. You need to specify what column they are related by.
I think you want something like:
SELECT * FROM user u
INNER JOIN subscriptionlog sl ON u.id = sl.userid
WHERE u.username LIKE 'SomeUSER'
select * from user u JOIN subscriptions s ON u.id = s.id where u.username = 'someuser'
The bit in bold is what you want to add, it combines the 2 tables into one that you return results from.
try this
SELECT
forum.user.userid,
forum.user.usergroupid,
forum.user.password,
forum.user.salt,
forum.user.pmunread,
forum.subscriptionlog.expirydate
FROM
forum.user
INNER JOIN forum.subscriptionlog
ON forum.subscriptionlog.userid = forum.user.userid
WHERE
forum.user.username LIKE 'SomeUSER'

SQL query join different tables based on value in a given column?

Well I am designing a domain model and data mapper system for my site. The system has different kind of user domain objects, with the base class for users with child classes for admins, mods and banned users. Every domain object uses data from a table called 'users', while the child classes have an additional table to store admin/mod/banned information. The user type is determined by a column in the table 'users' called 'userlevel', its value is 3 for admins, 2 for mods, 1 for registered users and -1 for banned users.
Now it comes a problem when I work on a members list feature for my site, since the members list is supposed to load all users from the database(with pagination, but lets not worry about this now). The issue is that I want to load the data from both the base user table and additional admin/mod/banned table. As you see, the registered users do not have additional table to store extra data, while for admin/mod/banned users the table is different. Moreover, the columns in these tables are also different.
So How am I supposed to handle this situation using SQL queries? I know I can simply just select from the base user table and then use multiple queries to load additional data if the user level is found to be a given value, but this is a bad idea since it will results in n+1 queries for n admins/mods/banned users, a very expensive trip to database. What else am I supposed to do? Please help.
If you want to query all usertypes with one query you will have to have the columns from all tables in your result-table, several of them filled with null-values.
To get them filled with data use a left-join like this:
SELECT *
FROM userdata u
LEFT OUTER JOIN admindata a
ON ( u.userid = a.userid
AND u.usertype = 3 )
LEFT OUTER JOIN moddata m
ON ( u.userid = m.userid
AND u.usertype = 2 )
LEFT OUTER JOIN banneddata b
ON ( u.userid = b.userid
AND u.usertype = -1 )
WHERE...
You could probably drop the usertype-condition, since there should only be data in one of the joined tables, but you never know...
Then your program-code will have the job to pick the correct columns based on the usertype.
P.S.: Not that select * is only for sake of simplicity, in real code better list all of the column-names...
While is totally fine having this hierarchy in your domain classes, I would suggest changing the approach in your database. Otherwise your queries are going to be very complex and slow.
You can have just another table called e.g. users_additional_info with the mix of the columns that you need for all your user types. Then you can do
SELECT * FROM users
LEFT JOIN users_additional_info ON users.id = users_additional_info.user_id
to get all the information in a single simple query. Believe me or not, this approach will save you a lots of headaches in the future when your tables start to grow or you decide to add another type of user.

How to show values from two different queries?

I have one database that contains all of user information including name. Then there is a second database that contains notes from the users and it contains the #id but not the name. The query i am doing to retrieve user notes doesn't have name so all its doing is showing the notes, then right under it i am doing another query to retrieve the name from the first database using the common #id. But it won't show.
Is there a way I can do this query in one? Please help. Thanks.
Use:
SELECT u.name,
n.*
FROM DB2.NOTES n
LEFT JOIN DB1.USERS u ON n.id = u.id
ORDER BY u.name
Assuming the connection credentials has access to both databases, you prefix the database name in front of the table name and separate with a period.
The LEFT JOIN will show both users, and notes without users associated. Here's a good primer on JOINs.
You might need to show your code, but you can write queries against two databases (or schemas) on the same host, just qualify the table names with the database name, e.g.
SELECT db1.user.id, db1.user.name, db2.userinfo.notes
FROM db1.user
INNER JOIN db2.userinfo ON(db1.user.id=db2.userinfo.id)
The credentials you are connecting with must have access to both databases for this to work of course.