Return Complex data types in SQL server - sql

I have two tables as below: One is department, the other is employee. Every department have several employees. Here is table definition:
Create table [dbo].[Department]
(
ID int not null,
Name varchar(100) not null,
revenue int not null
)
Create table [dbo].[Employee]
(
ID int not null,
DepartmentID int not null,--This is foreign key to Department
Name varchar(100) not null,
Level int not null
)
Now, I want to query all the department with employee if department revenue is more than a value. So the result will contain a department list. For every department, it should also contain employee list.
In our client, we use c# to retrieve the data, here is the interface:
public List<Department> GetHighRevenueDepartmentWithEmployee(int revenueBar)
{
throw new NotImplementedException();
}
My question here is: is it possible to get the compound result in one query/stored procedure. It is OK use one stored procedure to query multiple times, but the whole data must be return back to client in one time.(This is performance reason) How can we achieve this? I know we can define table values type here, but I cannot define a table value type which contain another table value as column inside.

Typically, you'd just return a result set with all of the columns from both tables:
SELECT
d.ID as DepartmentID,d.Name as DepartmentName,d.Revenue,
e.ID as EmployeeID,e.Name as EmployeeName,e.Level
FROM
Department d
inner join
Employee e
on d.ID = e.DepartmentID
WHERE
d.revenue > #value
ORDER BY
d.ID
Now, the data returned for the department will be repeated multiple times - once for every employee. But that's fine. Just use the first row for each new department and ignore it in the remaining rows. That would be for the first row of the result set, and for any row where the DepartmentID is different from the previous row.

Related

Conversion failed when converting the varchar value 'Assistant' to data type int. SQL Message error

I have this query :
--What is the Specialization of employee ID 5?
SELECT EmpName
FROM Employee
WHERE Employee.ID IN(
SELECT Specialization
FROM Specialization
WHERE spe_mng_id = 5);
And when I run the command it returns me this error message:
"Conversion failed when converting the varchar value 'Assistant' to data type int."
My records are in varchar :
--Table Specialization
create table Specialization(
spe_id int,
Specialization varchar(50),
spe_mng_id int IDENTITY(1,1),
FOREIGN KEY(spe_mng_id) REFERENCES Employee(ID)
);
I don't understand what is hapenning, I am also quite new to SQL so it's dificult to find answers for my exact problem, thus asking the comunity!
I am expecting to get a return value of the Specialization of Employee with ID 5.
ID and spe_mng_id are linked.
When you run SELECT Specialization FROM Specialization WHERE spe_mng_id = 5, you already get a list of all specializations (possibly only one) of employee n5. If this is the only information needed (as in nothing from table Employee is required), you could even run this query directly.
However, if you also need to get the EmpName as an output (or any other info from table Employee), you will need to join the two tables using the JOIN command, using the info that spe_mng_id is a reference to ID in the table Employee (as seen through the FOREIGN KEY definition).
Something like:
SELECT EmpName, Specialization
FROM Employee
JOIN Specialization ON Employee.ID = Specialization.spe_mng_id
WHERE Employee.ID = 5
The conversion problem happened because you were trying to find rows whose Employee.ID (an INT) was in the list of Specialization of Employee n5 (a column of VARCHAR).

creating the sql query for company supervisors

I have four tables
create table emp (emp_ss int, emp_name nvarchar(20));
create table comp(comp_name nvarchar(20), comp_address nvarchar(20));
create table works (emp_ss int, comp_name nvarchar(20));
create table supervises (spv_ss int, emp_ss int );
Here SUPRVISER_SS and EMP_SS are subset of SS. Now I have to find:
the name of all the companies who have more than 4 supervisors
I have made a query for the above problem but not sure whether it is correct or not
SELECT COMP_NAME , COUNT(EMP_SS) FROM WORKS
WHERE EMP_SS IN (SELECT DISTINCT SPV_SS FROM supervises)
GROUP BY COMP_NAME
HAVING COUNT(EMP_SS) > 4;
the name of supervisors who have the largest number of employees
but unable to get the required result of the above condition
SELECT SPV_SS, COUNT(*) max_ FROM supervises GROUP BY SPV_SS
You don't need to have a seperate table for supervisors unless they come with extra information that doesn't belong in the employee table, just add an extra field (foreign key) in Employee table that links to the primary key in the same table.
First question: select company just use a group by companyid clause and then check if the count of supervisors is larger than 4 for.
Second question: select count(empid) and supervisor, use group by supervisor clause and add order by clause on the count column
I explained the logic, as for the actual sql code, you're gonna have to figure that out yourself.

How to insert values from column A of table X to column B of table Y - and order them randomly

