The query I am trying to perform is
With getusers As
(Select userID from userprofspecinst_v where institutionID IN
(select institutionID, professionID from userprofspecinst_v where userID=#UserID)
and professionID IN
(select institutionID, professionID from userprofspecinst_v where userID=#UserID))
select username from user where userID IN (select userID from getusers)
Here's what I'm trying to do. Given a userID and a view which contains the userID and the ID of their institution and profession, I want to get the list of other userID's who also have the same institutionID and and professionID. Then with that list of userIDs I want to get the usernames that correspond to each userID from another table (user). The error I am getting when I try to create the procedure is, "Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.". Am I taking the correct approach to how I should build this query?
The following query should do what you want to do:
SELECT u.username
FROM user AS u
INNER JOIN userprofspecinst_v AS up ON u.userID = up.userID
INNER JOIN (SELECT institutionID, professionID FROM userprofspecinst_v
WHERE userID = #userID) AS ProInsts
ON (up.institutionID = ProInsts.institutionID
AND up.professionID = ProInsts.professionID)
Effectively the crucial part is the last INNER JOIN statement - this creates a table constituting the insitutionsids and professsionids the user id belongs to. We then get all matching items in the view with the same institution id and profession id (the ON condition) and then link these back to the user table on the corresponding userids (the first JOIN).
You can either run this for each user id you are interested in, or JOIN onto the result of a query (your getusers) (it depends on what database engine you are running).
If you aren't familiar with JOIN's, Jeff Atwood's introductory post is a good starting place.
The JOIN statement effectively allows you to explot the logical links between your tables - the userId, institutionID and professionID are all examples of candidates for foreign keys - so, rather than having to constantly subquery each table and piece the results together, you can link all the tables together and filter down to the rows you want. It's usually a cleaner, more maintainable approach (although that is opinion).
Related
This is task table:
This is user table:
I want to select user tasks.
I would give from backend ("given_to_user) id.
But The thing is I want that SELECTED data would have usernames instead of Id which is (created_by_user and given_to_user).
SELECTED table would look like this.
Example:
How to achieve what I want?
Or maybe I designed poorly my tables that It is difficult to select data I need? :)
task table has to id values that are foreign keys to user table.
I tried many thinks but couldn't get desired result.
You did not design poorly the tables.
In fact this is common practice to store the ids that reference columns in other tables. You just need to learn to implement joins:
SELECT
task.id, task.title, task.information, user.usename AS created_by, user2.usename AS given_to
FROM
(task INNER JOIN user ON task.created_by_user = user.id)
INNER JOIN user AS user2 ON task.created_by_user = user2.id;
Do you just want two joins?
select t.*, uc.username as created_by_username,
ug.username as given_to_username
from task t left join
users uc
on t.created_by_user = uc.id left join
users ug
on t.given_to_user = ug.id;
This uses left join in case one of the user ids is missing.
I have two queries I need in one table, and haven't been able to find results in searching.
In the first table there is a UserID, which is a number, along with what the actual user id is and user's name.
My issue is that in every other query the user is only referred to as this number. I'm needing help in how to translate this UserID value into the actual User's name in my other queries.
Table with User's ID and User's Name:
SELECT *
FROM [Table].[dbo].[User]
Table example where the user is only referred to as this number, along with all other tables:
SELECT *
FROM [Table].[LoginStatus]
You need to join the two tables:
SELECT u.[UserName], l.*
FROM [LoginStatus] l
JOIN [Users] u ON u.id = l.user_id
So first sorry for my english, my native language is german.
I have an ACCESS DB with a few Tables, the DB is filled with healing Plants, and there is one Table named "Issues" it looks like that:
Columns: ID -- Name -- Headache -- Pain -- Vomitting - and so on....
And the Columns for the indications like headache and so on, are boolean- True or False.
Now i`d like to make an query that asks the user (With a listbox in a form or so, or a Text input) to tell his indication, and then there should be a list of Substances/Plants where the Value for the indication (ColumnName) is true.
I think thats a parameter for a search in a table for columns.
I'd look at the design of your database. Having a table with separate columns for each issue would be a real headache to update if another issue became apparent.
I'd probably use four tables for this:
Users: UserID (AutoNum, PK), UserName (Text)
Plants: PlantID (AutoNum, PK), PlantName (Text)
IssueList: IssueID (AutoNum, PK), IssueDescription (Text)
User_Issues: UserID (Num, PK), PlantID (Num, PK), IssueID (Num, PK), HasIssue (Boolean)
The User_Issues table has a composite key made up each identifier from the other tables - this will ensure that a user can't have the same issue for a plant more than once.
When a new user is created a query runs to update the User_Issues table:
INSERT INTO User_Issue(PlantID, IssueID, UserID)
SELECT PlantID, IssueID, UserID
FROM Plants, IssueList, Users
WHERE UserName = "Darren"
This will create a Cartesian product from the plants and issues for each user. So, for example, if you have two plants and three issues you'll get 2x3 records created - a possible 6 issues across the two plants.
This SQL will allow you to allocate an issue:
SELECT UserName
, PlantName
, IssueDesc
, HasIssue
FROM ((
User_Issue INNER JOIN Users ON User_Issue.UserID = Users.UserID)
INNER JOIN Plants ON User_Issue.PlantID = Plants.PlantID)
INNER JOIN IssueList ON User_Issue.IssueID = IssueList.IssueID
ORDER BY PlantName, IssueDesc
To view the issues you just have to add WHERE HasIssue to the above SQL.
SELECT UserName
, PlantName
, IssueDesc
, HasIssue
FROM ((
User_Issue INNER JOIN Users ON User_Issue.UserID = Users.UserID)
INNER JOIN Plants ON User_Issue.PlantID = Plants.PlantID)
INNER JOIN IssueList ON User_Issue.IssueID = IssueList.IssueID
WHERE HasIssue
ORDER BY PlantName, IssueDesc
I'm building this bartering-type function in this site using PHP/MySQL and I'm trying to create a query that responds with the following fields:
owner's username, title, offerer's username, offerer's item
Basically I have three tables here with the following fields:
users
user_id, username, email
items_available
item_number, owner_id (foreign key that links to user_id), title
offers_open
trade_id, offerers_id (fk of user_id), offerers_item(fk with item_number), receivers_id (fk from user_id)
How do I do this? I've seen some references to many-to-many SQL queries but they don't seem to particularly fit what I'm looking for (for example, the offerers_id and the owner_ids refer to different users_id in the Users table, but how do I make them distinguishable in the sql query?)
If I understand correctly, this is what you are looking for:
SELECT owner.username, oferrers.username, ia.title
FROM offers_open o
INNER JOIN users AS offerers
ON o.offerers_id = offerers.user_id
INNER JOIN items_available AS ia
ON o.offerers_item= ia.item_number
INNER JOIN users AS owner
ON ia.owner_id = owner.user_id
I don't see a title on the users table, so didn't include one.
I'm not sure exactly what output you want, but since your users table will appear twice in the query, they need to be aliased like so:
SELECT offerer.username AS offerer_username, title, receiver.username AS receiver_username
FROM users AS owner
JOIN items_available ON owner_id = owner.user_id
JOIN offers_open ON offerers_item = item_number
JOIN users AS receiver ON receivers_id
Again, don't know if that's what you want, but hope you get the idea.
It sounds as you need an alias of the users table.
Something like?
select
u.*, ia.*, oo.*,u2.*
from
users as u,
items_available as ia,
offers_open as oo,
users as u2
where
u.user_id = ia_user_id and
oo.user_id = u2.user_id and
oo.item_id = ia.item_id
I have two tables, one stores the users, the other stores the users' email addresses.
table users: (userId, username, etc)
table userEmail: (emailId, userId, email)
I would like to do a query that allows me to fetch the latest email address along with the user record.
I'm basically looking for a query that says
FIRST ORDER BY userEmail.emailId DESC
THEN GROUP BY userEmail.userId
This can be done with:
SELECT
users.userId
, users.username
, (
SELECT
userEmail.email
FROM userEmail
WHERE userEmail.userId = users.userId
ORDER BY userEmail.emailId DESC
LIMIT 1
) AS email
FROM users
ORDER BY users.username;
But this does a subquery for every row and is very inefficient. (It is faster to do 2 separate queries and 'join' them together in my program logic).
The intuitive query to write for what I want would be:
SELECT
users.userId
, users.username
, userEmail.email
FROM users
LEFT JOIN userEmail USING(userId)
GROUP BY users.userId
ORDER BY
userEmail.emailId
, users.username;
But, this does not function as I would like. (The GROUP BY is performed before the sorting, so the ORDER BY userEmail.emailId has nothing to do).
So my question is:
Is it possible to write the first query without making use of the subqueries?
I've searched and read the other questions on stackoverflow, but none seems to answer the question about this query pattern.
But this does a subquery for every row and is very inefficient
Firstly, do you have a query plan / timings that demonstrate this? The way you've done it (with the subselect) is pretty much the 'intuitive' way to do it. Many DBMS (though I'm not sure about MySQL) have optimisations for this case, and will have a way to execute the query only once.
Alternatively, you should be able to create a subtable with ONLY (user id, latest email id) tuples and JOIN onto that:
SELECT
users.userId
, users.username
, userEmail.email
FROM users
INNER JOIN
(SELECT userId, MAX(emailId) AS latestEmailId
FROM userEmail GROUP BY userId)
AS latestEmails
ON (users.userId = latestEmails.userId)
INNER JOIN userEmail ON
(latestEmails.latestEmailId = userEmail.emailId)
ORDER BY users.username;
If this is a query you do often, I recommend optimizing your tables to handle this.
I suggest adding an emailId column to the users table. When a user changes their email address, or sets an older email address as the primary email address, update the user's row in the users table to indicate the current emailId
Once you modify your code to do this update, you can go back and update your older data to set emailId for all users.
Alternatively, you can add an email column to the users table, so you don't have to do a join to get a user's current email address.