Multiple mysql joins, how to combine these 2 select statments - mysql

I have 2 select statements I would like to combine into one, though I really only need the info from one field in the second select statement(The field data from user_info_data). The fields I need are Firstname, lastname, email, course fullname, role, and the field data where fieldid = '15'. The first select statement will give me everything but the data field. And the second gives me everything but the course. I tried doing the second select statement similar to Role field but it complains about it returning more than one row. If I try and just use the course name without the fieldid='15' part, it brings up over 100k records(Each user shows up in each course and all their data).
Fields for tables:
user(id,auth,confirmed,policyagreed,username,password,idnumber,firstname,lastname,email,phone etc..)
user_info_data(id,userid,fieldid,data)
role(id,name,shortname,description,sortorder)
role_assignments(id,roleid,contextid,userid...)
context(id,contextlevel,instanceid,path,depth)
First statement:
SELECT user.firstname AS Firstname, user.lastname AS Lastname, user.email AS Email, course.fullname AS Course, role.name AS Role
FROM user AS user, course AS course,role,role_assignments AS asg
INNER JOIN context AS context ON asg.contextid=context.id
WHERE context.contextlevel = 50
AND role.id=asg.roleid
AND user.id=asg.userid
AND context.instanceid=course.id
Output of first stament:
Firstname Lastname Email Course Role
John Doe john.doe#email.com Course-Name Student
Second statement:
SELECT user.firstname AS 'First Name', user.lastname AS 'Last Name', user.email AS 'Email', user_info_data.data AS 'IBCLC Certified'
FROM user, user_info_data
WHERE user.id = user_info_data.userid
AND fieldid = '15'
Output of second stament:
Firstname Lastname Email IBCLC Certified
John Doe john.doe#email.com Yes
Desired Output:
FirstName,LastName,Email,IBCLC Certified,Course,Role
Other select statement I tried: Brings up 9,494 records, but right now the field data where fieldid is 15 is a list of possible choices, could that be why?
SELECT user.firstname AS Firstname, user.lastname AS Lastname, user.email AS Email, userdata.data, course.fullname AS Course, role.name AS Role
FROM user AS user, course AS course, user_info_data AS userdata, role,role_assignments AS asg
INNER JOIN context AS context ON asg.contextid=context.id
WHERE context.contextlevel = 50
AND userdata.fieldid = 15
AND role.id=asg.roleid
AND user.id=asg.userid
AND context.instanceid=course.id

I added user_info_data to your first request like this:
SELECT user.firstname AS Firstname,
user.lastname AS Lastname,
user.email AS Email,
course.fullname AS Course,
role.name AS Role,
ibclcCert.data AS 'IBCLC Certified'
FROM user,
course,
role,
role_assignments AS asg,
context,
user_info_data AS ibclcCert
WHERE context.contextlevel = 50
AND role.id=asg.roleid
AND user.id=asg.userid
AND context.instanceid=course.id
AND asg.contextid=context.id
AND ibclcCert.userid = user.id
AND ibclcCert.fieldid = '15'
I renamed the user_info_data table reference to something denoting the actual field, ibclcCert in this case. This renaming is a provision in case that you one day want to access more than one data field. When you do, you'd include the table multiple times, one for every field you need. See also this answer about how to deal with such data formats.

Related

Don't want to fetch single column (name)

