Check if combination of fields exist - mysql

I have a query that displays the modules that are available for a student to enrol on and shows them in a list.. I would like it if the modules that student has enrolled on do not show in the list. Once a student has enrolled on a module it is stored in a table called tbl_studentModule which has two fields, regNum ($studentID) and moduleID.
What do I need to add to this query to only show the modules that are not already in the tbl_studentModule with the relevant regNum.
EG I would lik the query to say something to the effect where the combination of regNum and moduleID do not already exist if tbl_studentModule.
Here is what I have so far...
SELECT DISTINCT am.moduleID, m.moduleName, am.type, s.regNum, s.award
FROM tbl_awardModules am
LEFT OUTER JOIN tbl_module m ON am.moduleID = m.moduleID
INNER JOIN tbl_awardLevels al ON am.awardLevelID = al.awardLevelID
INNER JOIN tbl_award a ON al.awardID = a.awardID
INNER JOIN tbl_student s ON a.awardID = s.award
LEFT JOIN tbl_studentModules sm ON s.regNum = sm.regNum
WHERE am.type <> 'C' AND sm.regNum = '$student_id' AND m.moduleName <> 'A_null_Choice' AND m.moduleName NOT LIKE '%Not Running%'
Hope that makes sense...

Ok, I sussed it..
I added
AND NOT EXISTS (SELECT * FROM tbl_studentModules WHERE regNum = '$student_id' AND moduleID = am.moduleID)
to the end if the query so now it only shows the rows of the table that do not already contain that combination of values

Related

Select all rows with multiple possible values

I am trying to get all fields from the product table (*) that have the following set of sub_property:
subprop_name=X
subprop_value=Y
I have the following tables :
https://imgur.com/a/y4LGqMI (couldn't upload the picture because the format was not accepted)
So, for an example, if I have two products which has in their sub_property table a entry like this:
subprop_name=X
subprop_value=Y
I would like to return it. As described by the schema, a product can have multiple sub_property entries!
So far, this is what I have:
SELECT prod_id,prod_name from product WHERE product.prod_id IN
(
SELECT property.product_prod_id FROM property WHERE property.prop_id IN
(
SELECT property_prop_id from sub_property WHERE
(
sub_property.subprop_name="Type de scanner" AND sub_property.subprop_value="par transparence"
)
OR
(
sub_property.subprop_name="Pages/minute maximum" AND subprop_value="8.5 pages"
)
)
)
But obviously, it doesn't work because of the 'OR'.
It returns me all items that have one of the set of sub_property instead of all the products that have all the sets of sub_property.
DATABASE HERE
Using JOIN's and an IN for the tupples could be a simple solution for this.
SELECT p.prod_id, p.prod_name
FROM product p
JOIN property AS prop
ON prop.product_prod_id = p.prod_id
JOIN sub_property AS subprop
ON subprop.property_prop_id = prop.prop_id
WHERE (subprop.subprop_name, subprop.subprop_value) IN (
('Type de scanner', 'par transparence'),
('Pages/minute maximum', '8.5 pages')
)
GROUP BY p.prod_id, p.prod_name
So... I am not sure if it's the correct way to validate two answers, but I got 2 working answers.
This is the first one from #Steff Mächtel using LEFT JOIN (https://stackoverflow.com/a/53915792/5454875)
And the second one is from #Shidersz (see comments below the original question), using INNER JOIN)
"I used and approach using INNER JOIN, is something like this what you need? db-fiddle.com/f/t6RrnhDPQuEamjf2bTxFeX/5"
EDIT
#Shidersz solution doesn't work because it selects all products who as at least one of the condition, wich I don't want. I want the product to have all the conditions.
UPDATE 2:
I would suggest to use LEFT JOIN for each property and each sub_property and then check the value inside WHERE condition:
SELECT product.prod_id, product.prod_name
FROM product
LEFT JOIN property AS property_a ON property_a.product_prod_id = product.prod_id AND
property_a.prop_name = "PROPERTY_GROUP_3"
LEFT JOIN sub_property AS sub_property_a ON sub_property_a.property_prop_id = property_a.prop_id AND
sub_property_a.subprop_name="property_4"
LEFT JOIN property AS property_b ON property_b.product_prod_id = product.prod_id AND
property_b.prop_name = "PROPERTY_GROUP_4"
LEFT JOIN sub_property AS sub_property_b ON sub_property_b.property_prop_id = property_b.prop_id AND
sub_property_b.subprop_name="property_3"
WHERE sub_property_a.subprop_value="value_of_property_4" AND
sub_property_b.subprop_value="value_of_property_3"
GROUP BY product.prod_id
Example: https://www.db-fiddle.com/f/wk344Gt6hm98xEhM4jei92/6
Example with 2 new "KEYS" (Index) for better performance:
ALTER TABLE `property`
... ADD KEY `prop_name` (`prop_name`);
ALTER TABLE `sub_property`
... ADD KEY `subprop_name` (`subprop_name`);
https://www.db-fiddle.com/f/wk344Gt6hm98xEhM4jei92/7
Example with INNER JOIN instead of LEFT JOIN
I see no difference with EXPLAIN on test data, maybe Mysql optimizer handles this internal equal
SELECT product.prod_id, product.prod_name
FROM product
INNER JOIN property AS property_a ON property_a.product_prod_id = product.prod_id AND
property_a.prop_name = "PROPERTY_GROUP_3"
INNER JOIN sub_property AS sub_property_a ON sub_property_a.property_prop_id = property_a.prop_id AND
sub_property_a.subprop_name="property_4" AND
sub_property_a.subprop_value="value_of_property_4"
INNER JOIN property AS property_b ON property_b.product_prod_id = product.prod_id AND
property_b.prop_name = "PROPERTY_GROUP_4"
INNER JOIN sub_property AS sub_property_b ON sub_property_b.property_prop_id = property_b.prop_id AND
sub_property_b.subprop_name="property_3" AND
sub_property_b.subprop_value="value_of_property_3"
GROUP BY product.prod_id
https://www.db-fiddle.com/f/wk344Gt6hm98xEhM4jei92/8

