I have to use only aggregate function (so without checking exact values in columns, for determined row), when I select the determined IT worker's salary.
It isn't as simple as SELECT SUM(salary) FROM table WHERE occupation='IT worker' LIMIT <here stays which place the person has on the list>, 1, is it? I think that by using SUM command, we don't check exact values.
If this question isn't understandable, I can translate the whole exercise.
EDIT: the exercise
Using only agregate functions (without checking exact values in columns, for determined row) create a query, which lets us know about determined IT worker's salary. table contains:
id int
occupation varchar(50)
salary int
I am not going to write the queries, this is meant to get you started:
The table seems to have 3 fields: id, occupation, and salary.
Each row seems to correspond to a specific worker
Then you can use agregate functions to calculate stuff regarding different occupations (for example).
The structure for a query that uses agregate functions is like this:
Select <fields and agregate functions>
from table
where <filter records to consider for the query before aggregation>
group by <field having the same value, hence that can be grouped by>
having <optional condition evaluated after doing the aggregation>
Examples of agregate functions are Sum, Count, Avg.
The question is not clear but with the informatin you have you can calculate:
Number of workers with same occupaton.
Average salary.
Total salary income by occupation.
If we ignore department for now you could do something like this
MariaDB [sandbox]> select emp_no, salary from employees ;
+--------+--------+
| emp_no | salary |
+--------+--------+
| 1 | 20000 |
| 2 | 39500 |
| 3 | 50000 |
| 4 | 19500 |
| 5 | 10000 |
| 6 | 19500 |
| 7 | 40000 |
| 9 | NULL |
+--------+--------+
8 rows in set (0.00 sec)
MariaDB [sandbox]> select emp_no,salary,
-> concat(rank,' of ' ,obs) as Rank,
-> Position,
-> reltoavg realtivetoavg
-> from
-> (
-> select emp_no,salary ,
-> #rn:=#rn+1 as Rank,
-> (select count(*) from employees) as obs,
-> concat('There are ',
-> (Select count(*) from employees e1 where e1.SALARY > e.salary) , ' employees who earn more and ',
-> (Select count(*) from employees e1 where e1.SALARY < e.salary and salary is not null) , ' who earn less') Position,
-> (select avg(salary) from employees) avgsalary,
-> if (salary > (select avg(salary) from employees), 'Salary is above average', 'salary is below average') reltoavg
-> from employees e,(Select #rn:=0) r
-> where salary is not null
-> order by salary
-> ) s
-> where s.emp_no = 1
-> ;
+--------+--------+--------+---------------------------------------------------------+-------------------------+
| emp_no | salary | Rank | Position | realtivetoavg |
+--------+--------+--------+---------------------------------------------------------+-------------------------+
| 1 | 20000 | 4 of 8 | There are 3 employees who earn more and 3 who earn less | salary is below average |
+--------+--------+--------+---------------------------------------------------------+-------------------------+
1 row in set (0.00 sec)
Related
In a given question,
Write a SQL query to get the second highest salary from the Employee table.
+----+--------+
| Id | Salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
+----+--------+
For example, given the above Employee table, the query should return 200 as the second highest salary. If there is no second highest salary, then the query should return null.
+---------------------+
| SecondHighestSalary |
+---------------------+
| 200 |
+---------------------+
I submited the query below
(window function to rank the salary then identify ifnull or not):
WITH salary_ranked
AS (
SELECT
salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS rank_num
FROM
Employee
)
SELECT
IFNULL(
(SELECT salary_ranked.salary
FROM salary_ranked
WHERE rank_num =2), 'null') AS SecondHighestSalary;
But it showed the wrong answer as below.
THE LATEST UPDATE
Revised the code below:
WITH salary_ranked
AS (
SELECT
salary,
DENSE_RANK() OVER (ORDER BY salary DESC) AS rank_num
FROM
Employee
WHERE
salary > 0
)
SELECT
IFNULL(
(SELECT salary_ranked.salary
FROM salary_ranked
WHERE rank_num =2), null) AS SecondHighestSalary;
It passed 7 test cases of 8. But it still leave the last situation to be solved.
SELECT id, salary FROM employees ORDER BY salary DESC LIMIT 1, 1
The first number after "LIMIT" is the offset when using the comma. The offset is zero-indexed. So, this query selects one row, starting at the second highest.
See the section on "offset" in the MySQL docs on SELECT
SQL Question:
Write a SQL query to get the nth highest salary from the Employee table (SQL Server)
| Id | Salary |
+----+--------+
| 1 | 100 |
| 2 | 200 |
| 3 | 300 |
For this example, the nth highest salary where n = 2 is 200. If there is no nth highest salary, then the query should return null.
| getNthHighestSalary(2) |
+------------------------+
| 200 |
My code is the following:
CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
BEGIN
RETURN (
select distinct a.salary from Employee a, Employee b where
a.id =b.id-n+1 order by a.id desc
limit 1
);
END
My question is: The code works for most of the cases except for the situation when there are multiple same values before the nth place. For example, whe n is 2 and the table is the following. (The expected result should be NULL and my code returns 100. ) So, how can I change my code so that it can work for all situations? Thank you!
+----+--------+
| id | salary |
+----+--------+
| 1 | 100 |
| 2 | 100 |
| 3 | 100 |
+----+--------+
Try this
Select distinct salary
From (
Select salary, dense_rank() over
(order by salary desc) r
from employee
) where r=n
1st 2nd and 3rd highest salary query
SELECT MAX(salary) AS ThirdHighestSalary
FROM emp
WHERE (salary <
(SELECT MAX(salary) AS SecondHighestSalary
FROM emp
WHERE (salary <
(SELECT MAX(salary) AS HighestSalary
FROM emp))))
I'm a beginner in mysql. The following codes look stupid but it is why my codes cannot work. I thought it would give me n rows. However, it only gave me one row. Suppose there are n rows in the table seat, and there are two fields including id, student.
I understand count(*) will return one number. I thought that, for each row, sql will check whether id equals total number of rows. But it didn't.
select id = count(*) as id, student
from seat
The following codes did what I wanted. Could anyone explain what makes them give different results?
select id = count2 as id, student
from seat, (select count(*) as count2 from seat) seat2
One way:
set #num := (select count(*) from seat);
select
id
, student
, case when id = #num then 'special' else 'normal' end as x
from seat
Another way:
select
id
, student
, case when id = x.y then 'special' else 'normal' end as x
from seat
cross join (select count(*) as y from seat) as x
;
NB: In both examples you need the subquery to return just one value in one row.
Given
+----+----------+
| id | lastname |
+----+----------+
| 1 | aaa |
| 2 | bbb |
| 3 | ccc |
+----+----------+
3 rows in set (0.00 sec)
Your first query is an instruction to mysql to count across the entire set
MariaDB [sandbox]> select id = count(*) as id, lastname
-> from users;
+------+----------+
| id | lastname |
+------+----------+
| 0 | aaa |
+------+----------+
1 row in set (0.00 sec)
Clearly this does not return the last id or the correct count. The correct count would be returned by this
select id, lastname , count(*)
from users;
+------+----------+----------+
| id | lastname | count(*) |
+------+----------+----------+
| 1 | aaa | 3 |
+------+----------+----------+
1 row in set (0.00 sec)
And the id and lastname are indeterminate.
Your second query returns a cartesian product
select id = count2, lastname, count2
-> from users, (select count(*) as count2 from users) seat2
-> ;
+-------------+----------+--------+
| id = count2 | lastname | count2 |
+-------------+----------+--------+
| 0 | aaa | 3 |
| 0 | bbb | 3 |
| 1 | ccc | 3 |
+-------------+----------+--------+
3 rows in set (0.00 sec)
Which again does not identify the id which matches the count..
Assuming the id is a number and increments in some fashion a way which does find the last id is
MariaDB [sandbox]> select id,lastname
-> from users
-> where id = (select count(*) from users);
+----+----------+
| id | lastname |
+----+----------+
| 3 | ccc |
+----+----------+
1 row in set (0.00 sec)
But this is dangerous - if id is auto_increment then the number of rows may not match the id because of the way auto_increment is treated (it can be overridden, insert update on duplicate key etc.)
A safer way is to
MariaDB [sandbox]> select id,lastname
-> from users
-> where id = (select max(id) from users);
+----+----------+
| id | lastname |
+----+----------+
| 3 | ccc |
+----+----------+
1 row in set (0.00 sec)
I think you should try something like this :
select id = (select count(*) from seat) as id, student
from seat
Basically your previous request with this statement in the FROM clause (select count(*) as count2 from seat) gives you only row so it can't compare to all of your rows because you put it in your FROM clause two tables seat and seat2 without the same number of rows.
I think you don't need to use two tables.
I thought it [count(*)] would give me n rows. However, it only gave me one row.
Nope. You are using COUNT(*) with no GROUP BY. That makes your query an aggregation query. An aggregation query with no GROUP BY always returns one row -- even when there are no rows in the table.
Your query would be invalid in almost any other database (and in the default configuration of future versions of MySQL) because you have an aggregation query and the column id is not in the GROUP BY nor an argument to an aggregation function.
In MySQL, probably the simplest way to do what you intend uses a subquery:
select id = (select count(*) from seat) as id, student
from seat
I have no idea why you would want to call the boolean result id, but that is what your original query expresses.
Conclusion: You need to practice aggregation queries and look up what GROUP BY does.
Table Name : Employee
+------+------+
| name | dept |
+------+------+
| ABC | 1 |
| BCA | 1 |
| CYZ | 2 |
| CYZ | 1 |
| n... | n... |
+------+------+
Table Name : Department
+----+-----------+
| id | dept_name |
+----+-----------+
| 1 | YYY |
| 2 | ZZZ |
| 3 | DDD |
+----+-----------+
I've to select 25 random entries against each dept_name from table Employees.
For eg. In table Department there are 10 entries with unique id.
so the result query will return 25(random) * 10 = 250 rows.
so far I'm working out this query but something is wrong with it.
Select * from Employee where dept in (Select id from Department) RAND;
Probably something like below:
SELECT d.id, GROUP_CONCAT(name) employee_list FROM Department d JOIN (
SELECT name FROM EMPLOYEE e WHERE d.id = e.dept ORDER BY RAND() LIMIT 25
) v
GROUP BY d.id
LIMIT 10
One option is to GROUP_CONCAT employees per department and then limit the list to 25 entries using SUBSTRING_INDEX(). Then join the limited values with employee table, like this:
SELECT e.* FROM Employee e
JOIN (
SELECT SUBSTRING_INDEX(GROUP_CONCAT(eid ORDER BY RAND()), ',', 25) EmpList
FROM Employee
GROUP BY dept
) t
ON FIND_IN_SET(e.eid, t.EmpList)
Working Fiddle: http://sqlfiddle.com/#!9/1bd04/1
Note: GROUP_CONCAT has a default limit of 1024 which can be increased.
Second option is to assign row numbers to all employees per department and then limit the result to 25 per department. This one does not uses group_concat.
SET #num := 0, #d_id := '';
SELECT eid, name, dept
FROM (
SELECT e.*,
#num := IF(#d_id = e.dept, #num + 1, 1) AS row_number,
#d_id := e.dept AS dummy
FROM (
SELECT * FROM Employee ORDER BY dept, RAND()
) e
) t
WHERE t.row_number <= 25
Working Fiddle: http://sqlfiddle.com/#!9/1bd04/22
Note: Both the fiddles above limits 2 employees per department for demo purposes.
I've a table like this:
+----+------+--------+
| id | name | salary |
+----+------+--------+
| 1 | Ajay | 20000 |
| 2 | Aja | 2000 |
| 3 | Aj | 200 |
| 4 | A | 3000 |
| 5 | q | 30000 |
+----+------+--------+
I want to write a query that can print highest salary, medium salary and lowest salary. So I wrote this query:
select salary
from parent
where max(sal)
&& salary < ( SELECT MAX( salary )
FROM parent )
&& min(salary);
And mysql returned an error:
ERROR 1111 (HY000): Invalid use of group function
what is the correct query?
MySQL doesn't offer an aggregate function to grab a median value, sorry to say. Hopefully you can go with the average (the arithmetic mean) value.
Stuff like MAX(), MIN(), and AVG() (called aggregate functions in the jargon of SQL) can't appear in WHERE clauses. They can show up in SELECT and HAVING clauses. That's why you got an error.
You'll be wanting
SELECT MAX(salary) max_salary,
AVG(salary) avg_salary,
MIN(salary) min_salary
FROM parent
If you control your own MySQL server and you have a few MySQL dba chops, you can install a user-defined function to compute the median value. (If you're using a hosting service with a multitenant MySQL server, forget about this.) Read this.
http://mysql-udf.sourceforge.net/
select 'min' as k, min(salary) as v from parent
union
select 'avg' as k, avg(salary) as v from parent
union
select 'max' as k, max(salary) as v from parent