def fetchProposalByStudio(studioId: Int): List[ProposalDetails] = {
ConnectionPoolManager.getDB(config = appConfig).localTx { implicit session: DBSession =>
logger.info("Querying proposal table to fetch all the proposals")
SQL("""SELECT [except name] p.id, id, proposal_title, challenge, possible_solution, explanation,
| submission_date, status, submitted_by, remark
| FROM proposal p inner join knolder k on k.id = p.knolder_id
| where k.studio_id =? order by p.id desc""".stripMargin)
.bind(studioId)
.map(rs =>
ProposalDetails(
rs.int("id"),
rs.int("id"),
rs.string("proposal_title"),
rs.string("challenge"),
rs.string("possible_solution"),
rs.string("explanation"),
rs.string("submission_date"),
Some(ProposalStatus.withName(rs.string("status"))),
rs.string("submitted_by"),
rs.string("remark"),
**rs.string("name")**
)
)
.list().apply()
}
}
I don't want to fetch this column name in my query but without involving this in the query i am getting this error due to using case class.
13:28:24.446 [default-akka.actor.default-dispatcher-8] INFO c.k.l.b.ProposalImpl - Something went wrong while fetching the proposals. Exception message: ERROR: syntax error at or near "["
Position: 8
Smells of a syntax problem...
Perhaps:
SELECT [except name] -- should be
SELECT `except name` -- in mysql
If you don't want a particular column in an SQL resultset, you simply don't mention it in the SELECT.
There is no notion of SELECT * EXCEPT FirstName FROM person - if Person has FirstName, LastName, Age, Address and you don't want FirstName, you don't put it in the select list:
SELECT LastName, Age, Address FROM Person
^^^^^^^
no FirstName mentioned here
Mention every column you do want, do not mention any column you don't want.
If the complaint is "but there are 527 columns and I want all except one" - you can do something like:
SELECT CONCAT(column_name, ',') FROM information_schema.columns WHERE table_name = 'Person' and column_name <> 'FirstName'
which produces a resultset like:
LastName,
Age,
Address,
... 523 other columns
And you can then copy that resultset and paste it into your code, and it already has commas on the end..
If you want the columns all on one line, use GROUP_CONCAT or use a decent text editor to replace \r\n with nothing. If you want to surround the column name in backticks, put it into the CONCAT.. The ultimate point here is that you're a software developer: you can write code that writes code, then you can copy the output, which is valid code, and paste it into some other code somewhere else

Query Prompting for Parameter Value

I am attempting to creat a VIEW for my class. I was instructed to make my Access Compatible syntax ANSI 92. I have done that but I keep getting a message saying to:
"Enter parameter Value for 'JR'."
But it should just be showing any with the JR in the field value.
Any idea what I am doing wrong?
SELECT Student.IDno, LastName, FirstName, Class AS
Junior, Major, GPA
FROM Student, Person
WHERE Student.IDno = Person.IDno
AND Class = “JR”;
I also have to include columns from 2-3 different tables, change the titles of two of the columns, and show only the records that have class = "JR".
Any advice on where to start looking for this info would be great.
Thank you.
EDIT: Thank you for the help with that last one. Now I'm trying to change this to be able to pull from multiple tables and I can't seem to figure anything out. When I run this code, it tells me it can't find the table or query. If I run each section alone, it works just fine. I need to pull some info from 4 tables...
SELECT Student.IDno, Person.LastName, Person.FirstName, Student.Class, Student.Major, Student.GPA
FROM Student, Person
WHERE Student.IDno = Person.IDno
AND Class = 'JR';
UNION
SELECT Student.IDno, Enrollment.OfferNo, Enrollment.Grade
FROM Student, Enrollment
WHERE Student.IDno = Enrollment.IDno;
The double-quotes present in your SQL code are 'smart quotes' or Unicode character 0x201C, as opposed to the standard double-quote, which is Unicode/ASCII character 0x0022.
Hence changing the SQL to either:
SELECT Student.IDno, LastName, FirstName, Class AS Junior, Major, GPA
FROM Student, Person
WHERE Student.IDno = Person.IDno
AND Class = "JR";
or:
SELECT Student.IDno, LastName, FirstName, Class AS Junior, Major, GPA
FROM Student, Person
WHERE Student.IDno = Person.IDno
AND Class = 'JR';
Will solve this.
However, I would also strongly suggest using an INNER JOIN (i.e. ANSI-92 syntax) in place of a cartesian product with join criteria in the WHERE clause (ANSI-89 syntax):
SELECT Student.IDno, LastName, FirstName, Class AS Junior, Major, GPA
FROM Student INNER JOIN Person ON Student.IDno = Person.IDno
WHERE Class = 'JR';
It is also advisable to state the table qualifier for each field (e.g. Person.LastName or Student.LastName) so as to avoid the improper use of reserved words or ambiguity arising from identically named fields in multiple tables.
In the code you have added to your question, you are attempting to UNION two SELECT queries which output a different number of columns, and presumably, different data types - this is invalid.
I imagine that you are actually looking to do this:
select
student.idno,
person.lastname,
person.firstname,
student.class,
student.major,
student.gpa,
enrollment.offerno,
enrollment.grade
from
(
student inner join person
on student.idno = person.idno
)
inner join enrollment
on student.idno = enrollment.idno
where
student.class = 'JR'