Selecting multiple rows in same table in the same JOIN

In the picture is my table situation right now:
The central table in this case right now is tblJob, here is everything defined what I need (not all in the picture).
The address table needs to return 2 values (1 of the company and 1 of the job itself). The only thing I need to do right now is to add the company address (the job address is already in my query) My query already looks like this:
SELECT
tblJob.jobID,
tblJob.amount AS jobAmount,
tblJob.extraInfo AS jobExtraInfo,
tblJob.views AS jobViews,
tblJob.description AS jobDescription,
tblJob.dateCreated AS jobDateCreated,
tblJobFunction.jobFunctionID,
tblJobFunction.jobFunction,
tblAddress.zipcode AS jobAddress,
tblAddress.city AS jobCity,
tblAddress.street AS jobStreet,
tblAddress.number AS jobNumber,
tblAddress.bus AS jobBus,
tblCountry.countryID AS jobCountryID,
tblCountry.country AS jobCountry,
tblCountry.areaCode AS jobAreaCode,
tblCompany.companyID,
tblCompany.name,
tblCompany.email,
tblCompany.GSM,
tblCompany.phoneNumber,
tblCompany.photoURL AS companyPhotoURL,
tblCompany.VATNumber,
tblCompany.websiteURL,
tblEvent.eventID,
tblEvent.event,
tblEvent.description AS eventDescription,
tblEvent.startDate AS eventStartDate,
tblEvent.endDate AS eventEndDate,
tblEvent.facebookURL,
tblEvent.photoURL AS eventPhotoURL,
tblEvent.views AS eventViews,
tblEvent.dateCreated AS eventDateCreated
FROM tblJob
JOIN tblAddress ON tblAddress.addressID = tblJob.addressID
JOIN tblCountry ON tblAddress.countryID = tblCountry.countryID
JOIN tblJobFunction ON tblJob.jobFunctionID =
tblJobFunction.jobFunctionID
JOIN tblCompany ON tblJob.companyID = tblCompany.companyID
LEFT JOIN tblEvent ON tblJob.eventID = tblEvent.eventID
Now the question is: how can I add the address from the company in the same query?
Use the address table as many times as you need it, but each time you must give it a new alias:
FROM tblJob
JOIN tblAddress ON tblAddress.addressID = tblJob.addressID
JOIN tblCountry ON tblAddress.countryID = tblCountry.countryID
JOIN tblJobFunction ON tblJob.jobFunctionID = tblJobFunction.jobFunctionID
JOIN tblCompany ON tblJob.companyID = tblCompany.companyID
JOIN tblAddress a2 ON a2.addressID = tblCompany.addressID
LEFT JOIN tblEvent ON tblJob.eventID = tblEvent.eventID
perhaps more like this:
SELECT JobAddress.street, CompanyAddress.street
FROM tblJob
JOIN tblAddress JobAddress ON JobAddress.addressID = tblJob.addressID
JOIN tblCompany ON tblJob.companyID = tblCompany.companyID
JOIN tblAddress CompanyAddress ON CompanyAddress.addressID = tblCompany.addressID

use multiple results of a query within the query with joins

