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
Related
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
all! I'm taking database class and have couple of questions that is so confusing to me. down below is my table
Student(S_ID, S_FIRST_NAME, S_LAST_NAME, S_MAJOR)
Course(C_ID, C_NAME, C_INST_NAME, C_ROOM)
takes(S_ID,C_ID)
Q-1.i want to select all the student_id who takes all courses taught by Davidson. I tried with this code
select s.S_ID from student s inner join (select t.S_ID from takes t inner join
course c on t.C_ID = c.C_ID group by t.S_ID having sum(case when c.C_INST_NAME
= 'Davidson' then 1 else 0 end) = 3) t on s.S_ID = t.S_ID;
it works because i know how many classes Davidson teaches(in my case 3). how do we write the query if we don't know how many classes he teaches?
Q-2. i want to select all the instructors who teach atleast 3 classes. For this question i did following
select distinct C_INST_NAME from course where C_ID >= 3;
+-------------+
| C_INST_NAME |
+-------------+
| Peterson |
| Davidson |
| Jackson |
| Hanney |
+-------------+
But i got all the instructor, any help would be appreciated thank you!
Q1.
SELECT
S_ID, GROUP_CONCAT(C_ID ORDER BY C_ID ASC)
FROM
takes
WHERE
GROUP_CONCAT(C_ID ORDER BY C_ID ASC) = (
SELECT
GROUP_CONCAT(Course.C_ID ORDER BY C_ID ASC)
FROM
Course
WHERE
Course.C_INST_NAME = "Davidson"
)
GROUP BY
S_ID
Q2.
SELECT
COUNT(C_ID) AS "numClassesTaught", Course.C_INST_NAME
FROM
Course
GROUP BY
Course.C_INST_NAME
HAVING
numClassesTaught >= 3
Those should both work.
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)
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I was given this MySQL Interview Question, which made me disqualified for the job.
I went to interview and was asked a question which I was not able to reply and I lost the job.
They asked.
We have two tables, the first table (master table) is CANDIDATES with fields:
candidate_id (primary_key)
candidate_name
The Second table (child table) is CANDIDATE_VOTES with fields:
v_id (primary key)
candidate_id (foreign key)
Every time a vote is given the candidate's candidate_key is put in the child.
CANDIDATE:
=================================
|candidate_id | candidate_Name |
|-------------------------------|
| 1 | abc |
|-------------------------------|
| 2 | xyz |
|-------------------------------|
| 3 | etc |
|-------------------------------|
CANDIDATE VOTES
==========================
| votes_id | candidate_id |
|-------------------------|
| 1 | 1 |
|-------------------------|
| 2 | 1 |
|-------------------------|
| 3 | 2 |
|-------------------------|
The Question was how would you declare a winner?
Please help me how to do it.
I tried a lot but could not find the logic.
You should return all candidates who have the most number of votes:
SELECT candidates.*
FROM candidates JOIN candidate_votes USING (candidate_id)
GROUP BY candidate_id
HAVING COUNT(*) = (
SELECT COUNT(*)
FROM candidate_votes
GROUP BY candidate_id
ORDER BY votes DESC
LIMIT 1
)
See it on sqlfiddle.
You can use a COUNT() to get the total number of votes associated with each candidate. By joining the two tables, you can return the candidate_name and if you use a LIMIT and ORDER BY on the query it will return only the record determined as the winner.
SELECT count(*) winner, c.candidate_Name
FROM candidates c
INNER JOIN candidate_votes cv
ON c.candidate_id = cv.candidate_id
GROUP BY c.candidate_Name
ORDER BY winner desc
LIMIT 1 -- remove the LIMIT to see all records
See SQL Fiddle with Demo
or MySQL allows to GROUP BY on fields not in the SELECT
SELECT count(*) winner, , c.candidate_Name
FROM candidates c
INNER JOIN candidate_votes cv
ON c.candidate_id = cv.candidate_id
GROUP BY cv.candidate_id
ORDER BY winner desc
LIMIT 1 -- remove the LIMIT to see all records
See SQL Fiddle with Demo
SELECT CANDIDATE_NAME, count(*)
FROM CANDIDATES, CANDIDATE_VOTES
WHERE CANDIDATES.CANDIDATE_ID = CANDIDATE_VOTES.CANDIDATE_ID
GROUP BY CANDIDATE_NAME
ORDER BY count(*) DESC
LIMIT 1
SELECT: you select the candidate names + the amount of votes
FROM: use both tables
WHERE: basicly a join to link the tables
GROUP BY: Group the votes per candidate name, the count(*) in the SELECT will show you the amount of lines that were grouped into 1 line (a.k.a. the amount of votes per candidate)
ORDER BY: order by amount of votes highest to lowest
LIMIT: Will only return 1 row, remove this line to see complete list of candidates and votes
There are several ways to this. One would be to use a GROUP BY:
SELECT TOP 1 C.candidate_id, C.candidate_name, COUNT(1) NoOfVotes
FROM CANDIDATES C
INNER JOIN CANDIDATE_VOTES CV ON C.candidate_id = CV.candidate_id
GROUP BY C.candidate_id, , C.candidate_name
ORDER BY 3 DESC
This statement creates one row for each vote then groups these rows by candidate and counts how many rows are there for each candidate. Then it orders by the counted votes per candidate and selects the top 1 (doesn't deal with ties though).
Edit: This answer is valid for T-SQL (SQL Server). It seems from the other answers that you need to use "LIMIT 1" at the end instead of the "TOP 1" at the beginning for MySQL.
I currently have this sql statement that I wrote and it works but it's not quite what I want. I've been working on it for hours but can't seem to get any further.
select parent.id as parent_id, parent.subject as parent,s.id,s.subject from (select s.id, s.subject from subjects s where parent_id = 0) parent join subjects s on parent.id = s.parent_id order by parent.subject, s.subject
It's grabbing all the subjects and ordering correctly but I also want to return the parent subject (parent_id = 0) at the top of each grouping. This is because some parents may not have subjects underneath but I still need to return them. Also the ordering is off when I try to do it as I want the parent first then it's child subjects. Hope that makes sense but if not just ask.
Any help would be appreciated.
Thanks
Steve
You're talking about grouping sets of rows by their parent rows.
The only way I know how to do this in MySQL is using the GROUP_CONCAT() function which won't group the subjects by row, but rather create a grouped string.
Here's what you can do:
SELECT
a.id,
a.subject,
GROUP_CONCAT(CONCAT(b.id, ':::', b.subject) ORDER BY b.subject SEPARATOR '|||') AS subjectlist
FROM
subjects a
LEFT JOIN
subjects b ON a.id = b.parent_id
WHERE
a.parent_id = 0
GROUP BY
a.id,
a.subject
ORDER BY
a.subject
So this will give you a result set like:
id | subject | subjectlist
---------------------------------------------------------------------
2 | subj1 | 23:::childsubj1|||28:::childsubj4
3 | subj2 | 18:::childsubj8|||55:::childsubj16
4 | subj3 | NULL
Depending on what language you are using in your application, you may be able to "explode" the subjects string into arrays delimited first by ||| which separates each subject, then ::: which separates that subject's ID and name.
Obviously, the downside of this is you have to make sure that your child subject name does not contain either ||| or ::: or whichever delimiters you decide to use.
Edit: Experimentally, I came up with this alternative solution which may be closer to what you're looking for:
Try:
SELECT
c.subj,
c.id
FROM
(
SELECT
CONCAT('---> ', b.subject) AS subj,
b.id,
CONCAT(a.subject, b.subject) AS orderfactor
FROM
subjects a
INNER JOIN
subjects b ON a.id = b.parent_id
WHERE
a.parent_id = 0
UNION ALL
SELECT
subject AS subj,
id,
subject AS orderfactor
FROM
subjects
WHERE
parent_id = 0
) c
ORDER BY
c.orderfactor
This query should give you a result along the lines of:
subject | id |
----------------------------------------------------------
subj1 | 2 |
---> childsubj1 | 23 |
---> childsubj4 | 28 |
subj2 | 3 |
---> childsubj8 | 18 |
---> childsubj16 | 55 |
subj3 | 4 |
subj4 | 5 |
---> childsubj10 | 79 |