I need to collect the values from the column "EmployeeID" of the table "Employees" and insert them into the column "EmployeeID" of the table "Incident".
At the end, the Values in the rows of the column "EmployeeID" should be arranged randomly.
More precisely;
I created 10 employees with their ID's, counting from 1 up to 10.
Those Employees, in fact the ID's, should receive random Incidents to work on.
So ... there are 10 ID's to spread on all Incidents - which might be 1000s.
How do i do this?
It's just for personal exercise on the local maschine.
I googled, but didn't find an explicit answer to my problem.
Should be simple to solve for you champs. :)
May anyone help me, please?
NOTES:
1) I've already created a column called "EmployeeID" in the table "Incident", therefore I'll need an update statement, won't I?
2) Schema:
[dbo].[EmployeeType]
[dbo].[Company]
[dbo].[Division]
[dbo].[Team]
[dbo].[sysdiagrams]
[dbo].[Incident]
[dbo].[Employees]
3) 1. Pre-solution:
CREATE TABLE IncidentToEmployee
(
IncidentToEmployeeID BIGINT IDENTITY(1,1) NOT NULL,
EmployeeID BIGINT NULL,
Incident FLOAT NULL
PRIMARY KEY CLUSTERED (IncidentToEmployeeID)
)
INSERT INTO IncidentToEmployee
SELECT
EmployeeID,
Incident
FROM dbo.Employees,
dbo.Incident
ORDER BY NEWID()
SELECT * FROM IncidentToEmployee
GO
3) 2. Output by INNER JOIN ON
In case you are wondering about the "Alias" column;
Nobody really knows which persons are behind the ID's - that's why I used an Alias column.
SELECT Employees.Alias,
IncidentToEmployee.Incident
FROM Employees
INNER JOIN
IncidentToEmployee ON
Employees.EmployeeID = IncidentToEmployee.EmployeeID
ORDER BY Alias
4) Final Solution
As I mentioned, I added at first a column called "EmployeeID" already to my "Incident" table. That's why I couldn't use an INSERT INTO statement at first and had to use an UPDATE statement. I found the most suitable solution now - without creating a new table as I did as a pre-solution.
Take a look at the following code:
ALTER Table Incident
ADD EmployeeID BIGINT NULL
UPDATE Incident
SET Incident.EmployeeID = EmployeeID
FROM Incident INNER JOIN Employees
ON Incident = EmployeeID
SELECT
EmployeeID,
Incident
FROM dbo.Employees,
dbo.Incident
ORDER BY NEWID()
Thank you all for your help - It took way longer to find a solution as I thought it would take; but I finally made it. Thanks!
UPDATE
I think you need to allocate different task to different user, a better approach will be to create a new table let's say EmployeeIncidents having columns Id(primary) , EmployeeID and IncidentID .
Now you can insert random EmployeesID and random IncidentID to new table, this way you will be able to keep records also ,
Updating Incident table will not be a smart choice.
INSERT INTO EmployeeIncidents
SELECT TOP ( 10 )
EmployeesID ,
IncidentID
FROM dbo.Employees,
dbo.Incident
ORDER BY NEWID()
Written by hand, so may need to tweak syntax, but something like this should do it. The Rand() function will give the same value unless seeded, so you can see with something like date to get randomness.
Insert Into Incidents
Select Top 10
EmployeeID
From Employees
Order By
Rand(GetDate())

How to perform a mass SQL insert to one table with rows from two seperate tables

I need some T-SQL help. We have an application which tracks Training Requirements assigned to each employee (such as CPR, First Aid, etc.). There are certain minimum Training Requirements which all employees must be assigned and my HR department wants me to give them the ability to assign those minimum Training Requirements to all personnel with the click of a button. So I have created a table called TrainingRequirementsForAllEmployees which has the TrainingRequirementID's of those identified minimum TrainingRequirements.
I want to insert rows into table Employee_X_TrainingRequirements for every employee in the Employees table joined with every row from TrainingRequirementsForAllEmployees.
I will add abbreviated table schema for clarity.
First table is Employees:
EmployeeNumber PK char(6)
EmployeeName varchar(50)
Second Table is TrainingRequirementsForAllEmployees:
TrainingRequirementID PK int
Third table (the one I need to Insert Into) is Employee_X_TrainingRequirements:
TrainingRequirementID PK int
EmployeeNumber PK char(6)
I don't know what the Stored Procedure should look like to achieve the results I need. Thanks for any help.
cross join operator is suitable when cartesian product of two sets of data is needed. So in the body of your stored procedure you should have something like:
insert into Employee_X_TrainingRequirements (TrainingRequirementID, EmployeeNumber)
select r.TrainingRequirementID, e.EmployeeNumber
from Employees e
cross join TrainingRequirementsForAllEmployees r
where not exists (
select 1 from Employee_X_TrainingRequirements
where TrainingRequirementID = r.TrainingRequirementID
and EmployeeNumber = e.EmployeeNumber
)

How to improve user defined function with while on SQL Server?

I have a SQL Server 2008 R2 UDF which performs a kind of recursive loop. I mean, I have a table called Employees where in one of my columns I store another Employee id (his boss).
When I get an employee id, I must be able to know the whole department below him. For example:
Employee Joe (ID:1) works for Robert (ID:2)
Employee Robert (ID:2) works for Michelle (ID:3)
I must be able to count the salary (let's suppose it's on the same table) of all employees below Michelle, i.e. Robert and Joe.
Up to now, I created a UDF that returns a table with all employee ids below Michelle and use an EXISTS clause on the queries' where but it performs very poorly.
Do you guys have another idea?
Thank you!
You should probably use a recursive CTE rather than a WHILE loop to find all of the employees. I don't have your tables or data so I've made some up:
create table Employees (
ID int not null primary key,
Name varchar(20) not null,
BigBossID int null foreign key references Employees(ID),
Salary decimal(18,4) not null
)
go
insert into Employees (ID,Name,BigBossID,Salary) values
(1,'Joe',2,2.50),
(2,'Robert',3,19000.75),
(3,'Michelle',null,1234567890.00)
And then I can use this query to find all employees below Michelle:
declare #RootID int
set #RootID = 3
;With EmployeesBelowRoot as (
select ID from Employees where BigBossID = #RootID
union all
select e.ID from Employees e inner join EmployeesBelowRoot ebr on e.BigBossID = ebr.ID
)
select SUM(Salary) from Employees where ID in (select ID from EmployeesBelowRoot)
You could (if you think it's worth it) place the CTE (EmployeesBelowRoot) into a UDF and call it with #RootID as a parameter, but I've just put it directly in the query for now.