SQL Select Max within a Subquery - sql

I've been having trouble with a SQL subquery, and although I imagine this is fairly basic, the internet does not seem to hold the answer. I have a subquery inside a FROM statement which has a MAX() function within it, and I cannot seem to reference this data in the rest of the query. The query is here:
SELECT
m.nameFirst, m.nameLast, t.salary, te.name
FROM
(SELECT
MAX(salary), teamID
FROM
salaries
GROUP BY
teamID) AS t, master AS m, teams AS te, salaries AS s
WHERE
t.salary = s.salary
AND s.teamID = t.teamID
AND s.playerID = m.playerID
AND te.teamID = t.teamID;
The subquery, when run by itself, returns results which look like this:
+-------------+--------+
| MAX(salary) | teamID |
+-------------+--------+
| 13166667 | ANA |
| 16000000 | ARI |...
However, when I try to run the whole query, I get the following result:
ERROR 1054 (42S22): Unknown column 't.salary' in 'field list'
I have tried a few different things, such as t.MAX(salary), MAX(t.salary), and even just t.*, but as I need to use the subquery's results later, it just throws different errors.
What name should I use to call the results of the MAX column of the subquery?
Thanks so much for any help.

you can use an alias for max column and your code will work :
SELECT m.nameFirst, m.nameLast, t.salary, te.name
FROM (
SELECT MAX(salary) as salary, teamID
FROM salaries
GROUP BY teamID
) AS t, master AS m, teams AS te, salaries AS s
WHERE t.salary=s.salary AND s.teamID=t.teamID AND s.playerID = m.playerID AND te.teamID=t.teamID;