How to "remove duplicates" from a UNION query

I have two tables in MySQL: One called gtfsws_users which contains users for a system I'm developing and another called gtfsws_repository_users which contains roles for these users.
gtfsws_users has these fields: email, password, name, is_admin and enabled.
gtfsws_repository_users has: user_email, repository_id and role.
The role is an integer that defines privileges over a GTFS repository (public transportation data, not relevant for my problem).
One important thing is that every administrator accont (that is, every user that has the is_admin flag set as 1 in gtfsws_users) has full access to all repositories.
Now, only users registered in gtfsws_repository_users will have access to a specific repository defined there (unless they are administrators, of course). One user can have multiple repositories which him/her can access.
What I'm trying to do is to get all users with access to a specific repository (it doesn't matter which type of role the user has, I just want to know if they can access the repository or not). So I'm writing this SQL statement for getting them:
(
SELECT DISTINCT
gtfsws_users.email AS email,
gtfsws_users.name AS name,
gtfsws_users.is_admin AS is_admin,
gtfsws_users.enabled AS enabled,
gtfsws_repository_users.role AS role
FROM
gtfsws_users
INNER JOIN
gtfsws_repository_users
ON
gtfsws_users.email = gtfsws_repository_users.user_email
WHERE
gtfsws_repository_users.repository_id = '2'
)
UNION
(
SELECT
email,
name,
is_admin,
enabled,
null AS role
FROM
gtfsws_users
WHERE
is_admin = 1
)
Now, this works fine for users with access to different repositories. It also gets all administrators too.
The problem is when I have an administrator that is also registered in gtfsws_repository_users, because I get it duplicated.
So for example, it I have this in gtfsws_users:
('test#test.com', '*****', 'Real name', 1, 1)
And also the user is registered in gtfsws_repository_users as this:
('test#test.com', 2, 10)
When I do the SELECT in MySQL (using the UNION to add all administrators) I get:
('test#test.com', 'Real name', 1, 1, 10)
('test#test.com', 'Real name', 1, 1, NULL)
What I need to do is to filter that table to remove duplicates, that is getting only:
('test#test.com', 'Real name', 1, 1, NULL)
Yes, getting NULL as the role (since it will be ignored as the user is an administrator).
Does anybody have a clue on how to achieve that?
Thanks a lot.
EDIT: Ok, thanks to Katrin's suggestion, I'm getting some progress. I do get one row, but it's the one with the role number defined. Any way to preserve the one with the NULL role instead of the defined one?
Since aggregate functions ignore null values, you can convert null to a number that can be extracted as min or max.
Assuming all your roles are greater than 0:
SELECT email, name, is_admin, enabled, nullif(min(coalesce(role, 0)), 0) as role
from
((
SELECT DISTINCT
gtfsws_users.email AS email,
gtfsws_users.name AS name,
gtfsws_users.is_admin AS is_admin,
gtfsws_users.enabled AS enabled,
gtfsws_repository_users.role AS role
FROM
gtfsws_users
INNER JOIN
gtfsws_repository_users
ON
gtfsws_users.email = gtfsws_repository_users.user_email
WHERE
gtfsws_repository_users.repository_id = '2'
)
UNION
(
SELECT
email,
name,
is_admin,
enabled,
null AS role
FROM
gtfsws_users
WHERE
is_admin = 1
)) as Q
GROUP BY email, name, is_admin, enabled

