The database above is given.
I have an Employee Good Employee and another Employee Excellent Employee. Excellent Employee runs a Department.
I want to update my database so Good Employee works in the Department which is led by Excellent Employee
Is it possible to do something like this?
UPDATE Employee
SET Department = (
SELECT AID
FROM Department
WHERE AID = Department AND Employee.Name = 'Excellent Employee')
WHERE Name = 'Good Employee' LIMIT 1;
(The statement above doesn't work)
Not sure exactly what you've got going on, but here is basic syntax for updating with a join in MySQL:
UPDATE FROM EmployeeAS e
LEFT JOIN Department as dept
ON e.? = dept.?
AND e.Name = 'Good Employee'
SET e.Department = dept.AID
This is definitely possible. You're off to a pretty good start. The parts that are correct are:
You are updating Employee where Name='Good Employee'
You are selecting a Department's AID.
From your query, it looks like the "works_at" relationship is stored in the Employee table under the column Department.
I can't tell how you are modeling the "runs" relationship. Let's just assume an Employee who runs a Department must also work at that department. Hence, we can just find which department "Excellent Employee" works at.
To find the department Excellent works at, we can use this query:
SELECT Department FROM Employee WHERE Name = 'Excellent Employee'
Thus, to move Good to Excellent's department, we can put that into the UPDATE:
UPDATE Employee
SET Department = (
...
) WHERE Name = 'Good Employee'
Unfortunately, MySQL has some quirks, so we need to change our subquery to work around that:
UPDATE Employee
SET Department = (
SELECT X.Department FROM (SELECT * FROM Employee) as X WHERE X.Name = 'Excellent Employee'
) WHERE Name = 'Good Employee'
Here's a fiddle showing it in action: http://sqlfiddle.com/#!2/b68bb/2
Related
create table students(id int,
name varchar(20),
dept varchar(10),
salary int default 10000
);
Insert into students values(1,'Ram','HR',10000);
Insert into students values(2,'Amrit','Mrkt',20000);
Insert into students values(3,'Ravi','HR',30000);
Insert into students values(4,'Raju','finance',40000);
Query which my tutor told me:
select name from employee where dept in(select dept from emp group by dept having count(*)<2);
he told that we should only use that attribute with select statement which has been used in group by and other attributes cannot be used.
But the following query also works:
select name from employee group by dept having count(*)<2;
is my query correct or wrong? if it is correct what is the advantage of using it as nested query than simple query?
If you have only one matching row, then you can use:
select max(name)
from employee
group by dept
having count(*) = 1;
The having clause guarantees one match. The max() returns the value in the one row.
This is fine, but not very orthodox -- it doesn't generalize very well. The form that your tutor suggests is more generalizable. It will readily adapt to looking for employees in departments with 2 employees or 7 or whatever.
So I have 2 tables; a task table and an employee table.
A task is created by an employee and maintains the id of the employee that creates it as creator_id.
A task is assigned to an employee and maintains the id of the employee it is assigned to as responsible_id.
The creator of the task and the employee it is assigned to can be different people.
How do I write a select statement that allows me to display the full names of both the employee that created the task and the employee that is assigned to it.
I think it might look something like this:
SELECT Task.Description, Employee1.name, Employee2.name
FROM Task, Employee Employee1, Employee Employee2
WHERE Task.creator_id = Employee1.id
AND Task.responsible_id = Employee2.id;
I have tried variations of this but it either returns errors or hits the memory limit.
Where am I going wrong?
From your description the query is correct but you should consider rewriting it to use explicit ANSI joins:
SELECT Task.Description, Employee1.name, Employee2.name
FROM Task
JOIN Employee Employee1 ON Task.creator_id = Employee1.id
JOIN Employee Employee2 ON Task.responsible_id = Employee2.id;
Sample SQL Fiddle
I'm working with a SQL database for a Skills Matrix application and I need a query to return a list of employees that are qualified for a given position. Here's a brief overview of the relevant relationships:
Employee has many skills through
qualifications
Position has many
skills through requirements
Is there a efficient way to return a list of employees that have the qualifications to meet a certain position's requirements?
EDIT
employees
- id
- name
positions
- id
- title
skills
- id
- name
requirements
- position_id
- skill_id
qualifications
- employee_id
- skill_id
SELECT *
FROM employees e
WHERE NOT EXISTS (
SELECT *
FROM requirements r
WHERE r.position_id = 1234
AND NOT EXISTS (
SELECT *
FROM qualifications q
WHERE q.skill_id = r.skill_id
AND q.employee_id = e.employee_id
)
)
It will find all employees such that there are no requirement that is not filled by the employee's qualifications.
The use of nested NOT EXISTS is even mentioned in the MySQL Reference Maual
Sure, it's possible. I count seven tables there: Employee, Qualifation, EmployeeQualifications, Position, Requirement, PositionRequirements, and RequirementQualifications. If your Qualifications and Requirements will always be 1:1 (ie, they are the same thing), you can do it more simply (5 tables) like this: Employee, Position, Skill, EmployeeSkills, PositionSkills.
Once you have the tables defined, the trick to building the query is to first look for any positions for which an employee is not qualified, and then do an exclusion join with that result set back to the position table to get your results.
Yes, to achieve what you want you need, given a Position to return only those Employees, that have qualifications that collectively include all the skills the Position requires. If you retrieve these Employees, this list it will represent the list of the customers you are after.
Update
Since I do not have any experience with mysql, my reply only deals with sql server.
Try something like this:
select
qualifications.employee_id
from
qualifications
join
requirements
on
requirements.skill_id = qualifications.skill_id
where
requirements.position_id = 1234
group by
qualifications.employee_id
having
count(qualifications.skill_id) = (select count(distinct skill_id) from requirements where requirements.position_id = 1234)
Create an index on each of
employees.id
qualifications.employee_id
qualifications.skill_id
requirements.skill_id
requirements.position_id
I'm far from being a database expert, so please feel free to let me know I'm doing it entirely wrong. I'm trying to create a set of tables that has the following basic rules:
There are companies, managers and employees. Managers can only belong to one company, but employees can belong to more then one manager. The table structure I've come up with is something like this:
# Companies
company_id
company_name
# Managers
manager_id
company_id
# Employees
employee_id
company_id
employee_name
# Managed By
employee_id
manager_id
Does this structure seem reasonable? I thought I need something like "Managed By" since an employee can have multiple managers.
What I'm boggling on is now how do I manage to grab the records I'd want. For example:
Get all employee names belonging to a certain manager
Get all employee names belonging to two certain managers
All employees to the same company
edit: I think I'm getting the queries figured out but this still feels unweidy, so any help on the table structure would be appreciated.
The fact I'm having problems writing queries for this information makes me think I've done something fundamentally wrong with the table structure. Hopefully someone here can set me right?
Generally, the scheme is correct. The one possibility that does exist, however, is that you could have data where an employee is managed by managers at more than two companies.
For your queries:
select distinct Employees.employee_name as name from Employees, Managers, ManagedBy where Managers.manager_id = X and ManagedBy.manager_id = Managers.manager_id and Employees.employee_id = ManagedBy.employee_id;
and
select distinct Employees.employee_name as name from Employees, Managers, ManagedBy where (Managers.manager_id = X or Managers.manager_id = Y) and ManagedBy.manager_id = Managers.manager_id and Employees.employee_id = ManagedBy.employee_id;
where X and Y are the manager IDs you want.
edit: I know you crossed out the queries you wanted, but the third one is this:
select distinct Employees.employee_name as name from Employees where Employees.company_id = Z;
where Z is the company ID you want.
All employees to the same company
SELECT employee_id, employee_name, company_name
FROM Employees
LEFT JOIN Companies ON Employees.company_id = Companies.company_id
WHERE Companies.company_id = ????
or if you pulling by name
WHERE Companies.company_name = 'ABC'
Get all employee names belonging to a certain manager
SELECT employee_id, employee_name, manager_id
FROM Employees
LEFT JOIN Managed_By ON Employees.employee_id = Managed_By.employee_id
WHERE Managed_By.manager_id = ????
manager_name in Managers table would be nice to have
I have a bunch of records (orders) that I want to make available to users to make reports from.
The users come from different departments, and I would like to make it, so each department can only see their own stuff.
I can't figure out how to do this the right way.
What I have now is:
- A model where I have placed a Filter on the Order table.
The filter can use GetUserID() to get the users name, but I can't figure out how I get from that to the "UserDepartment" table that maps users to specific departments.
Ofcourse, I would prefer a solution whereby I didn't have to create new access groups or edit the model for each department that someone might dream up.
Any clues?
(Using SQL server 2008)
EDIT: This link http://blogs.msdn.com/bobmeyers/articles/Implementing_Data_Security_in_a_Report_Model.aspx shows the basics of what I'm trying to do, but the author seems to assume that each record have a UserName field that can be matched.
In my case i want all users of department X to be able to access the line.
We had a similar problem to this and ended up writing a function in SQL.
The function did the following:
Received the username parameter from SRSS
Performed a lookup on the permissions table and retrieved the records (department Id's in your case).
returned the department Id's
Then our sql statement looked like this:
SELECT *
FROM ImportantData
WHERE DepartmentId IN (SELECT Id FROM fn_GetUserDepartmentAllocations(#UserName))
This did force us to modify all of the sql queries but it allowed us to do it with minimal complex logic.
The other thing that this allows for is if you have one user who transcends department boundaries: for example a manager of 2 departments.
CREATE FUNCTION [dbo].[fn_GetUserDepartmentAllocations]
(
#UserName NVARCHAR(100)
)
RETURNS
#TempPermissions TABLE
(
DepartmentId Int
)
AS
BEGIN
INSERT INTO #TempPermissions
SELECT DepartmentId
FROM DepartmentPermissions
WHERE DepartmentAllowedUsername = #UserName
RETURN
END
The main benefit to doing it this way is it also allows you to edit one place to change the entire permissions structure, you don't have to go through each and every report to change it, instead you change one place
For example you could have a manager who belongs to 2 departments but is not allowed to view them except on thursdays (I know silly example but you get the point hopefully).
Hope this helps
Pete
This assume that Users have Orders.
So, filter by users who exist in the same dept as the filter user. Don't filter orders directly.
I've guessed at schema and column names: hoep you get the idea...
SELECT
MY STuff
FROM
Order O
JOIN
UserDept UD ON O.UserCode = UD.UserCode
WHERE
EXISTS (SELECT *
FROM
UserDept UD2
WHERE
UD2.UserCode = #MYUSerCode
AND
UD2.DeptID = UD.DeptID)
--or
SELECT
MY STuff
FROM
Order O
JOIN
UserDept D ON O.UserCode = D.UserCode
JOIN
UserDept U ON D.DeptID = U.DeptID
WHERE
U.UserCode = #MYUSerCode
What you're trying to achieve is difficult using the GetUserID() method. To use that your source query would have to return a lot of redundant data, imagine something like the following:
/*
Table: User
Fields: UserID, LoginName, FullName
Table: Department
Fields: DepartmentID, Name
Table: UserDepartments
Fields: UserID, DepartmentID
Table: Order
Fields: OrderNumber, DepartmentID
*/
SELECT O.OrderNumber, O.DepartmentID, U.LoginName
FROM Order O
JOIN Department D ON D.DepartmentID = O.DepartmentID
JOIN UserDepartments UD ON UD.DepartmentID = D.DepartmentID
JOIN User U ON U.UserID = UD.UserID
This will give you more rows than you want, basically a copy of the order for each user in the department that owns the order.
Now you can apply your filter as described in the link you provided. This will filter it down to just one copy of the order rows for the current user if they're in the right department.
If this is a performance issue there's other alternatives, easiest being using a local report (.RDLC) in either ASP.NET, WinForms or WPF and passing user details off to the data call so the filtering can be done in the SQL.