How to find average without using group by statement in sql - sql

I want to know if its possible to get the functionality of group by with using it.
I need to find average without using group by.
basically I am looking for an alternative for the below simple query without using group by.
SELECT
AVG(salary)
, g.emp_id
FROM #emp e ,#salary d
WHERE e.emp_id=d.emp_id
GROUP BY e.emp_id

One option
SELECT e.emp_id ,
( SELECT AVG(salary)
FROM #salary d
WHERE d.emp_id = e.emp_id )
FROM #emp e

If your DB supports partition you can do:
SELECT e.emp_id
, AVG(s.salary) OVER(PARTITION BY s.emp_id) AS average_salary
FROM #emp e
INNER JOIN #salary s ON (e.emp_id = s.emp_id)
I fail to see the purpose of this exercise however.
It just makes your query harder to read, harder to debug and replaces commonly used syntax with obscure code.
Group by rocks
Did you know that group by even as a 'grant total' function build in
SELECT
AVG(d.salary)
, e.emp_id
FROM #emp e
INNER JOIN #salary s ON (e.emp_id = s.emp_id)
GROUP BY e.emp_id WITH ROLLUP
See: SQL-server: http://msdn.microsoft.com/en-us/library/bb522495.aspx
MySQL: http://dev.mysql.com/doc/refman/5.0/en/group-by-modifiers.html
Remark
Do not use implicit SQL '89 syntax, as much as I love Bill Joel's we didn't start the fire it is time to move on to the much better SQL '92's Explicit join syntax.
As for songs, 1989 really has a better year:

If you really wanted to do this, you could SELECT ... ORDER BY employee and then write a cursor to calculate the averages piecemeal. I don't see any good reason to do this, though.

Are you looking for something like this?
SELECT AVG(d.salary) over (partition by null),
e.emp_id
FROM #emp e
JOIN #salary d ON e.emp_id = d.emp_id;
It will return all employee ids and the average salary calculated for all employees (so it will contain the same information for all rows).