where clause in COUNT function and joining two queries

I have a table that I am trying to count the number of course passed, and also list the modules passed as well.
The first problem I am having is what to put in the where variable, so that its not specific to a customer(I can use the query below for a particular customer and a particular course)but I will like a generic query where the result will be distinct in terms of user and course like the one below
SELECT FirstName
,LastName
,CourseTitle
,Noofmodules
,count(Coursecompleted) AS modulescompleted
FROM EStudentsprogress
WHERE Coursecompleted = '1'
AND EmailAddress = 'scascsc#e.co.uk'
AND CourseTitle = 'Microsoft MOS 2010 EXCEL'
GROUP BY FirstName
,LastName
,CourseTitle
,Noofmodules
How can I make it list the result as above, whereby I don't specify the email address or course title(trying to get the result for all the clients )
Also I have a query that list the courses that is passed by the customer, I will like the column with the list of courses passed be added to the result above, but as a column for each course.
SELECT FirstName
,LastName
,CourseTitle
,EmailAddress
,CourseModule AS coursepassed
FROM EStudentsprogress
WHERE coursecompleted = 1
Cheers
Can you not just add the email address and course title fields to the select fields and the GROUP BY clause.
Also you can use GROUP_CONCAT to bring back a field containing all the course modules.
Something like this:-
SELECT FirstName,
LastName,
CourseTitle,
Noofmodules,
EmailAddress,
CourseTitlecount,
COUNT(Coursecompleted) as modulescompleted,
GROUP_CONCAT(CourseModule) as modulescompletednames
FROM EStudentsprogress
WHERE Coursecompleted = '1'
GROUP BY FirstName, LastName, CourseTitle, Noofmodules, EmailAddress, CourseTitlecount ;

select values from multiple tables where value = X

I'm trying to perform what I assume is a very simple query on a MySQL DB. Here's my table setup;
Table 1 - CMS_AccessLevels
accessLevel
titleColor
Table 2 - CMS_Users
userID
username
userEmail
userAvatar
userSignature
accessLevel
I've already got this query;
SELECT `titleColor` FROM `CMS_AccessLevels` WHERE `accessLevel` = (SELECT `accessLevel` FROM `CMS_Users` WHERE `userID` = 3)
This works correctly and returns the correct titleColor value based on the accessLevel matching across both tables.
Now, what I want to do is also grab some of the values from CMS_Users as well. For the sake of simplicity, let's assume I want to grab only a few of the values, so my result set might look something like this;
userID|username|userAvatar|accessLevel|titleColor
-------------------------------------------------
0 |Scott |image.png | 6 |#FFFFFF
or as a PHP Array (shown just so you can see the logical layout if the above table didn't make sense);
array('userID' => $result['userID'],
'username' => $result['username'],
'userAvatar' => $result['userAvatar'],
'accessLevel' => $result['accessLevel'],
'titleColor' => $result['titleColor'];
Let's say I want to get userID, userName, userAvatar and accessLevel from CMS_Users, and titleColor from CMS_AccessLevels where CMS_Users.userID is equal to '3', remembering that CMS_AccessLevels.accessLevel and CMS_Users.accessLevel MUST match.
Realistically, the only piece of data I know before running the query is userID.
Is it possible to do this with a single query?
Try this:
SELECT u.userID, u.username, u.userAvatar, u.accessLevel, al.titleColor
FROM CMS_AccessLevels al
INNER JOIN CMS_Users u
ON u.accessLevel = al.accessLevel
WHERE u.userID = 3
You are using subqueries whereas joins will be the right choice. You might try something like
SELECT a.titleColor AS titleColor, u.username AS username FROM CMS_users u INNER JOIN CMS_AccessLevels a ON u.accessLevel = a.accessLevel WHERE u.userID = '3'