What can I add to my query to total up two rows? - sql

I have the below query and results. What can I add to this query to combine the calories for people with the same name? For example, Dave's total should be 3045+3129 to show 6174.
SELECT
likes.*, beer.cal, (beer.cal * 21) AS 'Drink 3 in a Week'
FROM
likes
INNER JOIN
beer ON likes.beer = beer.beer;
**name beer cal Drink 3 in a Week**
dave bud 145 3045
dave coors 149 3129
gary miller 143 3003
linda coors 149 3129
mike bud 145 3045
mike miller 143 3003
sally coors 149 3129
sally miller 143 3003

You can use window funtion
SELECT
likes.*, beer.cal,
SUM(beer.cal * 21) OVER(PARTITION BY NAME) AS 'Drink 3 in a Week'
FROM
likes
INNER JOIN
beer ON likes.beer = beer.beer;
Another option is group by.

Related

SQL Grouping of Salaries

I have a question to ask and I am supposed to create a query which shows:
MIN(lastname) MAX(firstname) SUM(salary) AVG(salary)
---------------------------------------------------------------
DAVIES TRINA 17500 3500
This was the query/queries I created:
SQL> SELECT MIN(LASTNAME), MAX(FIRSTNAME), SUM(SALARY), AVG(SALARY)
2 FROM EMPLOYEES
3 GROUP BY JOB_ID;
SQL> SELECT MIN(LASTNAME), MAX(FIRSTNAME), SUM(SALARY), AVG(SALARY)
2 FROM EMPLOYEES
3 GROUP BY JOB_ID, MANAGER_ID;
But I get multiple rows shown to me and in the part where DAVIES TRINA was shown the SUM and AVG salary is different and I am unsure how they were grouped.
MIN(LASTNAME) MAX(FIRSTNAME) SUM(SALARY) AVG(SALARY)
---------- ---------- ----------- -----------
ERNST DIANA 10200 5100
HIGGINS SHELLEY 12000 12000
GIETZ WILLIAM 8300 8300
MOURGOS KEVIN 5800 5800
WHALEN JENNIFER 4400 4400
DE HAAN NENA 34000 17000
ZLOTKEY ELENI 10500 10500
HARTSTEIN MICHAEL 13000 13000
KING STEVEN 24000 24000
ABEL KIMBERLEY 26600 8866.66667
FAY PAT 6000 6000
**DAVIES TRINA 11700 2925**
What am I doing wrong?
MORE INFO BELOW:
EMPLOYEE_ID FIRSTNAME LASTNAME JOB_ID SALARY MANAGER_ID DEPARTMENT_ID
100 STEVEN KING AD_PRES 24000 90
101 NENA KOCHAR AD_VP 17000 100 90
102 LEX DE HAAN AD_VP 17000 100 90
103 ALEXANDER HUNOLD IT_PROG 101 60
104 BRUCE ERNST IT_PROG 6000 102 60
107 DIANA LORENTZ IT_PROG 4200 103 60
124 KEVIN MOURGOS ST_MAN 5800 100 50
141 TRINA RAJS ST_CLERK 3500 124 50
142 CURTIS DAVIES ST_CLERK 3100 124 50
143 RANDALL MATOS ST_CLERK 2600 124 50
144 PETER VARGAS ST_CLERK 2500 124 50
EMPLOYEE_ID FIRSTNAME LASTNAME JOB_ID SALARY MANAGER_ID DEPARTMENT_ID
149 ELENI ZLOTKEY SA_MAN 10500 100 80
174 ELLEN ABEL SA_REP 11000 149 50
176 JONATHAN TAYLOR SA_REP 8600 149 80
178 KIMBERLEY GRANT SA_REP 7000 149
200 JENNIFER WHALEN AD_ASST 4400 101 10
201 MICHAEL HARTSTEIN MK_MAN 13000 100 20
202 PAT FAY MK_REP 6000 201 20
205 SHELLEY HIGGINS AC_MGR 12000 101 110
206 WILLIAM GIETZ AC_ACCOUNT 8300 205 110
If you provide the proper data that is, the data before running the query/queries and also tell why it should be 17500(sum) and 3500(avg) then you have more chances to get answers.
In the 1st query you are grouping based on JOB_ID. That means for all similar JOB_IDs (in case of SUM(SALARY)) it will select the the values of SALARY column and SUM the values for each different JOB_ID.
Example:
JOB_ID SALARY
1 200
2 300
1 150
2 100
3 270
If you run the following query:
Select JOB_ID,SUM(SALARY) FROM Table GROUP BY JOB_ID
Output:
JOB_ID SALARY
1 350
2 400
3 270

Confusion with the behavior of HAVING clause

