How to get hierarchical data - sql

I want to execute a SQL sentence, there are two tables
Table Name Description
********* *********
H_person Employee Data
Modelorg Position Data
I want to write an sql that shows "who is connected to whom". In h_person table
Fıeld Name Description
********* *********
p_no Employee ID
P_ad Employee Name
P_soyad Employee Surname
P_pzsyn Employee Position ID
In Modelorg Table
Fıeld Name Description
********* *********
Pozkod Position ID
Pozad Position Name
USTPOZKOD the upper position (POZKOD connected to USTPOZKOD)
USTPOZKOD is also the POZKOD at the same time,there is a hierarchial connection.
I would like to form a report shows person ID, Name, Surname, Position Name, Upper Position Name, Manager ID and Maneger Name-Surname(helding Upper Position ID).
Additionally sometimes Upperpostion may be empty and when executing the report, it will be null. I would like to add a rule, If upperposition is null, bring 2 level upper manager
In H_person Table
First Data
*** ***
P_no=14556 P_ad=John
p_Soyad= Onel
P_Pzsyn= 72878 /Account Specialist
Second Data
P_no=14656
P_ad=Sara
p_Soyad= Yildiz
P_Pzsyn= 5455 /Account Manager
*** ***
In Modelorg Table
Pozkod=72878
Pozad=Account Specialist
Ustpozkod=5455 (Account Manager) USTPOZKOD is at the same time a pozkod.
select p_no, p_ad, p_soyad, Pozad, USTPOZKOD (we connected pozkod to USTPOZKOD and I woul like to bring "who held this USTPOZKOD(NAME, Surname) from h_person, modelorg.
USTPOZKOD also equals to POZKOD because someone helds this position

You need to use a common table expression (CTE) to build the recursive query.
An example:
WITH #rec AS
(
SELECT ID, ParentID
FROM RecTable
WHERE ParentID = 0
UNION ALL
SELECT R.ID, R.ParentID
FROM RecTable R
INNER JOIN #rec P ON R.ParentID = P.ID
)
SELECT *
FROM #rec

Related

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.

Connect by prior - show parent record in result set also

I have this code
select column from Table
start with supervisor_id='555555'
connect by prior employee_id=supervisor_id
So this query gives me the result for all the employees that have 55555 as their supervisor_id and any other employees that have those employee_id as their supervisor_id, but I also want the person with the user_id = 555555 to show up in my result too, and he has to show up in the same column as if he is part of the result of the query. Any help is appreciated. Thank you
Put an OR condition and it should work.
See demo: http://sqlfiddle.com/#!4/7ef7f9/1
Select distinct *
from table1
start with supervisor_id='555555' or employee_id='555555'
connect by prior employee_id=supervisor_id
You could union the supervisor into the query:
select column from Table where user_id='555555'
union all
select column from Table
start with supervisor_id='555555'
connect by prior employee_id=supervisor_id
I'm assuming that the person with user_id = '555555' comes from Table also and you want to display the same column - if not substitute those changes you need into the above SQL.

Join master table's data to a key/value table data in one SELECT

I have a table called Contacts that contains the columns
Id
FirstName
LastName
I have another table called ContactsExtra. It has the following columns:
Id
ContactId (FK refers to Contacts Id)
PropertyId (FK refers to Properties Id)
PropertyValue
This is a Key/Value table that stores some extra contact properties. E.g. if contact has a Salary property there is a record in this table for all Contacts that stores the Salary value.
All Properties (whether they are in the main Contacts table or not) are stored in a separate table called Properties. In this table, those properties that come from Contacts (FirstName and LastName) are locked. But the user can add or remove custom properties (these ones are not locked). The value of these new properties will be stored in ContactsExtra.
The Properties table contains the following columns:
Id
Name
What I would like to do is to display all the contact information using one SELECT. So e.g. in the above case there will be a result with columns Id,FirstName,LastName and also Salary. The first three come from Contacts and the last comes from the Key/Value table. How can I join these information together?
SELECT
Contacts.FirstName,
Contacts.LastName,
Properties.Name,
ContactsExtra.PropertyValue
FROM
Contacts
LEFT OUTER JOIN ContactsExtra ON Contacts.Id = ContactsExtra.ContactId
LEFT OUTER JOIN Properties ON ContactsExtra.PropertyId = Properties.Id
Okay, here's the update with a PIVOT (not UNPIVOT as I first thought)...
SELECT
*
FROM
(
SELECT
Contacts.FirstName,
Contacts.LastName,
Properties.Name,
ContactsExtra.PropertyValue
FROM
Contacts
LEFT OUTER JOIN ContactsExtra ON Contacts.Id = ContactsExtra.ContactId
LEFT OUTER JOIN Properties ON ContactsExtra.PropertyId = Properties.Id
) DerivedPivotable
PIVOT
(
MAX(PropertyValue)
FOR [Name] IN (<comma delimited list of values from your Properties.Name field, without string markup>)
--FOR [Name] IN (Salary, Height, Status, SSN) --example row
) Pivoted
Please check against your data - I expect the output to be something like...
FirstName LastName Salary Height Status SSN
-----------------------------------------------------------
Jane Doe NULL 5'7" Single NULL
Bob Smith 70,000 6'1" NULL 123-45-6789
The use of MAX is a bit of a kludge because it has to be an aggregate function there. The assumption is being made that there is only one value in the ContactsExtra table for each combination of user and property.

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
)

