mysql select when matching multiple rows - mysql

I have a project where I need to select only the users that answered to some questions in a certain way (based on a filter).
The filter table (filter) looks like this
question | answer
Q1 | A
Q2 | B
The user table (answers) looks like this
user | question | answer
1 | Q1 | A
1 | Q2 | D
2 | Q1 | A
2 | Q2 | B
How can I select from the user table only the user(s) that match the filter?
I tried
"SELECT user FROM answers WHERE (question = Q1 AND answer = A)
AND (question = Q2 AND answer = B)"
and it doesn't work -- I get an empty result. Thank you.

In your query you are asking to get data which is not present. You are trying to get that user which has both the combination.
Try this
SELECT user FROM answers WHERE (question = 'Q1' AND answer = 'A')
OR (question = 'Q2' AND answer = 'B')

try this
select answers.user
from filter, answers
where filter.question=answers.question and filter.answer=answers.answer
group by answers.user having count(answers.question)=2
or
select user
from answers
where user not in
(select distinct a.user from answers a, filter f
where a.question=f.question and a.answer!=f.answer)

Try this:
Select
DISTINCT(userId)
from user_table ut
inner join filtertable ft on (ut.question=ft.question and ut.answer=ft.answer)

Related

Query database to obtain first unique value

I have a pretty simple table like this:
id | custom_id | answer
----------------------------------
1 | 123 | Answer 1
__________________________________
2 | 123 | Answer 2
__________________________________
3 | 422 | Answer 3
__________________________________
4 | 345 | Answer 2
__________________________________
5 | 992 | Answer 1
__________________________________
6 | 452 | No answer
__________________________________
What I am trying to do is count the number of Answer 1, Answer 2, etc. So, for the above data I would expect to get:
2 * Answer 1
2 * Answer 2
1 * Answer 3
Note, that anything that is No answer should be discarded.
However, further to the above, I want to take into account only one answer per custom_id, and this should be their first answer. So really, the output I expect to get for the above data should be:
2 * Answer 1
1 * Answer 2
1 * Answer 3
This is because we take only the first answer for custom_id = 123.
So far, I have made the following query:
select
answer,
count(*) as totalCount
from
" . DB_TABLE . "
where
answer <> 'No answer'
group by
custom_id
However, this seems to return the total counts (as I explained first), not taking into consideration that there should only be one per custom_id. I thought the group by would solve this issue, but this does not seem to be the case.
How can I achieve the results I am after?
Thanks
One approach, will be first to create a derived table with the IDs of the first answers for every custom_id and also filter those with values No answer (since you want to ignore they), like this:
SELECT
custom_id,
MIN(id) AS firstAnswerID
FROM
<table_name>
WHERE
answer <> "No Answer"
GROUP BY
custom_id
Then, we can join the original table with this previous one on the ID column (this will act like a filter for those that aren't first answers or have the No answer value), make a GROUP BY the answer column and count the numbers of each one. In summary, this will do what you want:
SELECT
t1.answer,
COUNT(*) AS NumTimes
FROM
<table_name> AS t1
INNER JOIN
( SELECT
custom_id,
MIN(id) AS firstAnswerID
FROM
<table_name>
WHERE
answer <> "No Answer"
GROUP BY
custom_id ) AS t2 ON t2.firstAnswerID = t1.id
GROUP BY
t1.answer
ORDER BY
NumTimes DESC
You can play with this here: DB Fiddle
Try to use this:
select answer, count(answer) as totalCount from " . DB_TABLE .
" where answer <> 'No answer' group by answer
You should count rows for every answer group, not for the entire table.

Query: I have 4 rows, need to add the results from 3 rows into one, and leave the last row untouched

I have a kind of tricky question for this query. First the code:
SELECT user_type.user_type_description,COUNT(incident.user_id) as Quantity
FROM incident
INNER JOIN user ON incident.user_id=user.user_id
INNER JOIN user_type ON user.user_type=user_type.user_type
WHERE incident.code=2
GROUP BY user.user_type
What Am I doing?
For example, I am counting police reports of robbery, made from different kind of users. In my example, "admin" users reported 6 incidents of code "2" (robbery) and so on, as is showed in 'where' clause (incident must be robbery, also code 2).
this brings the following result:
+-----------------------+----------+
| user_type_description | Quantity |
+-----------------------+----------+
| Admin | 6 |
| Moderator | 8 |
| Fully_registered_user | 8 |
| anonymous_user | 9 |
+-----------------------+----------+
Basically Admin,Moderator and Fully_registered_user are appropriately registered users. I need to add them in a result where it shows like:
+--------------+------------+
| Proper_users | Anonymous |
+--------------+------------+
| 22 | 9 |
+--------------+------------+
I am not good with sql. Any help is appreciated. Thanks.
You can try to use condition aggregate function base on your current result set.
SUM with CASE WHEN expression.
SELECT SUM(CASE WHEN user_type_description IN ('Admin','Moderator','Fully_registered_user') THEN Quantity END) Proper_users,
SUM(CASE WHEN user_type_description = 'anonymous_user' THEN Quantity END) Anonymous
FROM (
SELECT user_type.user_type_description,COUNT(incident.user_id) as Quantity
FROM incident
INNER JOIN user ON incident.user_id=user.user_id
INNER JOIN user_type ON user.user_type=user_type.user_type
WHERE incident.code=2
GROUP BY user.user_type
) t1
You just need conditional aggregation:
SELECT SUM( ut.user_type_description IN ('Admin', 'Moderator', 'Fully_registered_user') ) as Proper_users,
SUM( ut.user_type_description IN ('anonymous_user') as anonymous
FROM incident i INNER JOIN
user u
ON i.user_id = u.user_id INNER JOIN
user_type ut
ON u.user_type = ut.user_type
WHERE i.code = 2;
Notes:
Table aliases make the query easier to write and to read.
This uses a MySQL shortcut for adding values -- just just adding the booelean expressions.
I would solve it with a CTE, but it would be better to have this association in a table.
WITH
user_type_categories
AS
(
SELECT 'Admin' AS [user_type_description] , 'Proper_users' AS [user_type_category]
UNION SELECT 'Moderator' AS [user_type_description] , 'Proper_users' AS [user_type_category]
UNION SELECT 'Fully_registered_user' AS [user_type_description] , 'Proper_users' AS [user_type_category]
UNION SELECT 'anonymous_user' AS [user_type_description] , 'Anonymous' AS [user_type_category]
)
SELECT
CASE WHEN utc.[user_type_category] = 'Proper_users' THEN
SUM(incident.user_id)
END AS [Proper_Users_Quantity]
, CASE WHEN utc.[user_type_category] = 'Anonymous' THEN
SUM(incident.user_id)
END AS [Anonymous_Quantity]
FROM
[incident]
INNER JOIN [user] ON [incident].[user_id] = [user].[user_id]
INNER JOIN [user_type] ON [user].[user_type] = [user_type].[user_type]
LEFT JOIN user_type_categories AS utc ON utc.[user_type_description] = [user_type].[user_type_description]
WHERE
[incident].[code] = 2

mysql - check if former entry of uid has property

Since this is my first question here,
pls be gentle :)
In case the following qustion has already been dealt with,
I would be happy to get some links that answer my qustion.
I have a database which contains a log of items beeing moved around in a warehouse.
example:
tablename: inventory_history
Id , Uid , location
1 | a1 | location1
2 | a2 | location2
3 | a3 | location3
4 | a3 | location5
5 | a2 | badlocation
I want to select Id, Uid and location but only if the location of the fromer entry of the same Uid(but lower Id) is not eqaul to 'badlocation'.
So I want to check if the entry of the same Uid with the next lower Id hat 'badlocation' as value for location.
My first thought was to manage this with subquerys but on second thought i think it would be much faster and more clean if one could do this with a join.
I tried something like this:
SELECT a.id, a.uid, a.location from
wms_inventory_history as a
Inner Join wms_inventory_history as b ON (a.uid = b.uid)
Where a.id > b.id limit 1,1 AND
a.location != 'bad_location'

How to find missing rows in second table from first table in my case? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have two tables.
Table1: First
--------------------------
| iso | WeldNo |
--------------------------
| AMD-11201-01 | 02 |
| RFG-11203-01 | 01 |
| AMD-11201-01 | 03 |
| RFG-11203-01 | 05 |
Table2: Second
--------------------------
| iso | WeldNo |
--------------------------
| AMD-11201-01 | 02 |
| RFG-11203-01 | 01 |
| RFG-11203-01 | 05 |
Expected Result:
--------------------------
| iso | WeldNo |
--------------------------
| AMD-11201-01 | 03 |
i tried query but wont work
select a.iso, a.WeldNo
from first a
where a.WeldNo, a.iso not in (select b.iso,b.WeldNo from second b);
Kindly give solution to my scenario
From the tags on the question it is not clear which RDBMS you are using. If you are using SQL Server you can use EXCEPT:
select a.iso, a.WeldNo
from first a
EXCEPT
select b.iso, b.WeldNo
from second b
This selects all items from the SELECT statement, except for the ones that are found in the second SELECT statement.
If you are using MySQL you could slightly fix your query (i.e. add parenthesis) and you should get a working query:
select a.iso, a.WeldNo
from first a
where (a.WeldNo, a.iso) not in (select b.WeldNo, b.iso from second b)
select f.*
from first_table f
left join second_table s on s.iso = f.iso
and s.WeldNo = f.WeldNo
where s.iso is null
Also see this great explanation of joins
You can use either a LEFT JOIN or an EXCEPT.
Left Join:
SELECT t1.iso, t1.WeldNo
FROM Table1 t1
LEFT JOIN Table2 t2 ON t1.iso = t2.iso AND t1.WeldNo = t2.WeldNo
WHERE t2.iso IS NULL
Except:
SELECT iso, WeldNo
FROM Table1
EXECEPT
SELECT iso, WeldNo
FROM Table2
There are some differences, though. In the case of except, both results have to have the same columns, while the LEFT JOIN lets you specify what to select from each table. Also, in most cases, the LEFT JOIN is going to be more performant, as it is better optimized. However, the EXCEPT will only return unique rows from the first query that are missing from the second query, so it might be more applicable to the situation. Of course, you could add a DISTINCT To the first query for a similar result:
SELECT DISTINCT t1.iso, t1.WeldNo
FROM Table1 t1
LEFT JOIN Table2 t2 ON t1.iso = t2.iso AND t1.WeldNo = t2.WeldNo
WHERE t2.iso IS NULL
All that said, it's probably better to use the LEFT JOIN, however it may vary depending on your database.
I would use not exists because it expresses the intent clearly i.e. "select all rows from table1 where a row in table2 with the same iso and WeldNo does not exist"
select * from table1 t1
where not exists (
select 1 from table2 t2
where t2.iso = t1.iso
and t2.WeldNo = t1.WeldNo
)

Group by in complex query with cases [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 8 years ago.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Improve this question
I have a table:
Visit (FromId, ToId, VisitTime)
where FromId and ToId are FKs to table
UserProfile (uid, name, age ...)
As a user with my UID I want to select all profiles I have visited or who visited me in one result set ordered by VisitTime and with the indication of the "direction of the visit".
I get data using this select:
SELECT CASE WHEN a.FromID = 'yourIDHere'
THEN c.Name
ELSE b.Name
END Name,
CASE WHEN a.FromID = 'yourIDHere'
THEN c.Age
ELSE b.Age
END Age,
a.VisitTime,
CASE WHEN a.FromID = 'yourIDHere'
THEN 'You'
ELSE 'Friend'
END DirectionOfVisit
FROM Visit a
INNER JOIN UserProfile b
ON a.FromID = b.Uid
INNER JOIN UserProfile c
ON a.ToID = c.Uid
WHERE 'yourIDHere' IN (a.FromID, a.ToID)
ORDER BY a.VisitTime
Now it prints (pseudo output)
Jack (id1) | IN |12.12.2012
Jack (id1) | IN |11.12.2012
Jack (id1) | IN |11.12.2012
Jack (id1) | OUT | 13.12.2012
Jack (id1) | OUT | 12.12.2012
Michael (id5) | IN | 5.12.2012
Michael (id5) | OUT | 6.12.2012
Michael (id5) | OUT | 5.12.2012
I would like the list to be like this:
Jack | IN | 12.12.2012 (the most recent)
Jack | OUT | 13.12.2012 (the most recent)
Michael (id5) | IN | 5.12.2012 (the most recent)
Michael (id5) | OUT | 6.12.2012 (the most recent)
I know the GROUP command would solve it but it's too complex for me (beginner).
You could use GROUP BY along with an aggregate function to get the result. Since you want the most recent date for each name and type (IN/OUT), then you can use the max() aggregate function on the date column. You will then use a GROUP BY on the other columns you want to return:
The basic syntax will be:
select
name,
type,
max(date) date
from yourtable
group by name, type;
See SQL Fiddle with Demo
If you want to return the max date with your existing query, you can just expand the query to use:
select name, age, max(VisitTime), DirectionOfVisit
from
(
SELECT CASE WHEN a.FromID = 'yourIDHere'
THEN c.Name
ELSE b.Name
END Name,
CASE WHEN a.FromID = 'yourIDHere'
THEN c.Age
ELSE b.Age
END Age,
a.VisitTime,
CASE WHEN a.FromID = 'yourIDHere'
THEN 'You'
ELSE 'Friend'
END DirectionOfVisit
FROM Visit a
INNER JOIN UserProfile b
ON a.FromID = b.Uid
INNER JOIN UserProfile c
ON a.ToID = c.Uid
WHERE 'yourIDHere' IN (a.FromID, a.ToID)
) d
group by name, age, DirectionOfVisit;
See SQL Fiddle with Demo