How to find average difference in mysql? - mysql

Consider a table employee storing the details of the employee.
ssn : social security number of the employee
address : storing the address of the employee
Looking at the address field in the employee table, you would notice that all the employees reside in "Fondren, Houston, TX". Consider the integer in the address field as house number. Consider the distance between the two houses as the difference in the house numbers, so the distance between house number 2 and 38 is 36 units. Write a query to determine the average distance between the house of the employee with ssn = '123456789' and the other employees' houses. Print the answer to two decimal places. Make sure that the answer is formatted with a comma like x,xxx.xx .
Can someone please help me solving this problem?
I do not want to use a SQL function.
The query I have made is:
SELECT
avg(
abs(CAST(address AS UNSIGNED) -
SELECT CAST(address AS UNSIGNED) from test.test where ssn = 1234)
) as average from test.test;

Assuming you don't want to include the distance from the employee's house to their own house, you need to compute the average excluding that. One way to do that is by CROSS JOINing a table of the numbers of employee houses not including the employee of interest, and a table of the number of the employee of interest's house. You can then compute the SUM of the absolute differences and divide that by the row count to get the average. You can then use FORMAT to get the output in the desired format:
SELECT FORMAT(SUM(ABS(oth - emp)) / COUNT(oth), 2) AS average
FROM (
SELECT CAST(address AS SIGNED) AS oth
FROM test
WHERE ssn != '123456789'
) t
CROSS JOIN (
SELECT CAST(address AS SIGNED) AS emp
FROM test
WHERE ssn = '123456789'
) t2
Demo on SQLFiddle

SELECT format (avg(abs(substring_index(address, ' ', 1)-(SELECT
substring_index(address, ' ', 1)
FROM employee
WHERE ssn = '123456789'
))), 2)
FROM employee
WHERE ssn != '123456789';

Related

Find the count of elements from another table

First the schema - i have 4 tables:
office - officeid, officename
member - memberid, officeid, membername (multiple members per office)
transaction - transactionid, memberid, transactiontype (multiple transactions per member)
activity - activityid, officeid (multiple activities per office)
How can i get the list of member names, along with offices and the count of each transaction type and total count of activities for that office with a single query?
I have tried myself and i can get the office names, member names and activity count but not able to get the transaction count (per transaction type) with a single query. Wondering if this is possible at all.
Any suggestions/help is appreciated. Please let me know if i can provide any details which i missed
Edit - I added a sqlfiddle with some sample data at http://sqlfiddle.com/#!9/9cf7b/1
Also realized i had missed the officeid foreign key in the member table.
Edit - Adding expected output
officename, membername, transaction_count_1, trasaction_count_2, activitycount
abc , aa , 1 , 1, , 3
abc , bb , 1 , 0, , 1
abc , cc , 0 , 1, , 0
I think this can solve your purpose.
select b.membername,a.officename,count(transactiontype)
from office a,
member b,
transaction c
where a.officeid = b.officeid
and b.memberid = c.memberid
group by b.membername,a.officename
If you need any further data manipulation just give me an idea (perferably a screenshot or an image) of how your output shall look and i shall change the query accordingly.
Thanks.

MySQL dynamic order