you can give it an alias to make it easier or in this case accessible
eg
SELECT MAX(salary) as max_salary, teamID ...
then later simply reference
t.max_salary
so in your example change it like this
SELECT m.nameFirst, m.nameLast, t.max_salary, te.name
FROM (
SELECT MAX(salary) as max_salary, teamID
-- rest of query

This is because there is no salary returned in subquery likewise the error name it as max(salary) as some_name then t.some_name=s.salary

Related

How to keep a bucket using case statement even if the count for items in that bucket is 0?

Here's the data table named "Salary_table" that i've created for this question:
So I want to find the number of employees in each salary bucket in each department. the buckets are
"<$100" "$100-$200" and ">$200"
The desired output is:
Below is my code for achieving this task:
select distinct(st.department) as "Department",
sb.salary_bucket as "salary range", count(*)
from Salary_table st
Left join (
select department, employee, case
when salary < 100 then "<$100"
when salary between 100 and 200 then "$100-$200"
else ">$200"
end
as salary_bucket
from Salary_table
) sb
on sb.employee = st.employee
group by st.department, sb.salary_bucket
order by st.department, sb.salary_bucket
;
but my output is a bit short of what im expecting:
There are TWO problems with my current output:
The buckets with 0 employees earning the salary in the bucket range are not listed; I want it to be listed with a value "0"
The salary bucket is NOT in the right order, even though I added in the statement "order by" but I think it's b/c its texts so can't really do that.
I would really appreciate some hints and pointers on how to fix/achieve these two issues I've addressed above. Thank you so much!
what i've tried
I tried use "left join" but output came out the same
I tried adding the "order by" clause but doesnt seem to work on text buckets
You are sort of on the right track, but the idea is a bit more complicated. Use a cross join to get all the rows -- the buckets and departments. Then use left join to bring in the matching information and finally group by for the aggregation:
select d.department, b.salary_bucket,
count(sb.department) as cnt
from (select '<$100' as salary_bucket union all
select '$100-$200' union all
select '>$200'
) b cross join
(select distinct department from salary_table
) d left join
(select department, employee,
(case when salary < 100 then '<$100'
when salary between 100 and 200 then '$100-$200'
else '>$200'
end) as salary_bucket
from Salary_table
) sb
on sb.department = d.department and
sb.salary_bucket = b.salary_bucket
group by d.department, b.salary_bucket;

SQL Assignment about joining tables

I am working on a SQL assignment in Oracle. There are two tables.
table1 is called Person10:
fields include: ID, Fname, Lname, State, DOH, JobTitle, Salary, Cat.
table2 is called StateInfo:
fields include: State, Statename, Capital, Nickname, Pop2010, pop2000, pop1990, sqmiles.
Question:
Create a view named A10T2 that will display the StateName, Capital and Nickname of the states that have at least 25 people in the Person10 table with a Cat value of N and an annual salary between $75,000 and $125,000. The three column headings should be StateName, Capital and Nickname. The rows should be sorted by the name of the state.
What I have :
CREATE VIEW A10T2 AS
SELECT StateName, Capital, Nickname
FROM STATEINFO INNER JOIN PERSON10 ON
STATEINFO.STATE = PERSON10.STATE
WHERE Person10.CAT = 'N' AND
Person10.Salary in BETWEEN (75000 AND 125000) AND
count(Person10.CAT) >= 25
ORDER BY STATE;
It gives me an error saying missing expression. I may need a group expression... but i dont know what I am doing wrong.
Yeah I originally messed this up when I first answered this because it was on the fly and I didn't have a chance to test what I was putting down. I forgot using a GROUP BY is more suited for aggregate functions (Like SUM, AVG and COUNT in the select) and that's probably why it's throwing the error. Using a ORDER BY is probably the correct option in this case. And you want to order your results by the state so you would use StateName.
SELECT S.StateName, S.Capital, S.Nickname
FROM STATEINFO S
INNER JOIN PERSON10 P ON S.STATE = P.STATE
WHERE P.CAT = 'N'
AND P.Salary BETWEEN 75000 AND 125000
ORDER BY S.StateName
HAVING count(P.CAT) >= 25;
Try moving your count() to HAVING instead of WHERE. You'll also need a GROUP BY clause containing StateName, Capital, and Nickname.
I know this link is Microsoft, not Oracle, but it should be helpful.
https://msdn.microsoft.com/en-us/library/ms180199.aspx?f=255&MSPPError=-2147217396
I'm no Oracle expert, but I'm pretty sure
Person10.Salary in BETWEEN (75000 AND 125000)
should be
Person10.Salary BETWEEN 75000 AND 125000
(no IN and no parentheses). That's how all other SQL dialects I know of work.
Also, move the COUNT() from the WHERE clause to a HAVING clause:
CREATE VIEW A10T2 AS
SELECT StateName, Capital, Nickname
FROM STATEINFO INNER JOIN PERSON10 ON
STATEINFO.STATE = PERSON10.STATE
WHERE Person10.CAT = 'N' AND
Person10.Salary BETWEEN 75000 AND 125000
ORDER BY STATE
HAVING count(Person10.CAT) >= 25;
You can try using a Sub Query like this.
CREATE VIEW A10T2 AS
SELECT statename, capital, nickname
FROM stateinfo
WHERE statename IN (SELECT statename
FROM person10
WHERE Cat = 'N'
AND Salary BETWEEN 75000 AND 125000
GROUP BY statename
HAVING COUNT(*) >= 25)
ORDER BY statename

Creating views with group by not grouping properly

I have data that looks like Music92838, Entertainment298928, SPORTS2837 etc. in my Event_type column, and I'm trying to create a view that groups the number of performances by event_type
I tried to do
CREATE VIEW Performances_Type_Cnt
AS SELECT regexp_replace(E.event_type, '[^a-zA-Z]', '', 'g') AS Event_Type,
COUNT(*)
FROM Event_Type E, Performance P
WHERE E.event_id = P.event_id
GROUP BY Event_Type;
Using regex to only select characters, and then group by Music, Sports etc in the Group By Event_type. But something isn't working as in my results I'm getting
event_type | count
---------------+-------
MUSIC | 1
SPORTS | 5
MUSIC | 8
MUSIC | 3
where Music appears more than once in event_type, which isn't the correct result.
Any and all help appreciated!
The "problem" is that Postgres allows column aliases in the GROUP BY. So, it is confused as to whether the EVENT_TYPE comes from the table or the alias. One simple solution is to use positional notation:
CREATE VIEW Performances_Type_Cnt AS
SELECT regexp_replace(E.event_type, '[^a-zA-Z]', '', 'g') AS Event_Type,
COUNT(*) as cnt
FROM Event_Type E JOIN
Performance P
ON E.event_id = P.event_id
GROUP BY 1;
I made some other changes:
Replaced the implicit join with an explicit JOIN. This is the standard way to write joins in SQL.
Added a column alias for COUNT(*).

STDDEV function and with clause

I am using Oracle. I have table like:
Company Employee salary
A1 Jim 122000
...
I want to return the company with the highest number of employee whose salary is above 2 standard deviations (~>95%). Here is my code
With Com_2Std as (
Select company-name, AVG(salary)+2*STDDEV(salary) as AboveS
From works
Group By company-name)
Select company-name, count(employee-name) as ENumber
From works
Where ENumber=MAX(
Select count(a.employee-name)
From works a, Com_2Std b
Where a.company-name=b.company-name
And a.salary>b.AboveS;
Group by a.company-name)
Group by company-name;
I have two quesions:
(1) I can't access to oracle today and can't test it. Is my code correct please?
(2) It looks quite complicated, any way to simplify it please?
with Com_2Std as (
select company-name, AVG(salary)+2*STDDEV(salary) as AboveS
from works
group by company-name
),
CompanyCount as (
select a.company-name, count(*) as CountAboveS
from
works a
inner join Com_2Std b on a.company-name=b.company-name
where
a.salary > b.AboveS
group by a.company-name
)
select company-name
from CompanyCount
where CountAboveS = (select max(CountAboveS) from CompanyCount)
This ought to be close. It will produce ties as well.

how to write SQL query in this situation

I have table named "Attendance" which looks like this:
Sno SecurityGroup SecurityName Designation AttendanceStatus
----------------------------------------------------------------
1 JJ Ram officer present
2 JJ Raja Guards Present
3 JJ Rani LadyGuards Present
4 JJ Ramu officer present
I need the Output as count of number of securities present in each Designation as follows:
SecutityGroup Officer Guards LadyGuards
-----------------------------------------
JJ 2 1 1
Can someone please help me write a query to get this Output?
select SecurityGroup,
sum(case when Designation = 'officer' then 1 end) as Officer,
sum(case when Designation = 'Guards' then 1 end) as Guards,
sum(case when Designation = 'LadyGuards' then 1 end) as LadyGuards
from Attendance
group by SecurityGroup
Alternately, if you are OK with having the information in rows instead, you can do:
select SecurityGroup, Designation, count(*) as Count
from Attendance
group by SecurityGroup, Designation
Obviously the second approach is preferred as it is less brittle, and will function if more Designations get added without any modification.
This can also be done with a PIVOT, depending on your database:
SELECT SecurityGroup, SUM([officer]) AS Officers, SUM([Guards]) AS Guards, SUM([LadyGuards]) AS LadyGuards
FROM Attendance
PIVOT
(
COUNT(Sno)
FOR Designation IN ([officer], [Guards], [LadyGuards])
) as pvt
WHERE AttendanceStatus = 'Present'
GROUP BY SecurityGroup
If you want to have the column list generated dynamically based on whatever is in the table, it gets harder, but this avoids the needs for lots of subqueries.
I Tried out using PIVOT in SQL, But i could not Get count value..
Following is Code i tried:
select SecurityGroup,Officer,Guards,LadyGuards from
(select SecurityGroup,rDesignation from Attendance
where SecurityGroup='jj') up
PIVOT (count(Designation) for Designation IN
(Officer,Guards,LadyGuards)) as pvt
When i Execute this Query, I get
SecurityGroup,Officer,Guards,LadyGuards
JJ,0,0,0
Instead of,
SecurityGroup,Officer,Guards,LadyGuards
JJ,2,1,1
select distinct SecurityGroup,
select sum(*) from Attendance where designation = 'officer') as Officer,
select sum(*) from Attendance where designation = 'Guards') as Guards,
select sum(*) from Attendance where designation = 'LadyGuards') as LadyGuards
from Attendance
You can use sub queries to get this accomplished:
SELECT
SecurityGroup,
(SELECT COUNT(*) FROM `Attendance` WHERE `Designation` = "officer") AS `Officer`,
(SELECT COUNT(*) FROM `Attendance` WHERE `Designation` = "Guards") AS `Guards`,
(SELECT COUNT(*) FROM `Attendance` WHERE `Designation` = "LadyGuards") AS `LadyGuards`
FROM `Attendance`
WHERE `SecurityGroup` = "JJ"
I haven't actually tested this query, as I just wanted to share the concept with you.
Also please do note that is not the fastest way of accomplishing what you need done, but I believe it's the simplest way possible.
I hope this works for you.