This question already has answers here:
SQL query to count number of times certain values occur in multiple rows
(5 answers)
Closed 4 years ago.
SELECT firstname, lastname, id
FROM contact
WHERE id IN
(SELECT contactid
FROM taglist
WHERE contactid IN
(SELECT contactid
FROM customerlist
WHERE companyid = 1) AND (tagid = 1 OR tagid = 4))
I have the query above where there is a single table that has a userid and a tag id. Each user can have multiple tags that are listed as separate entries on this table.
I need to be able to select only users with two or more specified tags. I thought the above query would do this, but it is returning every user with either tag 1 or tag 4.
If I change it to this: (tagid = 1 AND tagid = 4)) I get 0 results because it is only looking at each individual entry, and no entry has more than one tag per user.
This example only has two tags selected, but the goal here is to allow the end user to be able to select any number of available tags and only show results where the user matches all selected tags.
I don't have any way to know a specific number of tags that are going to be selected to match on. Currently there are 20 available tags, and clients can add their own tags if they wish.
So how do I accomplish this? I am very new to SQL queries, and not very familiar with joins yet so I am thinking this is going to have something to do with it, but I don't know. Any nudges in the right direction would be greatly appreciated.
You can get contacts with the two tags by doing:
SELECT contactid
FROM taglist
WHERE tagid IN (1, 4)
GROUP BY contactid
HAVING COUNT(*) = 2;
The rest of your query is doing other stuff not mentioned in your question, so it is unclear what you really want. Obviously, you can use this as a subquery to get full contact information.
Related
This question already has answers here:
SELECTING with multiple WHERE conditions on same column
(12 answers)
Closed 1 year ago.
I don't know if the question title is so clear, but here is my question:
I had table UsersMovements which contains Users along with their movements
UsersMovements:
ID
UserID
MovementID
Comments
I need help looking for a query which would give me if users 1, 2 & 3 had been in a common MovementID, knowing that I had know what is the MovementID
The real case is that I want to see if those X users which I would select been in an area (in a limited interval, assuming I had date/Time in the table)
Thank you
The following returns all movement ids that have all three users:
select movementid
from usermovements
where userid in (1, 2, 3)
group by movementid
having count(distinct userid) = 3
Apologies for the title as I'm a bit unsure how to phrase this myself so hopefully an example might help.
I've got a MySQL table that holds questions
question_id, PK Int
text - Text
I also have a table called value that looks like this
value_id, PK Int
value - varchar
I think I might need a mapping table for this along the lines of
question_to_value
question_id int
value_id int
Though if my example looks like I don't need one then I can change the structure
Basically, given a single or multiple value_ids I want to pick the question that should be asked
so if I am given value_ids 1,2 I should have a unique question_id relating to those ids in the database. Given a value_id of 3 there should be a different question_id, and an input of value_ids (1,2,3) or 1,3 should again retrieve unique question_ids for both permutations.
I'm struggling with how I should go about it. Should I use a) a sort of joining table for this, and b) Most efficient way of querying it.
My initial thought it to have a question_to_value table that holds a question_id and value_id on a 1-1 basis, then doing the following
select question_id from question WHERE value_id in (?,?,?) but i'm not sure if this is the optimal way to structure this. Especially as the trouble is using the 'IN' query above if I'm just given the value_id of 1, it would actually bring back all the questions where value_id '1' is the only or part of the group of values to product a particular question. e.g
question_id 1 maps to value 1
question_id 2 maps to values of 1 and 2.
my in statement would bring back question_ids 1 and 2 for a value_id of 1 when I only want question_id 1 as it should match all criteria.
Any ideas on how I should structure this?
*** editing I'm trying to come up with another way of phrasing this to avoid confusion so hopefully the following will help
consider I have 4 'questions'
a
b
c
d
If I'm given an input of 1 I only want to retrieve a.
If I'm given 2 inputs of 1 and 2 I only want to retrieve b.
If I'm given 3 inputs of 1,2,3 I only want to retrieve c.
If I'm given 2 inputs of 1 and 3 I only want to retrieve d.
I'm trying to break the problem apart into component parts to define the question in a way that can be expressed in code.
I'm working on the idea that the proper question must match two rules:
The question must have an entry for each of the input values
The question must not have entries for any other input value
First, consider a query that returns all the value ids for the inputs.
SELECT value_id from values where `value` IN <inputs>
I don't know what language you are using, so I can't tell you how to build the inputs list. In php, it would be something like:
"('" . implode("','" $inputs) . "')"
to properly wrap each option in quotes (assuming the values don't also have quotes, but that's a separate, language-specific problem to solve).
Now it is simple to use that query to create a query that returns questions that have ANY of the input values:
SELECT question_id
FROM mapping_table
WHERE value_id IN (SELECT value_id from values where `value` IN <inputs>)
Finally, we can tweak that query to only return the question_ids with the right number of matches. We want one row for each question, and we only want questions that match all the values:
SELECT question_id
FROM mapping_table
WHERE value_id IN (SELECT value_id from values where `value` IN <inputs>)
GROUP BY question_id
HAVING COUNT(question_id) = <number of inputs>
That will give you a list of question_ids that match constraint 1 above. It will not test for constraint 2 in every case; if the input is (1,2) then this will match the question for (1,2) and the question for (1,2,3).
However, if you only get one row back from this query, there is no need to filter that list with the second query.
If you did get more than one match for the above, the second query is pretty simple - it's similar to the above query but with a different WHERE clause. This will get all the mapping table entries for the ids from the first query, and match the ones that don't have any extras:
SELECT question_id
FROM mapping_table
WHERE question_id IN <ids from first query>
GROUP BY question_id
HAVING COUNT(question_id) = <number of inputs>
You could combine the two queries, but unless performance is an issue, I'd keep them separate to make things easier to maintain.
NOTE: there is nothing here to constrain your data to make sure it is valid. In other words, there's nothing to prevent two questions from matching (1,2) when the questions are added to the database.
I am trying to design a query that picks up duplicate records from across two tables based on a few fields. I've set up what I've done so far here: http://sqlfiddle.com/#!2/e36c8d/1/0
Some context:
1) These two tables identified below house 'items' for a game that players play. Items come from either drops from monsters/player trades.
2) Players in the game are identified by their CharID
3) Items are primarily defined by the following unique fields: Name, ItemID, ID1, ID2, ID3.
4) There are other attributes for each item, but these can be changed depending on what the player does (e.g. changes colour of item; moves it position, upgrades it).
5) There are two tables where items are stored: ITEM and BANKITEM. Item = bag; Bankitem = warehouse.
There are occasions where players can (accidentally, or intentionally) duplicate individual items and then trade those items to other players or use on another one of their characters.
Needs (Really important to meet all 3 needs):
1) I need the query to scan both tables simultaneously to identify items that have duplicate Name, ItemID, ID1, ID2, ID3 that I can then investigate further (and delete one of the duplicates).
2) I need the query to exclude certain items based on Name (e.g., RedPotions all have the same Name, ItemID, ID1, ID2, and ID3. These are common items and duplicates are fine...I don't need them included in the listing as they are not rare/high value items).
3) I need the query to exclude CharID that are NULL (This is where I am having real difficulty because CharID is not part of my SELECT statement, and it can't be because it is entirely possible for two different CharIDs to have the same duplicate rare item).
SQL FIDDLE:
If the query was working properly, the results should show:
2 duplicate ChainHose(M) with the following common fields: ChainHose(M), 100, 17089, 22452, -12225
The ChainHose(M) with the CharID of '0' would be excluded from the listing. Note the actual field in the table is NULL and not '0'. (I am new to SQL/SQL Fiddle and wasn't sure how to make it 'NULL' in SQL Fiddle for example purposes.
2 duplicate Hauberk(W) with the following common fields: Hauberk(W), 200, 12369, 15252, 95682. It doesn't matter that the colour and lifespan are different (player with the duplicate could have dyed the armour after obtaining the duplicated item. The lifespan could have been reduced through use).
Does anyone have any advice? I've previously asked a similar question without resolve (see Advanced SQL Query Design Help (Duplicates across two tables, multiple fields, possible exclusions based on one field)). The person recommended I be more specific and to use SQL Fiddle, so I have done so in hopes I can get this working properly.
Thanks in advance.
Is this what you need?
SQL Fiddle
SELECT *
from bankitem
where exists(
SELECT Name, ItemID, ID1, ID2, ID3
from item
where bankitem.Name = item.Name
and bankitem.ItemID = item.ItemID
and bankitem.ID1 = item.ID1
and bankitem.ID2 = item.ID2
and bankitem.ID3 = item.ID3
)
and name not in('RedPotion')
and charid <> 0
Here is the general setup.
I have the tables Cards, Attributes, and a join table between them. (Let's call it Tags. It contains a CardID and an AttributeID.) The Attributes table is mostly just descriptions such as HasPower, IsPoisonous, ImmuneToWater, etc.
How would I go about querying for all cards that are both IsPoisonous and IsElectric? Let's assume I have the IDs for those already (13 and 45), so technically, the Attributes table does not need to be part of this SQL. I concocted something like this, but I'm not even sure if it is optimal.
SELECT *, (COUNT * FROM Tags t WHERE t.CardID = c.CardID AND t.AttributeID IN (13, 45)) AS TagCount
FROM Cards c
WHERE TagCount = 2
I hope my question makes sense. Basically, imagine you are looking at a web UI; you are sifting through a pool of ~5000 cards and want to filter down your results. So, you start checking boxes: "Poisonous", "Electric", "Immune to Water", etc. The results then filter down based on those attributes.
Thoughts?
SELECT *
FROM Cards
WHERE (Cards.Id IN (
SELECT DISTINCT CardID
FROM Tags
WHERE AttributeID IN (13, 45)
GROUP BY CardID
HAVING (COUNT(AttributeID) >= 2)
))
Inner query fetches the CardIDs that have at least two of the attributes you'd specified, then uses that result as a filter to fetch the actual card data in the outer query.
Although you could use multiple JOINs, I recommend you redesign your DB so that the attributes are simply columns in the Cards table.
I don't think this is a duplicate posting because I've looked around and this seems a bit more specific than whats already been asked (but I could be wrong).
I have 4 tables and one of them is just a lookup table
SELECT exercises.id as exid, name, sets, reps, type, movement, categories.id
FROM exercises
INNER JOIN exercisecategory ON exercises.id = exerciseid
INNER JOIN categories ON categoryid = categories.id
INNER JOIN workoutcategory ON workoutid = workoutcategory.id
WHERE (workoutcategory.id = '$workouttypeid')
AND rand_id > UNIX_TIMESTAMP()
ORDER BY rand_id ASC LIMIT 6;
exercises table contains a list of exercise names, sets, reps, and an id
categories table contains an id, musclegroup, and type of movement
workoutcategory table contains an id, and a more specific motion (ie: upper body push, or upper body pull)
exercisecategory table is the lookup table that contains (and matches the id's) for exerciseid, categoryid, and workoutid
I've also added a column to the exercises table that generates a random number upon entering the row in the database. This number is then updated only for the specified category when it is called, and then sorted and displays the ascending order of the top 6 listings. This generates a nice random entry for me. (Found that solution elsewhere here on SO).
This works fine for generating 6 random exercises from a specific top level category. But I'd like to drill down further. Here's an example...
select all rows inside categoryid 4
then still within the category 4 results, find all that have movementid 2, and then find one entry with a typeid 1, then another for typeid 2, etc
TLDR; Basically there's a few levels of categories and I'm looking to select a few from here and a few from there and they're all within this top level. I'm thinking this could all be executed within more than one query but im not sure how... in the end I'm looking to end with one array of the randomized entries.
Sorry for the long read, its the best explanation I've got.
Just realized I never came back to this posting...
I ended up using several mysql queries within a switch based on what is needed during the request. Worked out perfectly.