I have some tables in my database, three main ones and one that holds the many-to-many relations.
1. Student (student_id, student_name)
2. Sport (sport_id, sport_name)
3. Departm (depart_id, depart_name)
4. Sch (sch_id, sch_name)
5. StudSport(relationid, studendid, sportid, departid, schid)
What I want to do is e.g. retrieve the name of the department based on the relations when I know the id. I can get the ids like this:
SELECT departid, schid from studsport
inner join Student on student_id = studentid
inner join Sport on sport_id = sportid
where student_id = 1 and sport_id=2
but I want to get the names of the department and the Sch from their corresponding tables, and I dont know how to do that.
As you don't select anything from Student or Sport, you can remove the corresponding inner joins.
SELECT d.depart_name, sch.sch_name FROM StudSport s
INNER JOIN Sch sch ON s.schid = sch.sch_id
INNER JOIN Departm d ON s.departid = d.depart_id
WHERE s.studendid = 1 AND s.sportid = 2
Something like this???
select sch.sch_nam, departm.depart_name,
-- what you have already --
Left outer Join StudSport on Student.student_id = Studsport.studentid and Sport.sport_id = StudSport.sportid
left outer Join Sch on StudSport.schid = Sch.sch_id
left outer join Departm on studsport.depart_id = studsport.departid
This is untested, a fiddle makes it much easier to give answers because of that.
EDIT - I misread your original query - before the downvotes start to rain - fixing it right now.
The way you should use LEFT OUTER and INNER joins is how the data is meant (again, a fiddle will normally be usefull) but it's just a couple of joins from what you have i guess:
select *
from studsport
join student on studsport.studentid = student.student_id
join sport on studsport.sportid = sport.sport_id
left outer Join Sch on StudSport.schid = Sch.sch_id
left outer join Departm on studsport.depart_id = studsport.departid
where student_id = 1 and sport_id=2

Select records that are not associated with the other record

Hi i have 3 tables Modules,Students and join table (many to many) StudentModules.I want to select all modules that the student has not registered for.When the student register the information is stored in the StudentModules table.Basically i want to select all modules that are not associated with the student number in the StudentModules table from the Modules table.
i have tried the following code
SELECT Modules.*, Students.*
FROM ((StudentsModules INNER JOIN
Modules ON StudentsModules.ModuleCode = Modules.ModuleCode) INNER JOIN
Students ON StudentsModules.StudentNo = Students.StudentNo)
Where StudentNo = 48377767 AND WHERE ModuleCode NOT IN (SELECT ModuleCode FROM StudentsModules)
You're close, you forgot one check at the end!
Edit this part:
NOT IN (SELECT ModuleCode FROM StudentsModules where StudentNo=48377767)
One possible way to select all modules that the student has not registered for, assuming that the student no is 48377767 in this example :
SELECT m.*
FROM Modules m
LEFT JOIN StudentsModules sm ON sm.ModuleCode = m.ModuleCode
AND sm.StudentNo = 48377767
WHERE sm.ModuleCode IS NULL
[SQL Fiddle]
UPDATE :
Different approach without JOIN :
SELECT m.*
FROM Modules m
WHERE m.ModuleCode NOT IN
(
SELECT ModuleCode
FROM StudentsModules
WHERE StudentNo = 48377767
)

SQL join multiple times?

I am making a user status list of the following format "A like B's XXX". A and B are both registered users and have firstname and lastname and user id. How to join the status table with the user table twice to get the names of the two users? Thank you.
SELECT "SQACTION"."TIMECREATED",
"SQWORDLIST".*,
"SUBJECT"."FIRSTNAME" subject_fn,
"SUBJECT"."LASTNAME" subject_ln,
author.firstname author_fn,
author.lastname author_ln
FROM "SQACTION"
INNER JOIN "SQWORDLIST"
ON SQACTION.ACTION = SQWORDLIST.GUID
INNER JOIN "SQUSER" SUBJECT
ON SQACTION.SUBJECT = SUBJECT.GUID
LEFT JOIN SQDOCUMENT
ON SQACTION.ENTITY = SQDOCUMENT.GUID
LEFT JOIN SQUSER AUTHOR
ON SQDOCUMENT.AUTHORID = AUTHOR.GUID
WHERE (SUBJECT.GUID = 'B4D3BF632C0C4DB3AB01C8B284069D8F')
OR (SUBJECT.GUID IN ('67882AF3FA3C4254AF9A12CA0B0AB6E4',
'6A4B52FE233444838AACFE2AFFE4D38F',
'8CA3FB9061FF4710B51F1E398D3D1917'))
ORDER BY "TIMECREATED" DESC
This is what I have tried. Thank you.
You need to include the table name twice in the FROM clause, and use an alias so you can specify which fields from each instance of the table are used in the ON statement. You didn't provide enough details in your question to give an exact example, so here is something more general.
UserTable, with ID & Name
RegTable, with UserID, and SponsorID
select ut1.name as [User],
ut2.name as [Sponsor]
from UserTable ut1
inner join RegTable rt on ut1.id = rt.userid
inner join UserTable ut2 on rt.sponsorid = ut2.id
do you mean something like, status have two field links to user table?
select user_a.first_name as user_a_first_name, user_b.first_name as user_b_first_name, status.status_name
from status
left join users as user_a on user_a.id = status.user_from_id
left join users as user_b on user_b.id = status.user_to_id