I am not able to understand the behavior of the following query:
select max(avg(salary)) from employees
group by first_name
having avg(salary) >= max(salary);
It prints out the result as 17000. But if max(salary) is 24000 shouldn't there be empty result. If I replace "">="" with ">" it prints the result as NULL.
And if I replace ">=" with "<", then 13100 is printed in the result.
Below is the employees table:
TJ 2100
Steven 2200
Hazel 2200
James 2400
Ki 2400
Karen 2500
James 2500
Joshua 2500
Peter 2500
Martha 2500
Randall 2500
Guy 2600
Randall 2600
Donald 2600
Douglas 2600
Irene 2700
John 2700
Sigal 2800
Mozhe 2800
Girard 2800
Vance 2800
Shelli 2900
Michael 2900
Timothy 2900
Anthony 3000
Kevin 3000
Alex 3100
Curtis 3100
Jean 3100
Alana 3100
Julia 3200
Stephen 3200
Winston 3200
Samuel 3200
Laura 3300
Jason 3300
Julia 3400
Trenna 3500
Renske 3600
Jennife 3600
Kelly 3800
Britney 3900
Sarah 4000
Alexis 4100
Diana 4200
Nandita 4200
Jennife 4400
David 4800
Valli 4800
Kevin 5800
Bruce 6000
Pat 6000
Sundita 6100
Amit 6200
Charles 6200
Sundar 6400
Shanta 6500
Susan 6500
David 6800
Luis 6900
Oliver 7000
Sarath 7000
Kimbe 7000
Mattea 7200
Eliza 7300
William 7400
Nanette 7500
Louise 7500
Ismael 7700
Jose 7800
Payam 7900
Matthew 8000
Christ 8000
Lindsey 8000
John 8200
Adam 8200
William 8300
Jack 8400
Jonath 8600
Alyssa 8800
Alex 9000
Daniel 9000
Peter 9000
Allan 9000
Patrick 9500
Danie 9500
David 9500
Tayler 9600
Hermann 10000
Harris 10000
Janette 10000
Peter 10000
Clara 10500
Eleni 10500
Gerald 11000
Den 11000
Ellen 11000
Lisa 11500
Alberto 12000
Shelley 12008
Nancy 12008
Michael 13000
Karen 13500
John 14000
Lex 17000
Neena 17000
Steven 24000
You are doing Group By First_name, in your table,
For Neena, max(salary) = 17000 and avg(salary)=17000,
So, >= matches the condition in the query and 17000 is returned.
Where as replacing >= with > evaulated to NULL.
For Steven, Max(salary)=24000, AVG(salary)=(24000+2200)/2=13100
So replacing >= with < returns 13100
Note : Grouping by ColumnName here first_name plays the key role
here. All the aggregate functions in SELECT as well as having clause,
are applied per employee and not on the whole table.
If you want to compare an employee's mean salary (does this really make sense? Surely an employee only has one salary at a point in time?) then this might help
WITH
employees (first_name,salary)
AS
(SELECT 'TJ',2100 FROM dual UNION ALL
SELECT 'Steven',2200 FROM dual UNION ALL
SELECT 'Hazel',2200 FROM dual UNION ALL
SELECT 'James',2400 FROM dual UNION ALL
SELECT 'Ki',2400 FROM dual UNION ALL
SELECT 'Karen',2500 FROM dual UNION ALL
SELECT 'James',2500 FROM dual UNION ALL
SELECT 'Joshua',2500 FROM dual UNION ALL
SELECT 'Peter',2500 FROM dual UNION ALL
SELECT 'Martha',2500 FROM dual
)
SELECT
first_name
,mean_salary_all_emps
,AVG(salary)
FROM
(SELECT
first_name
,salary
,AVG(salary) OVER () mean_salary_all_emps
FROM
employees
)
WHERE 1=1
GROUP BY
first_name
,mean_salary_all_emps
HAVING AVG(salary) > mean_salary_all_emps
;

Copy rows of data in SQL Server

Please help me come up with a solution for the situation being explained below:
ID name address age hobby GPA
---------------------------------------------------------
101 James 100 Garfield St 21 reading 3.13
101 James 100 Garfield St 21 writing 2.63
101 James 100 Garfield St 21 running 3.81
109 Tom 19 Lily Ave 19 dating 3.54
109 Tom 20 Lily Ave 19 climbing 2.76
109 Tom 21 Lily Ave 19 watching 3.91
I want to copy the set of rows with the same ID (eg. 101) and assign each set a State abbreviation(s) by running a single sql query. For instance: adding states CA, NJ, and DE to rows with an ID of 101, the result set is expected to look like this:
ID name address age hobby GPA state
-----------------------------------------------------------------------
101 James 100 Garfield St 21 reading 3.13 CA
101 James 100 Garfield St 21 writing 2.63 CA
101 James 100 Garfield St 21 running 3.81 CA
101 James 100 Garfield St 21 reading 3.13 NJ
101 James 100 Garfield St 21 writing 2.63 NJ
101 James 100 Garfield St 21 running 3.81 NJ
101 James 100 Garfield St 21 reading 3.13 DE
101 James 100 Garfield St 21 writing 2.63 DE
101 James 100 Garfield St 21 running 3.81 DE
Please keep in mind that everything else remains the same way as they were before the addition of the state abbreviations. Also assume I have more than three states to add and integrate to the query, say, I have all 50 states. Thank you for your time and effort in advance!
This should produce that result set:
select x.*, y.st
from tbl x
join
(select 'CA' as st union all
select 'NJ' union all
select 'DE') y
where x.id = 101
Create a new table with IDs and States
ID ST
101 CA
101 NJ
101 DE
109 ..
then join that on your table
SELECT t.*, s.st
FROM tbl t
JOIN states s ON t.id = s.id