In general, all I need to do is to order a MySQL table.
But, it has to be a "smart" order and I would like to hear your opinions.
There is a table of customers
id, name, email, phone, country, language, registration_time
There is another table which holds the skills of sales managers as numeric values -
sales_manager_id, skill_type, skill_name, skill_value
7, language , English , 5
Which means that manager number 7 speaks English on level 5.
Every sales manager can have multiple skills.
Now, I want to order the customers table by country, language and registration_time (in this exact order) for a specific sales manager in such a way that the top rows will be from a country in which this sales manager has highest skills, after this by language in which he has the highest skills and after this by registration time.
Do you have any suggestions? The biggest problem is that this query should be simple and readable as much as possible because there would be modifications in the future and I don't want to deal with enormous queries.
I assume I understand your problem. If not please correct me, else here is my solution.
I did a few changes to your tabels in order to test the query and you can test my solution like I did here: SQL Fiddle
(1) You need to JOIN your customers table two times with the skills table - first for the country skill and second for the language skill of a sales manager:
select *
from customers
join skills as country_skills on country_skills.skill_name = customers.country
join skills as language_skills on language_skills.skill_name = customers.language
(2) You need to restrict your results for just the sales manager you want, e.g. sales manager with id = 11:
where country_skills.sales_manager_id = 11
and language_skills.sales_manager_id = 11
(3) The 'dynamic' order you want:
order by country_skills.skill_value desc, language_skills.skill_value desc, regTime desc
This would be my complete query:
select *
from customers
join skills as country_skills on country_skills.skill_name = customers.country
join skills as language_skills on language_skills.skill_name = customers.language
where country_skills.sales_manager_id = 11
and language_skills.sales_manager_id = 11
order by country_skills.skill_value desc, language_skills.skill_value desc, regTime desc
So you got all customers sorted by country skills of a specific sales manager > language skills of a specifiy sales manager > regTime of customer.
This query ignores customers with a country or language the sales manager got no skill... you can avoid that with a LEFT JOIN

Why this query doesn't work with such condition?

I'm trying to solve some tasks from this http://sqlzoo.net/wiki/SELECT_within_SELECT_Tutorial
At the last task(number 8) I wrote a query:
select name, continent from world a
where a.population >
(select 3*max(population) from world b
where b.continent = a.continent)
but this query doesn't return any rows. But works almost the same query(just added an additional conditin in the end of subquery). But what's the matter? Why doesn't it return raws even if names of countries are the same?
select name, continent from world a
where a.population >
(select 3*max(population) from world b
where b.continent = a.continent and a.name <> b.name)
Let me translate what both query does to english, so you can realize the difference.
first query; compare and get all countries who are on the same continent and have more than 3 times of the maximum populated country in that continent.
second query; compare and get all countries who are on the same continent and have more than 3 times of the maximum populated country in that continent except himself.
in your first query the maximum populated country cannot be more than 3 times more populated than himself if he is the max populated country himself so your query returns 0 results.
but on the second query the maximum populated country EXCEPT himself can have population 3 times more than other countries in the same continent.

Query to get the output as shown in designation table

EmpId EmpDeptName
1 Account
2 Sales
3 IT
4 HR
i want output in the format
EmpId Account Sales IT HR
1
2
3
4
If anybody knows how to write query to get this output , please provide me that query.
This type od data transformation is a PIVOT, where you take row data and convert it to columns.
You did not provide many details, but if you wanted the count of employees in each department, you could use something like this:
select Account, Sales, IT, HR
from
(
select EmpDeptName
from employees
) d
pivot
(
count(EmpDeptName)
for EmpDeptName in (Account, Sales, IT, HR)
) p;
This will display the total number of employees in each department as column data instead of rows.

MySQL - The most occuring for the specific day?

