Struggling to find the right answer for this so hopefully someone can help. It maybe so simple that I've overlooked something obvious and making it more difficult than I should be.
I have two tables - titles [including titleIDs and titleNames], and groups [including groupIDs with title IDs they are associated with]. A titleID can have many groupIDs attached.
I'm trying to write a query that brings me back results of TitleIDs that match a criteria of groupIDs that have been selected.
So I've tried
SELECT * FROM titles INNER JOIN groups ON titles.titleID = groups.titleID WHERE
groups.groupID = 6 AND
groups.groupID = 24 AND
groups.groupID = 53
So I want to return results of only titles that are only associated with ALL these group IDS.
The numbers will actually be replaced by what someone selects from a few tickboxes, but have hardcoded them in for purposes of this example.
I tried experimenting with a subquery but I couldn't get it to work, also I believe Subs can slow things down and I'm already going to be dealing with a lot of data.
The plan is for someone to select one or more groupIDs from a list and then return only results of Titles that are associated with all the GroupsIDs selected.
Any pointers, clues, advice on this would be really welcome.
Thanks
You can do so by using in() for the group ids and matching the count of distinct groups foreach title,if 3 group ids provided so count for each title groups must be 3 so the title that has exactly these 3 groups will be returned
SELECT * FROM titles t
INNER JOIN groups g ON t.titleID = g.titleID
WHERE g.groupID IN(6,24,53)
GROUP BY t.titleID
HAVING COUNT(DISTINCT g.groupID) = 3
Related
In my situation, I've two tables, a table with all institutions profile and a table which represents material studied by each of these institutions.
In a search, I want to look for institution's name which studied specifics type of material. So it's possible to look for institution which studied "Wood" and "Metal", just "Metal" etc...
I've tried the following query :
SELECT p.name
FROM q1_institution_profiles p
INNER JOIN q9_materials_studied_by_institution pf
ON pf.id_institution = p.id_institution
WHERE pf.id_material_studied = 10 AND pf.id_material_studied = 8
However result is empty because there is a problem when I have multiple conditions (here id_material_studied must be equal 8 and 10).
Is there a way to achieve this properly or do I have to do on join for each criteria ?
Thank you in advance for answer
I think this is what you want:
SELECT p.name
FROM q1_institution_profiles p INNER JOIN
q9_materials_studied_by_institution pf
ON pf.id_institution = p.id_institution
WHERE pf.id_material_studied IN (8, 10)
GROUP BY p.name
HAVING COUNT(DISTINCT pf.id_material_studied) = 2;
That is, get names where there are rows with each of the two values.
The WHERE clause selects only materials 8 and 10. The GROUP BY then groups these by p.name. The question is: Does a single name have both these materials? Well, that is what count(distinct) does.
I have got a somewhat complicated problem. This is my situation (ERD).
For a dashboard i need to create a pivot table that shows me the total amount of competences used by the vacancies. Therefore I need to:
Count the amount of vacancies per template
Count the amount of templates per competence
and last: multiply these numbers to get the total amount of comps used.
I have the first query:
SELECT vacancytemplate_id, count(id)
FROM vacancies
group by vacancytemplate_id;
And the second query isn't that difficult either, but I don't know what the right solution will be. I'm literally brainstuck. My mind can't comprehend how I can achieve the next step and put it down in a query. Please kind stranger, help me out :)
EDIT: my desired result is something like this
NameOfComp, NrOfTimesUsed
Leading, 17
Inspiring, 2
EDIT2: the meta query it should look like:
SELECT NameOfComp, (count of the competences used by templates) * (number of vacancies per template)
EDIT3: http://sqlfiddle.com/#!9/2773ca SQLFiddle
Thanks a lot!
If I am understanding your request correctly, you are wanting a count of competences per vacancy. This can be done very simply due to your table structure:
Select v.ID, count(*) from vacancy as v inner join CompTemplate_Table as CT
on v.Template_ID = CT.Template_ID group by v.ID;
The reason you can do only one join is because there will be a record in the CompTemplate_Table for every competency in each template. Additionally, the same key is used to join vacancy to templates as is used to join templates to CompTemplate_Table, so they represent the same key value (and you can skip joining the Templates table if you don't need data from there).
If you are wanting to add this data to a pivot table, I will leave that exercise to you. There are a number of tutorials available if you do a quick google search and it should not be that hard.
UPDATE: For the second query you are looking at something like:
Select cp.NameOfComp, count(*) from vacancy as v inner join CompTemplate_Table as CT
on v.Template_ID = CT.Template_ID inner join competencies as CP
on CP.ID = CT.Comp_ID
group by CP.NameOfComp
The differences here are you are adding in the comptetencies table, as you need data from that, and grouping by the CP.NameOfComp instead of the vacancy id. You can also restrict this to specific templates, competencies, or vacancies by adding in search conditions (e.g. where CP.ID = 12345)
It's been hours that I've been searching for a solution (books, internet, etc) and can't find anything. Here's my problem:
I got a table of items being tagged by 2 criteria: let's name them crit1 and crit2. For each of the items I can have for crit1 and crit2 the following int example values (criteria1,criteria2): (1,5) (5,2) (4,7) (8,6), etc.
In another table I store users that are subscribed to some of these items filtered by the above criteria. Let's say that user_id 1 is subscribed to the following item type (criteria1, criteria2): (1,5) (2,7). When I make my query to fetch the items that user 1 is subscribed to, I get the items tagged with (1,5) (2,7) but also (1,7) or (2,5). The SQL Select query is making cross-comparisons between each row.
Generally, I would like to know how to make a query that is filtered from more than 1 field in the same row (no cross-row allowed).
I tried to use JOINS to sort the problem but I can't link criteria1 and criteria2 in the same JOIN. I have to use 2 JOINS and that makes them independent (and the cross-comparison between criteria1 and criteria2 will happen).
Use AND operator in ON clause for JOIN:
SELECT i.* FROM subscriptions s
JOIN items i
ON i.crit1 = s.crit1 AND i.crit2 = s.crit2
WHERE s.user_id = 1
without seeing the rest of the structure specifically, I'll give it a shot like...
select
i.itemid,
i.itemDescription,
s.subscriberName
from
items i
join Subscribers s
on i.category1 = s.category1
AND i.category2 = s.category2
If this isn't it, you might need to dump some sample data from each respective table of what you are trying to actually get.
Try this:
multiply crit 1 by 1000 (or some other number-depending or size of numbers) and add to it Crit2
Use that formula in your where or join
I have a query that returns results related to items that match a specific category...
There are 3 mysql tables that results to this, items, categories and item_categories.
These i assume are self explanatory, but the latter, is a linking table that links any specific item to any specific category, using a match of id's.
The items table contains one row, with an id value of 1.
The categories table is filled with 15 rows, with id values of 1-15.
the item_categories table contains one row, the item_id value is 1 and the category_id value is 5.
This is the mysql query in its php form:
$catResultQuery = "
SELECT i.id, name, price
FROM items i
INNER JOIN item_categories
ON i.id = item_id
INNER JOIN categories c
ON category_id = c.id
WHERE MATCH (c.id)
AGAINST ('{$_SESSION['input']}' IN BOOLEAN MODE)
ORDER BY name
";
The session variable has a value of 5, but for some reason, this query displays a 0 result set.
Even when i run the query in php myadmin, it returns 0 rows.
And i am confused, because in my head, the logic behind all of this seems fairly simple, but for some reason i get 0? Does anyone have any idea where i have gone wrong with this?
Any advice and input would be greatly appreciated, thank you!!
Ok, I see now that you're building the SQL dynamically. If that's the case, then this should work:
SELECT i.id, name, price
FROM items i
INNER JOIN item_categories
ON i.id = item_id
INNER JOIN categories c
ON category_id = c.id
WHERE c.id
IN ('{$_SESSION['input']}')
ORDER BY name
Just make sure '{$_SESSION['input']}' is comma delimited and be aware that this carries the risk of SQL injection because you're constructing the SQL on the fly.
I have a database with a table for details of ponies, another for details of contacts (owners and breeders), and then several other small tables for parameters (colours, counties, area codes, etc.). To give me a list of existing pony profiles, with their various details given, i use the following query:
SELECT *
FROM profiles
INNER JOIN prm_breedgender
ON profiles.ProfileGenderID = prm_breedgender.BreedGenderID
LEFT JOIN contacts
ON profiles.ProfileOwnerID = contacts.ContactID
INNER JOIN prm_breedcolour
ON profiles.ProfileAdultColourID = prm_breedcolour.BreedColourID
ORDER BY profiles.ProfileYearOfBirth ASC $limit
In the above sample, the 'profiles' table is my primary table (holding the Ponies info), 'contacts' is second in importance holding as it does the owner and breeder info. The lesser parameter tables can be identified by their prm_ prefix. The above query works fine, but i want to do more.
The first big issue is that I wish to GROUP the results by gender: Stallions, Mares, Geldings... I used << GROUP BY prm_breedgender.BreedGender >> or << GROUP BY ProfileBreedGenderID >> before my ORDER BY line, but than only returns two results from all my available profiles. I have read up on this, and apparantly need to reorganise my query to accomodate GROUP within my primary SELECT clause. How to do this however, gets me verrrrrrry confused. Step by step help here would be fantabulous.
As a further note on the above - You may have noticed the $limit var at the end of my query. This is for pagination, a feature I want to keep. I shouldn't think that's an issue however.
My secondary issue is more of an organisational one. You can see where I have pulled my Owner information from the contacts table here:
LEFT JOIN contacts
ON profiles.ProfileOwnerID = contacts.ContactID
I could add another stipulation:
AND profiles.ProfileBreederID = contacts.ContactID
with the intention of being able to list a pony's Owner and Breeder, where info on either is available. I'm not sure how to echo out this info though, as $row['ContactName'] could apply in either the capacity of owner OR breeder.
Is this a case of simply running two queries rather than one? Assigning a variable $foo to the first run of the query, then just run another separate query altogether and assign $bar to those results? Or is there a smarter way of doing it all in the one query (e.g. $row['ContactName']First-iteration, $row['ContactName']Second-iteration)? Advice here would be much appreciated.
And That's it! I've tried to be as clear as possible, and do really appreciate any help or advice at all you can give. Thanks in advance.
##########################################################################EDIT
My query currently stands as an amalgam of that provided by Cularis and Symcbean:
SELECT *
FROM (
profiles
INNER JOIN prm_breedgender
ON profiles.ProfileGenderID = prm_breedgender.BreedGenderID
LEFT JOIN contacts AS owners
ON profiles.ProfileOwnerID = owners.ContactID
INNER JOIN prm_breedcolour
ON profiles.ProfileAdultColourID = prm_breedcolour.BreedColourID
)
LEFT JOIN contacts AS breeders
ON profiles.ProfileBreederID = breeders.ContactID
ORDER BY prm_breedgender.BreedGender ASC, profiles.ProfileYearOfBirth ASC $limit
It works insofar as the results are being arranged as I had hoped: i.e. by age and gender. However, I cannot seem to get the alias' to work in relation to the contacts queries (breeder and owner). No error is displayed, and neither are any Owners or Breeders. Any further clarification on this would be hugely appreciated.
P.s. I dropped the alias given to the final LEFT JOIN by Symcbean's example, as I could not get the resulting ORDER BY statement to work for me - my own fault, I'm certain. Nonetheless, it works now although this may be what is causing the issue with the contacts query.
GROUP in SQL terms means using aggregate functions over a group of entries. I guess what you want is order by gender:
ORDER BY prm_breedgender.BreedGender ASC, profiles.ProfileYearOfBirth ASC $limit
This will output all Stallions, etc. next to each other.
To also get the breeders contact, you need to join with the contacts table again, using an alias:
LEFT JOIN contacts AS owners
ON profiles.ProfileOwnerID = owners.ContactID
LEFT JOIN contacts AS breeders
ON profiles.ProfileBreederID = breeders.ContactID
To further expand on what #cularis stated, group by is for aggregations down to the lowest level of "grouping" criteria. For example, and I'm not doing per your specific tables, but you'll see the impact. Say you want to show a page grouped by Breed. Then, a user picks a breed and they can see all entries of that breed.
PonyID ProfileGenderID Breeder
1 1 1
2 1 1
3 2 2
4 3 3
5 1 2
6 1 3
7 2 3
Assuming your Gender table is a lookup where ex:
BreedGenderID Description
1 Stallion
2 Mare
3 Geldings
SELECT *
FROM profiles
INNER JOIN prm_breedgender
ON profiles.ProfileGenderID = prm_breedgender.BreedGenderID
select
BG.Description,
count(*) as CountPerBreed
from
Profiles P
join prm_BreedGender BG
on p.ProfileGenderID = BG.BreedGenderID
group by
BG.Description
order by
BG.Description
would result in something like (counts are only coincidentally sequential)
Description CountPerBreed
Geldings 1
Mare 2
Stallion 4
change the "order by" clause to "order by CountsPerBreed Desc" (for descending) and you would get
Description CountPerBreed
Stallion 4
Mare 2
Geldings 1
To expand, if you wanted the aggregations to be broken down per breeder... It is a best practice to group by all things that are NOT AGGREGATES (such as MIN(), MAX(), AVG(), COUNT(), SUM(), etc)
select
BG.Description,
BR.BreaderName,
count(*) as CountPerBreed
from
Profiles P
join prm_BreedGender BG
on p.ProfileGenderID = BG.BreedGenderID
join Breeders BR
on p.Breeder = BR.BreaderID
group by
BG.Description,
BR.BreaderName
order by
BG.Description
would result in something like (counts are only coincidentally sequential)
Description BreaderName CountPerBreed
Geldings Bill 1
Mare John 1
Mare Sally 1
Stallion George 2
Stallion Tom 1
Stallion Wayne 1
As you can see, the more granularity you provide to the group by, the aggregation per that level is smaller.
Your join conditions otherwise are obviously understood from what you've provided. Hopefully this sample clearly provides what the querying process will do. Your group by does not have to be the same as the final order... its just common to see so someone looking at the results is not trying to guess how the data was organized.
In your sample, you had an order by the birth year. When doing an aggregation, you will never have the specific birth year of a single pony to so order by... UNLESS.... You included the YEAR( ProfileYearOfBirth ) as BirthYear as a column, and included that WITH your group by... Such as having 100 ponies 1 yr old and 37 at 2 yrs old of a given breed.
It would have been helpful if you'd provided details of the table structure and approximate numbers of rows. Also using '*' for a SELECT is a messy practice - and will cause you problems later (see below).
What version of MySQL is this?
apparantly need to reorganise my query to accomodate GROUP within my primary SELECT clause
Not necessarily since v4 (? IIRC), you could just wrap your query in a consolidating select (but move the limit into the outer select:
SELECT ProfileGenderID, COUNT(*)
FROM (
[your query without the LIMIT]
) ilv
GROUP BY ProfileGenderID
LIMIT $limit;
(note you can't ORDER BY ilv.ProfileYearOfBirth since it is not a selected column / group by expression)
How many records/columns do you have in prm_breedgender? Is it just Stallions, Mares, Geldings...? Do you think this list is likely to change? Do you have ponies with multiple genders? I suspect that this domain would be better represented by an enum in the profiles table.
with the intention of being able to list a pony's Owner and Breeder,
Using the code you suggest, you'll only get returned instances where the owner and breeder are the same! You need to add a second instance of the contacts table with a different alias to get them all, e.g.
SELECT *
FROM (
SELECT *
FROM profiles
INNER JOIN prm_breedgender
ON profiles.ProfileGenderID = prm_breedgender.BreedGenderID
LEFT JOIN contacts ownerContact
ON profiles.ProfileOwnerID = ownerContact.ContactID
INNER JOIN prm_breedcolour
ON profiles.ProfileAdultColourID = prm_breedcolour.BreedColourID
) ilv LEFT JOIN contacts breederContact
ON ilv.ProfileBreederID = breederContact.ContactID
ORDER BY ilv.ProfileYearOfBirth ASC $limit