I am mostly new to SQL and ran across a situation that I can't figure out. Say that I have 2 tables: P and A.
Person id Live Income
--------- -- ---- ------
Tom 1 House 10
Sarah 2 Apt 7
Sterling 3 Playpen 0
Chris 4 House 6
Juanita 5 Apt 12
...
Live2 id Attribute
--------- -- -----
House 1 Job
House 2 Car
House 3 Kids
Apt 4 Job
Apt 5 Car
Playpen 6 Diapers
So if you have a 'House' then you always also have a Job, Car, and Kids. If you have a Playpen then you only have Diapers (and never a Job).
What I am trying to do (without double-counting people) is find the total income for 'House' people (Live='House', the 1st category), then 'Job' people (Attribute='Job', 2nd category), then 'Diaper' people, etc. So Tom is counted as a 'House' person but not a 'Job' person (because he has been previously classified and I don't want to double-count income).
Logically I can think of several ways to approach and based on my research this seems to be a perfect place to use the long form of CASE because I can specify conditions from different columns. BUT, I can't seem to join the tables in a way that I don't end up double counting income by creating too many rows. For example, I'll JOIN them and it will create 3 Tom entries (one each for Job, Car, Kids).
IMO either we need multiple 'Attribute' columns (one each for Job, Car, Kids, Diapers) so 'Tom' is still fully described on one row or some way to ignore all the other 'Tom' rows once he has been counted in a classification.
without knowing some additional details im guessing this is what you want... table a is the one with the person in it table b has live2 in it
SELECT
SUM(CASE WHEN live = 'House' THEN income ELSE 0 END) as house,
SUM(CASE WHEN live = 'Apt' THEN income ELSE 0 END) as apt,
SUM(CASE WHEN live = 'Playpen' THEN income ELSE 0 END) as playpen
FROM
( SELECT a.*
FROM a
JOIN b ON b.live2 = a.live
GROUP BY a.id
)t
DEMO
what this is assuming is that besides house the only other live is apt that can have a job. if thats the case then this query will do what you want.
If you want to actually specify 'Job' in the query then you can do it like this.
SELECT
SUM(CASE WHEN live = 'House' THEN income ELSE 0 END) as house,
SUM(CASE WHEN attribute = 'Job' AND live2 <> 'House' THEN income ELSE 0 END) as apt,
SUM(CASE WHEN live = 'Playpen' THEN income ELSE 0 END) as playpen
FROM
( SELECT a.*, b.live2, b.attribute
FROM a
JOIN b ON b.live2 = a.live
GROUP BY a.id
)t
you could also join with each field specified.. if you want an example I can show you
You're question is a bit strange, I'll agree. There isn't any complication since none of your persons live in a house and an apartment...
select live,
sum(income) income,
count(*) people
from p
left join
a
on p.live = a.live2
and a.attribute = 'job'
group by live
Related
A sample record:
Row(user_id='KxGeqg5ccByhaZfQRI4Nnw', gender='male', year='2015', month='September', day='20',
hour='16', weekday='Sunday', reviewClass='place love back', business_id='S75Lf-Q3bCCckQ3w7mSN2g',
business_name='Notorious Burgers', city='Scottsdale', categories='Nightlife, American (New), Burgers,
Comfort Food, Cocktail Bars, Restaurants, Food, Bars, American (Traditional)', user_funny='1',
review_sentiment='Positive', friend_id='my4q3Sy6Ei45V58N2l8VGw')
This table has more than a 100 million records. My SQL query is doing the following:
Select the most occurring review_sentiment among the friends (friend_id) and the most occurring gender among friends of a particular user visiting a specific business
friend_id is eventually a user_id
Example Scenario:
One user
Has Visited 4 Businesses
Has 10 friends
5 of these friends have visited Business 1 & 2 while other 5 have
visited 3rd business only and none have visited the fourth
Now, for Business 1 and 2, the 5 friends have more positive than
negative sentiments for B1 and have more -ve than +ve sentiment for
B2 and all -ve for B3
I want the following output for this:
**user_id | business_id | friend_common_sentiment | mostCommonGender | .... otherCols**
user_id_1 | business_id_1 | positive | male | .... otherCols
user_id_1 | business_id_2 | negative | female | .... otherCols
user_id_1 | business_id_3 | negative | female | .... otherCols
Here's a simple query I wrote for this in pyspark:
SELECT user_id, gender, year, month, day, hour, weekday, reviewClass, business_id, business_name, city,
categories, user_funny, review_sentiment FROM events1 GROUP BY user_id, friend_id, business_id ORDER BY
COUNT(review_sentiment DESC LIMIT 1
This query will not give what is expected but I'm not sure how exactly to fit in a INNER-JOIN into this?
Man does that data structure make things hard. But lets break it down into steps,
You need to self join to get the data for friends
Once you have the data for friends, perform aggregate functions to get counts of each possible value, grouping by the user and the business
sub query the above in order to make decisions between the values based on counts.
I'm just going to call your table "tags", so the join would be as follows, sadly just like in real life we can't assume everyone has friends, and since you didn't specify to exclude the forever alone crowd, we need to use a left join to keep users without friends.
From tags as user
left outer join tags as friends on user.friend_id = friends.user_id
and friends.business_id = user.business_id
Next you have to figure out what the most common gender/review is for a given user and business combination. This is where the data structure really kicks us in the butt, we could do this in one step with some clever window functions, but I want this answer to be easily understood, so I'm going to use a sub-query and a case statements. For the sake of simplicity I'm assuming binary genders, but depending on the woke level of your app, you can follow the same patterns for additional genders.
select user.user_id, user.business_id
, sum(case when friends.gender = 'Male' then 1 else 0 end) as MaleFriends
, sum(case when friends.gender = 'Female' then 1 else 0 end) as FemaleFriends
, sum(case when friends.review_sentiment = 'Positive' then 1 else 0 end) as FriendsPositive
, sum(case when friends.review_sentiment = 'Negative' then 1 else 0 end) as FriendsNegative
From tags as user
left outer join tags as friends on user.friend_id = friends.user_id
and friends.business_id = user.business_id
where user.business_id = <<your business id here>>
group by user.user_id, user.business_id
Now we just have to grab data from the sub-query and make some decisions, you may want to add some additional options, for instance you may want to add options in case there are no friends, or friends are evenly split between gender/sentiment. same pattern as below though with extra values to choose from.
select user_id
, business_id
, case when MaleFriends > than FemaleFriends then 'Male' else 'Female' as MostCommonGender
, case when FriendsPositive > FriendsNegative then 'Positive' else 'Negative' as MostCommonSentiment
from ( select user.user_id, user.business_id
, sum(case when friends.gender = 'Male' then 1 else 0 end) as MaleFriends
, sum(case when friends.gender = 'Female' then 1 else 0 end) as FemaleFriends
, sum(case when friends.review_sentiment = 'Positive' then 1 else 0 end) as FriendsPositive
, sum(case when friends.review_sentiment = 'Negative' then 1 else 0 end) as FriendsNegative
From tags as user
left outer join tags as friends on user.friend_id = friends.user_id
and friends.business_id = user.business_id
where user.business_id = <<your business id here>>
group by user.user_id, user.business_id) as a
This gives you the steps to follow, and hopefully a clear explanation on how they work. Good luck!
I am not entirely sure even how to name this post, because I do not know exactly how to ask it.
I have three tables. One with users, one with foods and one with the users rating of the foods, like such (simplified example):
Foods
id name type
---------------------
1 Apple fruit
2 Banana fruit
3 Steak meat
Users
id username
-----------------
1 Mark
2 Harrison
3 Carrie
Scores (fid = food id, uid = user id)
fid uid score
---------------------
1 1 3
1 2 5
2 1 2
3 2 3
Now, I have this query, which works perfectly:
SELECT fn.name as Food, ROUND(AVG(s.score),1) AS AvgScore FROM Foods fn LEFT JOIN Scores s ON fn.id = s.fid GROUP BY fn.id ORDER BY fn.name ASC
As you can tell, it lists all names from Foods including an average from all users ratings of the food.
I also want to add the unique users own score. (Assume that when Mark is logged in, his uid is set in a session variable or whatever)
I need the following output, if you are logged in as Mark:
Food AvgScore Your Score
Apple 4 3
I have made several attempts to make this happen, but I cannot find the solution. I have learned that if you have a question, it is very likely that someone else has asked it before you do, but I do not quite know how to phrase the question, so I get no answers when googling. A pointer in the right direction would be much appreciated.
You can try with case:
SELECT fn.name as Food,
ROUND(AVG(s.score),1) AS AvgScore,
sum(case s.uid = $uid when s.score else 0 end) as YourScore
FROM Foods fn
LEFT JOIN Scores s ON fn.id = s.fid
GROUP BY fn.id
ORDER BY fn.name ASC
$uid is variable off course.
I'm trying to count some results from a query. I've been through the various examples on here but none of them are adaptable enough to do what I'm trying to do.
If someone could take a look, point out where I'm going wrong, and kindly put me out of my misery, that would be wonderful. Thank-you.
Four Tables: Areas, Departments, Systems and Checks
Each Area has many Departments. Each Department has many Systems; and each System has many Checks. I'm trying to find out how many different Systems (by System_ID) have been checked in the previous week.
Current Query
Select
a.Area_Name,
d.Department_Name,
s.System_ID,
s.System_Name,
c.Check_Date
from departments d
left join areas a
on a.Area_ID = d.Department_Area
left join systems s
on s.System_Department = d.Department_ID
left join checks c
on c.Check_System_ID = s.System_ID
where Week(c.Check_Date) = Week(Now())
and Year(c.Check_Date) = Year(Now())
Returns the Following :
Area_Name | Department_Name | System_ID | System_Name | Check_Date
Area 1 Department 1 1 System 1 2017-02-27
Area 1 Department 1 1 System 1 2017-02-27
Area 1 Department 1 2 System 2 2017-02-27
Area 1 Department 2 3 System 3 2017-02-27
What I'm trying to get to will group the areas, departments, systems etc. To show a count of how many different systems have been checked in the week.
(I'm aware I haven't included any count or group-by in the query... I've left them out purposely to provide context. I have tried every possible way I can think but my knowledge is obviously lacking somewhere)
Desired Result
Area_Name | Department_Name | Count_Checks
Area 1 Department 1 2
Area 1 Department 2 1
As you can see, the desired result has grouped the two System 1 and treated them as 1 (as it's a single unique system), to show that over the last week, 2 different systems have been checked from department 1 and only 1 from department 2.
If anyone can shed some light... please do!
Thanks in advance for any help!
Use GROUP BY and aggregate using a combination of area/department as group:
SELECT a.Area_Name,
d.Department_Name,
COUNT(DISTINCT s.System_ID) AS Count_Checks
FROM departments d
LEFT JOIN areas a
ON a.Area_ID = d.Department_Area
LEFT JOIN systems s
ON s.System_Department = d.Department_ID
LEFT JOIN checks c
ON c.Check_System_ID = s.System_ID AND
WEEK(c.Check_Date) = WEEK(NOW()) AND
YEAR(c.Check_Date) = YEAR(NOW())
GROUP BY a.Area_Name,
d.Department_Name
One part of the query which might not be obvious is the code used to determine Count_Checks:
COUNT(DISTINCT s.System_ID)
This will count, for each area/department group, the number of distinct system ID values. In the case of Area 1/Department 1, this would yield a distinct system count of 2, while for Area 1/Department 2, this would give a count of just 1.
Iam trying to analyze some date from a mysql table.
The data is a representation of incomming calls, each line represents one call
category purpose
cars question
bikes question
cars question
cars complaints
scooters question
bikes complaints
now for the plotting I need the data to look like this
category cat_count question complaints
cars 3 2 1
bikes 2 1 1
scooters 1 1
I figured out that I can sort and count by one field by using something like this
SELECT category, count(*) FROM stat GROUP BY category ORDER BY count(*) desc;
which will give me
category count
cars 3
bikes 2
scooters 1
but how can I add the purpose counts to that output?
I would usually write a php or bash script, but if its possible to do it in mysql I would rather do it like that instead of having a 3 loop script noone will understand in 1 year :-))
Thanks in advance for any hint (even if the hint is "impossible")
You can do this way:
SELECT category, count(*) as cat_count,
SUM(CASE WHEN purpose='question' THEN 1 ELSE 0 END) as question,
SUM(CASE WHEN purpose='complaints' THEN 1 ELSE 0 END) as complaints
FROM stat
GROUP BY category
ORDER BY count(*) desc;
Result:
CATEGORY CAT_COUNT QUESTION COMPLAINTS
cars 3 2 1
bikes 2 1 1
scooters 1 1 0
See result in SQL Fiddle.
This question already exists:
SQL Query geting infromation from table
Closed 9 years ago.
I would like to do two things but I've goten stuck.
First of all I would like to write a SQL statement to show me all the sport and all competition days each sport has. The table Event looks like this
Competitor ID sports branch distance men's/women
1 Running Long-Distance 50000 MEN
I also have an Table named EventDay which has CompetitorID, date ,arena and spectators.
CompetitorID Date Arena Spectators
1 08/11/11 Olympus 500
There is obviously going to be an join statment here but I cant get it to work.
In the next table below I would like to get out exactly how mand gold medals the invidual countries have goten from the branch Athletics. I would also like it to be devided in the sex and sorted after the name of the country.
Land Sex Ammount gold
USA L 2
USA M 4
Ryss L 3
Ryss H 2
TRY THIS
SELECT Country,Sex
, sum(AmountGold) as TotalGold
FROM YourTable
GROUP BY
Country,Sex
ORDER BY
Country,Sex
I think this is what you need
select Country
, Sex
, sum(case when MedalType = 'Gold' then 1 else 0 end) as AmountGold
from YourTable
group by
Country
, Sex
order by
AmountGold desc
Try this:
SELECT COUNTRY,
SUM(AMOUNT_GOLD) AS TOTAL_GOLD
FROM ATHLETICS
GROUP BY LAND,
SEX
ORDER BY LAND