I'm stuck on this problem.
Basically I need to find out for each department how to figure out which days had the most sales made in them. The results display the department number and the date of the day and a department number can appear several times in the results if there were several days that have equally made the most sales.
This is what I have so far:
SELECT departmentNo, sDate FROM Department
HAVING MAX(sDate)
ORDER BY departmentNo, sDate;
I tried using the max function to find which dates occurred most. But it only returns one row of values. To clarify more, the dates that has the most sales should appear with the corresponding column called departmentNo. Also, if two dates for department A has equal amount of most sales then department A would appear twice with both dates showing too.
NOTE: only dates with the most sales should appear and the departmentNo.
I've started mySQL for few weeks now but still struggling to grasp the likes of subqueries and store functions. But i'll learn from experiences. Thank you in advance.
UPDATED:
Results I should get:
DepartmentNo Column 1: 1 | Date Column 2: 15/08/2000
DepartmentNo Column 1: 2 | Date Column 2: 01/10/2012
DepartmentNo Column 1: 3 | Date Column 2: 01/06/1999
DepartmentNo Column 1: 4 | Date Column 2: 08/03/2002
DepartmentNo Column 1: nth | Date Column 2: nth date
These are the data:
INSERT INTO Department VALUES ('1','tv','2012-05-20','13:20:01','19:40:23','2');
INSERT INTO Department VALUES ('2','radio','2012-07-22','09:32:23','14:18:51','4');
INSERT INTO Department VALUES ('3','tv','2012-09-14','15:15:43','23:45:38','3');
INSERT INTO Department VALUES ('2','tv','2012-06-18','06:20:29','09:57:37','1');
INSERT INTO Department VALUES ('1','radio','2012-06-18','11:34:07','15:41:09','2');
INSERT INTO Department VALUES ('2','batteries','2012-06-18','16:20:01','23:40:23','3');
INSERT INTO Department VALUES ('2','remote','2012-06-18','13:20:41','19:40:23','4');
INSERT INTO Department VALUES ('1','computer','2012-06-18','13:20:54','19:40:23','4');
INSERT INTO Department VALUES ('2','dishwasher','2011-06-18','13:20:23','19:40:23','4');
INSERT INTO Department VALUES ('3','lawnmower','2011-06-18','13:20:57','20:40:23','4');
INSERT INTO Department VALUES ('3','lawnmower','2011-06-18','11:20:57','20:40:23','4');
INSERT INTO Department VALUES ('1','mobile','2012-05-18','13:20:31','19:40:23','4');
INSERT INTO Department VALUES ('1','mouse','2012-05-18','13:20:34','19:40:23','4');
INSERT INTO Department VALUES ('1','radio','2012-05-18','13:20:12','19:40:23','4');
INSERT INTO Department VALUES ('2','lawnmowerphones','2012-05-18','13:20:54','19:40:23','4');
INSERT INTO Department VALUES ('2','tv','2012-05-12','06:20:29','09:57:37','1');
INSERT INTO Department VALUES ('2','radio','2011-05-23','11:34:07','15:41:09','2');
INSERT INTO Department VALUES ('1','batteries','2011-05-21','16:20:01','23:40:23','3');
INSERT INTO Department VALUES ('2','remote','2011-05-01','13:20:41','19:40:23','4');
INSERT INTO Department VALUES ('3','mobile','2011-05-09','13:20:31','19:40:23','4');
For department1 the date 2012-05-18 would appear because that date occurred the most. And for every department, it should only show the one with the most sales, and if same amount of sales appears on the same date then both will appear, e.g. Department 1 will appear twice with both the dates of max sales.
I've tested the following query based on the table and two columns you've provided along with sample data. So, let me describe it for you. The inner-most "PREQUERY" is doing a count by department and date. The results of this will be pre-ordered by Department first, THEN the highest count in DESCENDING ORDER (so highest sales count is listed FIRST), it doesn't matter what date the count happened.
Next, by utilizing MySQL #variables, I'm pre-declaring two to be used in the query. #variables are like inline programming with MySQL. They can be declared once and then changed as applied to each record being processed. So, I'm defaulting to a bogus department value and a zero sales count.
Now, I'm grabbing the results of the PreQuery (Dept, #Sales and Date), but now, adding a test. If it is the FIRST ENTRY for a given department, use that record's "NumberOfSales" and put into the #maxSales variable and store as a final column name "MaxSaleCnt". The next column name uses the #lastDept and is set to whatever the current record's Department # is. So it can be compared to the next record.
If the next record is the same department, then it just keeps whatever the #maxSales value was from the previous, thus keeping the same first count(*) result for ALL entries on each respective department.
Now, the closure. I've added a HAVING clause (not a WHERE as that restricts what records get tested, but HAVING processes AFTER the records are part of the PROCESSED set. So now, it would have all 5 columns. I am saying ONLY KEEP those records where the final NumberOfSales for the record MATCHES the MaxSaleCnt for the department. If one, two or more dates, no problem it returns them all per respective department.
So, one department could have 5 dates with 10 sales each, and another department has 2 dates with only 3 sales each, and another with only 1 date with 6 sales.
select
Final.DepartmentNo,
Final.NumberOfSales,
Final.sDate
from
(select
PreQuery.DepartmentNo,
PreQuery.NumberOfSales,
PreQuery.sDate,
#maxSales := if( PreQuery.DepartmentNo = #lastDept, #maxSales, PreQuery.NumberOfSales ) MaxSaleCnt,
#lastDept := PreQuery.DepartmentNo
from
( select
D.DepartmentNo,
D.sDate,
count(*) as NumberOfSales
from
Department D
group by
D.DepartmentNo,
D.sDate
order by
D.DepartmentNo,
NumberOfSales DESC ) PreQuery,
( select #lastDept := '~',
#maxSales := 0 ) sqlvars
having
NumberOfSales = MaxSaleCnt ) Final
To clarify the "#" and "~" per you final comment. The "#" indicates a local variable to the program (or in this case and in-line sql variable) that can be used in the query. The '~' is nothing more than a simple string that probability would never exist that of any of your departments, so when it is compared to the first qualified record, does an IF( '~' = YourFirstDepartmentNumber, then use this answer, otherwise use this answer).
Now, how do the above work. Lets say the following is the results of your data returned by the inner-most query, grouped and ordered by the most sales at the top going down... SLIGHTLY altered from your data, lets just assume the following to simulate multiple dates on Dept 2 that have the same sales quantity...
Row# DeptNo Sales Date # Sales
1 1 2012-05-18 3
2 1 2012-06-18 2
3 1 2012-05-20 1
4 2 2012-06-18 4
5 2 2011-05-23 4
6 2 2012-05-18 2
7 2 2012-05-12 1
8 3 2011-06-18 2
9 3 2012-09-14 1
Keep track of the actual rows. The innermost query that finishes as alias "PreQuery" returns all the rows in the order you see here. Then, that is joined (implied) with the declarations of the # sqlvariables (special to MySQL, other sql engines dont do this) and starts their values with the lastDept = '~' and the maxSales = 0 (via assignment with #someVariable := result of this side ).
Now, think of the above being handled as a
DO WHILE WE HAVE RECORDS LEFT
Get the department #, Number of Sales and sDate from the record.
IF the PreQuery Record's Department # = whatever is in the #lastDept
set MaxSales = whatever is ALREADY established as max sales for this dept
This basically keeps the MaxSales the same value for ALL in the same Dept #
ELSE
set MaxSales = the # of sales since this is a new department number and is the highest count
END IF
NOW, set #lastDept = the department you just processed to it
can be compared when you get to the next record.
Skip to the next record to be processed and go back to the start of this loop
END DO WHILE LOOP
Now, the reason you need to have the #MaxSales and THEN the #LastDept as returned columns is they must be computed for each record to be used to compare to the NEXT record. This technique can be used for MANY application purposes. If you click on my name, look at my tags and click on the MySQL tag, it will show you the many MySQL answers I've responded to. Many of them do utilize # sqlvariables. In addition, there are many other people who are very good at working queries, so dont just look in one place. As for any question, if you find a good answer that you find helpful, even if you didn't post the question, clicking on an up-arrow next to the answer helps others indicate what really helped them understand and get resolution to questions -- again, even if its not your question. Good luck on your MySQL growth.
I think this can be achieved with a single query, but my experiences for similar functionality have involved either WITH (as defined in SQL'99) using either Oracle or MSSQL.
The best (only?) way to approach a problem like this is to break in into smaller components. (I don't think your provided statement provides all columns, so I'm going to have to make a few assumptions.)
First, how many sales were made for each day for each group:
SELECT department, COUNT(1) AS dept_count, sale_date
FROM orders
GROUP BY department, sale_date
Next, what's the most sales for each department
SELECT tmp.department, MAX(tmp.dept_count)
FROM (
SELECT department, COUNT(1) AS dept_count
FROM orders
GROUP BY department
) AS tmp
GROUP BY tmp.department
Finally, putting the two together:
SELECT a.department, a.dept_count, b.sale_date
FROM (
SELECT tmp.department, MAX(tmp.dept_count) AS max_dept_count
FROM (
SELECT department, COUNT(1) AS dept_count
FROM orders
GROUP BY department
) AS tmp
GROUP BY tmp.department
) AS a
JOIN (
SELECT department, COUNT(1) AS dept_count, sale_date
FROM orders
GROUP BY department, sale_date
) AS b
ON a.department = b.department
AND a.max_dept_count = b.dept_count