Insert into table some values which are selected from other table

I have my database structure like this ::
Database structure ::
ATT_table- ActID(PK), assignedtoID(FK), assignedbyID(FK), Env_ID(FK), Product_ID(FK), project_ID(FK), Status
Product_table - Product_ID(PK), Product_name
Project_Table- Project_ID(PK), Project_Name
Environment_Table- Env_ID(PK), Env_Name
Employee_Table- Employee_ID(PK), Name
Employee_Product_projectMapping_Table -Emp_ID(FK), Project_ID(FK), Product_ID(FK)
Product_EnvMapping_Table - Product_ID(FK), Env_ID(FK)
I want to insert values in ATT_Table. Now in that table I have some columns like assignedtoID, assignedbyID, envID, ProductID, project_ID which are FK in this table but primary key in other tables they are simply numbers).
Now when I am inputting data from the user I am taking that in form of string like a user enters Name (Employee_Table), product_Name (Product_table) and not ID directly. So I want to first let the user enter the name (of Employee or product or Project or Env) and then value of its primary key (Emp_ID, product_ID, project_ID, Env_ID) are picked up and then they are inserted into ATT_table in place of assignedtoID, assignedbyID, envID, ProductID, project_ID.
Please note that assignedtoID, assignedbyID are referenced from Emp_ID in Employee_Table.
How to do this ? I have got something like this but its not working ::
INSERT INTO ATT_TABLE(Assigned_To_ID,Assigned_By_ID,Env_ID,Product_ID,Project_ID)
VALUES (A, B, Env_Table.Env_ID, Product_Table.Product_ID, Project_Table.Project_ID)
SELECT Employee_Table.Emp_ID AS A,Employee_Table.Emp_ID AS B, Env_Table.Env_ID, Project_Table.Project_ID, Product_Table.Product_ID
FROM Employee_Table, Env_Table, Product_Table, Project_Table
WHERE Employee_Table.F_Name= "Shantanu" or Employee_Table.F_Name= "Kapil" or Env_Table.Env_Name= "SAT11A" or Product_Table.Product_Name = "ABC" or Project_Table.Project_Name = "Project1";
The way this is handled is by using drop down select lists. The list consists of (at least) two columns: one holds the Id's teh database works with, the other(s) store the strings the user sees. Like
1, "CA", "Canada"
2, "USA", 'United States"
...
The user sees
CA | Canada
USA| United States
...
The value that gets stored in the database is 1, 2, ... whatever row the user selected.
You can never rely on the exact, correct input of users. Sooner or later they will make typo's.
I extend my answer, based on your remark.
The problem with the given solution (get the Id's from the parent tables by JOINing all those parent tables together by the entered text and combining those with a number of AND's) is that as soon as one given parameter has a typo, you will get not a single record back. Imagine the consequences when the real F_name of the employee is "Shant*anu*" and the user entered "Shant*aun*".
The best way to cope with this is to get those Id's one by one from the parent tables. Suppose some FK's have a NOT NULL constraint. You can check if the F_name is filled in and inform the user when he didn't fill that field. Suppose the user eneterd "Shant*aun*" as name, the program will not warn the user, as something is filled in. But that is not the check the database will do, because the NOT NULL constraints are defined on the Id's (FK). When you get the Id's one by one from the parent tables. You can verify if they are NOT NULL or not. When the text is filled in, like "Shant*aun*", but the returned Id is NULL, you can inform the user of a problem and let him correct his input: "No employee by the name 'Shantaun' could be found."
SELECT $Emp_ID_A = Emp_ID
FROM Employee_Table
WHERE F_Name= "Shantanu"
SELECT $Emp_ID_B = Emp_ID
FROM Employee_Table
WHERE B.F_Name= "Kapil"
SELECT $Env_ID = Env_ID
FROM Env_Table
WHERE Env_Table.Env_Name= "SAT11A"
SELECT $Product_ID = Product_ID
FROM Product_Table
WHERE Product_Table.Product_Name = "ABC"
SELECT $Project_ID = Project_ID
FROM Project_Table
WHERE Project_Name = "Project1"
Please use AND instead of OR.
INSERT INTO ATT_TABLE(Assigned_To_ID,Assigned_By_ID,Env_ID,Product_ID,Project_ID)
SELECT A.Emp_ID, B.Emp_ID, Env_Table.Env_ID, Project_Table.Project_ID, Product_Table.Product_ID
FROM Employee_Table A, Employee_Table B, Env_Table, Product_Table, Project_Table
WHERE A.F_Name= "Shantanu"
AND B.F_Name= "Kapil"
AND Env_Table.Env_Name= "SAT11A"
AND Product_Table.Product_Name = "ABC"
AND Project_Table.Project_Name = "Project1";
But it is best practice to use drop down list in your scenario, i guess.