SQL Select Distinct returning duplicates

I am trying to return the country, golfer name, golfer age, and average drive for the golfers with the highest average drive from each country.
However I am getting a result set with duplicates of the same country. What am I doing wrong? here is my code:
select distinct country, name, age, avgdrive
from pga.golfers S1
inner join
(select max(avgdrive) as MaxDrive
from pga.golfers
group by country) S2
on S1.avgdrive = s2.MaxDrive
order by avgdrive;
These are some of the results I've been getting back, I should only be getting 15 rows, but instead I'm getting 20:
COUN NAME AGE AVGDRIVE
---- ------------------------------ ---------- ----------
Can Mike Weir 35 279.9
T&T Stephen Ames 41 285.8
USA Tim Petrovic 39 285.8
Ger Bernhard Langer 47 289.3
Swe Fredrik Jacobson 30 290
Jpn Ryuji Imada 28 290
Kor K.J. Choi 37 290.4
Eng Greg Owen 33 291.8
Ire Padraig Harrington 33 291.8
USA Scott McCarron 40 291.8
Eng Justin Rose 25 293.1
Ind Arjun Atwal 32 293.7
USA John Rollins 30 293.7
NIr Darren Clarke 37 294
Swe Daniel Chopra 31 297.2
Aus Adam Scott 25 300.6
Fij Vijay Singh 42 300.7
Spn Sergio Garcia 25 301.9
SAf Ernie Els 35 302.9
USA Tiger Woods 29 315.2
You are missing a join condition:
select s1.country, s1.name, s1.age, s1.avgdrive
from pga.golfers S1 inner join
(select country, max(avgdrive) as MaxDrive
from pga.golfers
group by country
) S2
on S1.avgdrive = s2.MaxDrive and s1.country = s2.country
order by s1.avgdrive;
Your problem is that some people in one country have the same average as the best in another country.
DISTINCT eliminated duplicate rows, not values in some fields.
To get a list of countries with ages, names, and max drives, you would need to group the whole select by country.

How I select record that not appear in another table

Table: Movie
mID title year director
101 Gone with the Wind 1939 Victor Fleming
102 Star Wars 1977 George Lucas
103 The Sound of Music 1965 Robert Wise
104 E.T. 1982 Steven Spielberg
105 Titanic 1997 James Cameron
106 Snow White 1937 <null>
107 Avatar 2009 James Cameron
108 Raiders of the Lost Ark 1981 Steven Spielberg
Table: Rating
rID mID stars ratingDate
201 101 2 2011-01-22
201 101 4 2011-01-27
202 106 4 <null>
203 103 2 2011-01-20
203 108 4 2011-01-12
203 108 2 2011-01-30
204 101 3 2011-01-09
205 103 3 2011-01-27
205 104 2 2011-01-22
205 108 4 <null>
206 107 3 2011-01-15
206 106 5 2011-01-19
207 107 5 2011-01-20
208 104 3 2011-01-02
I need to fetch movies which are not rate yet. In this case Titanic (mID 105) and Star Wars (mID 102) never get rate in rating table.
I figured out it with
select distinct movie.title from movie,rating where
rating.mid!=movie.mid except select distinct movie.title from
movie,rating where rating.mid=movie.mid
however I think it might have better (easier/cleaner) way to do.
Simple:
SELECT Movies.* FROM Movies LEFT JOIN Rating ON Movies.mID = Rating.mID WHERE Rating.mID IS NULL
If I understood your question properly, that looks like textbook application of outer joins.
You could do it like this:
SELECT * FROM Movie WHERE mid NOT IN (SELECT DISTINCT(mid) FROM Rating)
Basically it will select all records from the movie table that are not in the rating table, linking them on the 'mid' column, which I am assuming is a unique identifier.
I will add another possibility.
Select [list columns here]
from Movie m
where NOT exists (SELECT * FROM RATING r where m.mid = r.mid)