Try This:
select * from (SELECT
AVG(salary)
, g.emp_id
FROM #emp e ,#salary d
WHERE e.emp_id=d.emp_id
GROUP BY e.emp_id) a`

Related

SQL Joins and Corelated subqueries with column data

I am facing an issue in terms of understanding the joins. Lets say for an example we have two tables employee and sales and now I have a query where we have sales of an employee using the id of the employee
select e.employeename
,s.city
,SUM(s.sales)
from employee e
left join (select sales,eid from sales) s on s.eid = e.id
group by 1,2
I'd like to understand why s.city wasn't showing up? and also would like to understand what is this concept called? Is it co related sub queries on Joins? Please help me down over here.
select
e.employeename
,s.city
,SUM(s.sales)
from employee e
left join (select sales,eid,city from sales) s on s.eid = e.id
group by 1,2
in the left join above you have to add city as well. The query Imagine select sales,eid,city from sales is a table itself and then from this table you are selecting city (your second column s.city) this will run error as your table doesn't have a city column yet.
It is much easier to use CTE (common table expressions than CTE's) You can also do the above question as
select
e.employeename
,s.city
,SUM(s.sales)
from employee e
left join sales as s
on e.id = s.id
group by 1,2
here I have added e.id = s.id instead of s.id = e.id it is better to reference the key of the main table first.
you could use CTE (although used when you have to do a lot of referencing but you can see how it works):
With staging as (
select
e.employeename
,s.city
,s.sales
from employee e
left join sales as s
on e.id = s.id
),
sales_stats as (
select
staging.employeename,
staging.city,
sum(staging.sales)
from staging
group by 1,2
#here you will select from staging again consider staging as a separate table so you will have to have all the columns in the staging that you want to use further. Also you will have to reference columns using staging.x
)
select * from sales_stats
-- here you could have combined the steps but I wanted to show you how cte works, Hope this works for you

Return a value from a range in MS Access

I am trying to do a very simple range lookup in MS Access.
I basically have two tables:
I am looking for a query that will be able to go find the appropriate range of the salary and return the correct tax rate.
I started off with this as my base:
SELECT IIf(Salary Between 1000 And 2000,10,20)
FROM Employees;
But I am not making any sort of progress.
Any assistance will be greatly appreciated.
One possible method is to use a correlated subquery, e.g.:
select e.*, (select top 1 t.taxrate from taxrates t where t.to > e.salary order by t.to)
from employees e
Or using between:
select e.*, (select top 1 t.taxrate from taxrates t where e.salary between t.to and t.from)
from employees e
Alternatively, you can use a left join in the following way:
select e.*, t.taxrate
from employees e left join taxrates t on (e.salary between t.to and t.from)
Note that MS Access cannot represent this type of join in query Design View (i.e. a join with 'calculated' join criteria as opposed to joining on equal field values), but this is still valid SQL which may be successfully evaluated by the JET database engine.
In all of the above, I've assumed that your tables are called Employees & TaxRates, change these to suit.
Here is an alternative solution:
SELECT Salary.*, TaxRate.TaxRate
FROM Salary, TaxRate
WHERE Salary BETWEEN From and TO;

How To improve a sql query performance

I Have a view that return to me the customers and sum of their payment and its work but it take 8 second and when i remove the computed column part from the query it didn't take any time, and i tried to solve this by creating a non-clustered index on tables but its also 8 second, so I'm asking about if there is any method to improve the performance, although i have to use this technique.
my code is
SELECT ID
,NAME
,Total = (
SELECT Sum(Value)
FROM TRANSACTION
WHERE Employee.ID = employee_ID
)
FROM Employee;
Thanks in advance
You could use a join in the subselect with the sum
select e.id, e.name, t.total
from employee e
join (
select employee_ID, sum(value) as total
from TRANSACTION
group by employee_ID
) t on t.employee_ID = e.id
You can try to use a join with group and see if that is faster:
select employee.id, employee.name, sum(value)
from employee
join transaction where transaction.employee_ID = employee.id
group by employee.id, employee.name
Also - try to avoid to give names that correspond to reserved words - like TRANSACTION - see https://dev.mysql.com/doc/refman/5.5/en/keywords.html
To hasten up you might want to consider a combined index on Emlpoyee(id,name) AND an index on Transaction.Employee_ID - both are neede to make the joins and grouping for this query fast. Check if transaction.employee_ID has a FK_Constraint to Employee.ID - that might help as well.
For this query:
SELECT ID, NAME,
(SELECT Sum(t.Value)
FROM TRANSACTION t
WHERE e.Employee.ID = t.employee_ID
) as Total
FROM Employee e;
You want an index on TRANSACTION(employee_ID, Value). That should actually give you optimal performance.
You can write this as a join -- but a left join:
SELECT e.ID, e.NAME, SUM(t.Value) as Total
FROM Employee e JOIN
TRANSACTION t
ON e.Employee.ID = t.employee_ID
GROUP BY e.ID, e.NAME;
However, the overall GROUP BY is usually less efficient than the "sub group by" in MySQL (and often in other databases as well).
Try an indexed view on the total
CREATE VIEW totalView
WITH SCHEMABINDING
AS
select employee_ID, sum(value) as total
from TRANSACTION
group by employee_ID
CREATE UNIQUE CLUSTERED INDEX PK_totalView ON totalView
(
employee_id,total
);
Then join to that
select employee.id, employee.name, coalesce(t.total,0)
from employee
left outer join totalView t where t.employee_ID = employee.id
Adjust the join type according to your need.

Multiple Count with different value each record

I have a problem with my query, please help me to solve this problem.
My Query :
SELECT D.DEPTNO,
(SELECT COUNT(DISTINCT P.PROJNO) FROM SCHEMA.PROJECT P, SCHEMA.DEPARTMENT D WHERE P.DEPTNO = D.DEPTNO) AS PROJECT,
(SELECT COUNT(DISTINCT E.EMPNO) FROM SCHEMA.EMPLOYEE E, SCHEMA.DEPARTMENT D WHERE E.WORKDEPT = D.DEPTNO) AS EMPLOYEE
FROM SCHEMA.DEPARTMENT D, SCHEMA.PROJECT P, SCEHMA.EMPLOYEE E GROUP BY D.DEPTNO#
AND HERE THE RESULT :
enter image description here
but it should each row has a different result.
I must show total of project and employee each department, so i group that by deptno, but the result shown all total project and employee
Please help me guys :)
I think you are trying to write this query:
SELECT D.DEPTNO,
(SELECT COUNT(DISTINCT P.PROJNO)
FROM SCHEMA.PROJECT P
WHERE P.DEPTNO = D.DEPTNO
) AS PROJECT,
(SELECT COUNT(DISTINCT E.EMPNO)
FROM SCHEMA.EMPLOYEE E
WHERE E.WORKDEPT = D.DEPTNO
) AS EMPLOYEE
FROM SCHEMA.DEPARTMENT D;
Notes:
You don't need JOINs in the subquery. The correlation clause is sufficient.
You don't need a GROUP BY in the outer query.
You probably don't need the COUNT(DISTINCT), but I'm not sure so I'm leaving it. in.
Never use commas in the FROM clause. Always use explicit JOIN syntax.
When you join tables - do not forget the join predicates!
If I got your requirement right - this might be a possible solution:
select deptno
,count_projects
,count_employees
from (
select deptno
,count(projno) as count_projects
from project
group by deptno ) as p
inner join
(select workdept
,count(*) as Count_employees
from employee
group by workdept) as e
on p.deptno = e.workdept
The table DEPARTMENT is not necessary unless you have to retrieve specific data from this table as well.

Oracle: single-row subquery returns more than one row

SELECT e.name
from emp e, departm d, salery s
WHERE e.dep=d.depid
AND s.emp= e.empid
AND s.sal > (SELECT round(avg(s.sal)) as AVGSAL
from emp e, departm d, salery s
WHERE e.dep=d.depid AND s.emp= e.empid
GROUP BY d.depid
);
MY Tables are:
emp (empid, name, dep)
departm (depid, name, headdep)
salery (emp, cost, sal, fdate)
I have some foreign keys:
departm: FOREIGN KEY (headdep) REFERENCES departm(depid)
emp: FOREIGN KEY(dep) REFERENCES departm(depid)
salery: FOREIGN KEY(emp) REFERENCES emp(empid)
I want to print a list of all employees which earn more money than the average of theyr department but when i run this query i have an error: single-row subquery returns more than one row
Can anyone help me? What's the problem with my query?
Finally I want to create a procedure, but first of all i have to write the query.
Thank you guys...
Analytic functions are the way to go on this query, but your version has several problems. You would see these problems much more readily if you used proper join syntax. You seem to be learning SQL, so just remember one simple rule: NEVER use commas in from clauses.
Apart from the syntax problem, you have a problem with your correlated subquery. Here is a version that should work:
SELECT e.vollername
from emp e join
salery s
on s.emp= e.empid
WHERE s.sal > (select round(avg(s2.sal)) as AVGSAL
from emp e2 join
salery s2
on s2.emp= e2.empid
where e2.dep = e.depid
);
Note the removal of the departm table from both the inner and the outer queries. In the outer one, it was merely superfluous. In the inner one, it prevented the query from producing the correct results because it removed the correlation.
This is somewhat easier with analytic functions (I also removed the join with departm, since it is not needed):
SELECT e.vollername
FROM (
SELECT
e.vollername,
s.sal,
round(avg(s.sal) over (partition by e.dep)) as avg_dep_sal
FROM
emp e
JOIN salery s ON e.empid = s.emp
)
where sal > avg_dep_sal