How to design/create rules table with criteria in SQL Server 2008 - sql

I don't have much experience with SQL Server and I'm pretty much lost when it comes to anything more advanced than simple INSERT/SELECT statements.
My task is to create table which hold 'criteria' (rules) for other tables in same DB. I mean we have an Employee table, a Salary table etc. I need to make some rules between Employee table and Salary table by its values, i.e. if Employee = John and Salary = 2000 then make 1 criteria, if Employee = Steve and Salary = 3000 then make 2 criteria.
I have created a table called Rules:
RuleID Criteria
--------------------------------------------------
1 Employee = John and Salary = 2000
2 Employee = Steve and Salary = 3000**
My question: As mentioned above is correct way to create 'criteria' table? (maybe I have 50 different conditions...Would it be correct way If I create table with all conditioned as mentioned above?) Please advise.
I am sorry If I am not able to explain it in correct way or asking basic question.
I would appreciate any help in this. Thanks a lot in advance..

We have created an effective Rules Engine that notifies the appropriate user(s) for a given rule. Our columns are as follows: RuleID, RuleName, SequenceNum, IsActiveFlag, RuleRunDays, DataSteward, CarbonCopyRecipients, NotificationLevel, RuleSQL, NotificationSubject, NotificationText, HTMLFlag
The key is to have a column that is a valid executable SQL statement (as RuleSQL above). Here is an example of a value you might put in the RuleSQL column:
SELECT ErrorMessage = 'Salary cannot be null for Active employees.'
, e.EmployeeName , es.Salary , ...
FROM EmployeeSalary es
JOIN Employee e
ON e.EmployeeId = es.EmployeeId
WHERE es.Salary IS NULL AND e.Status = 'Active'

Related

Understanding NOT EXISTS in SQL

I am a beginner in SQL. I am now studying EXISTS and NOT EXISTS.
Question:
Retrieve the names of each employee who works on ALL projects
controlled by department 5.
Answer:
select fname, lname
from employee
where not exists ( (select pnumber from project where dnum = 5)
MINUS
(select pno from works_on where essn = ssn)
);
The first select in subquery gives (1,2,3) and the second select gives me (1,2,3,10,20,30). So (1,2,3) - (1,2,3,10,20,30) = 0. How does this solve the query? I am not sure if my logic is correct or the way I approach the problem.
Can someone please help me understand the solution step by step and visually if possible? thanks
Link to the course
So, the original problem was to:
Retrieve the names of each employee who works on ALL the projects controlled by department 5.
The provided answer makes use of the equivalence of:
All x such that f(x)
No x such that not f(x)
To put that in English, the problem is equivalent to finding those employees for whom there is no project controlled by department 5 that the employee doesn't work on.
So, first find all the projects controlled by department 5, then remove from that any project that the employee works on. That's exactly what the provided answer is doing. If there is nothing left, then there is no project controlled by department 5 that the employee doesn't work on. So by the equivalance, the employee works on all the projects controlled by that department.
While this is technically correct, it can feel a little odd. Especially if it were the case that department 5 controls zero projects. If that were true, the query would return all the employees ... which might not be quite what was expected.
Firstly, MINUS is an Oracle term. SQL-Server uses EXCEPT. Please read https://blog.sqlauthority.com/2008/08/07/sql-server-except-clause-in-sql-server-is-similar-to-minus-clause-in-oracle/ for more information.
Secondly, EXISTS returns either a TRUE or a FALSE result based on whether or not the parameter statement returns any records. For example, EXISTS ( SELECT * FROM Employee WHERE Fname = 'John' ) will return TRUE whereas EXISTS ( SELECT * FROM Employee WHERE Fname = 'Slartibartfast' ) will return FALSE.
https://www.w3schools.com/sql/sql_exists.asp gives a good explanation of EXISTS (with examples).
The EXISTS subquery does not need to refer to the main statement - it just needs to return at least one record in the same circumstances as when you want EXISTS to return TRUE. For instance...
SELECT *
FROM Employee
WHERE Dno = 5
AND EXISTS ( SELECT Sex
FROM employee
WHERE Sex = 'M'
AND Dno = 5 )
This query will return all records from Employee (irrespective of their Sex) for Dno 5 if that Department has at least one person with Sex = 'M'.
As for NOT EXISTS...
SELECT *
FROM Employee
WHERE Dno = 5
AND NOT EXISTS ( SELECT Sex
FROM employee
WHERE Sex = 'M'
AND Dno = 5 )
This query will return all records from Employee (irrespective of their Sex) for Dno 5 if that Department has no person with Sex = 'M'.
If you have any questions or comments, then please feel free to post a Comment accordingly.

Excessive Case Statement Help - SQL Server

I'm supposed to answer this for class, and it's tricky (for me)
Write a SELECT query to output the name of all employees with the name of their supervisor. If the employee has no supervisor, the supervisor name column should contain the text 'No Supervisor'.
The primary key field in my db is the employeeid and they are provided with names, and each student also has a supervisorid
The table for this is shown below (sorry for the layout):
employeeid lastname firstname salary supervisorid
1 Stolz Ted 25000 NULL
2 Boswell Nancy 23000 1
3 Hargett Vincent 22000 1
4 Weekley Kevin 22000 3
5 Metts Geraldine 22000 2
6 McBride Jeffrey 21000 2
7 Xiong Jay 20000 3
I was wondering how I could go about this statement without using the case statement to apply each of the 7 students with:
when concat(firstname,' ',lastname)='Nancy Boswell' then 'Ted Stolz'
In larger tables this would simply be a HUGE statement, is there a better way to do it?
Thanks!
EDIT:
I've now tried this:
SELECT
EMP1.employeeid as 'employee',
EMP2.supervisorid as 'manager'
FROM
employee EMP1
LEFT OUTER JOIN
employee EMP2
ON
emp1.employeeid = emp2.supervisorid;
However, I am seeing duplicate fields, for some reason employee 2 and 3 are appearing twice, meaning there are 9 fields showing instead of 7.
Also, I need to display their names, not their id's does that mean I need to join the join that i've already done to the employee name ? How would I do this?
Thanks for the feedback guys!
You need to link the table with itself based on the supervisorId. This might be strange if you are new to SQL but it is very common to do. You tell with SQL to add the row of the supervisor to the row of the employee via its primary key.
SELECT
*
FROM
EMPLOYEES EMP1
LEFT OUTER JOIN
EMPLOYEES EMP2
ON
-- make link between tables here
Note that the above query is not 100% correct / complete, its an indication. The LEFT OUTER JOIN statement makes the employees without supervisor have null values for the supervisor, otherwise the whole record would be left out.

Replace values in column with Oracle

How can I change all the values of a single column for other ones in one single order?
For example, I want to change old values of the last column salary (2250,1,3500,1) for new ones (2352,7512,4253,1142). I have this database:
I know how to do it but changing step by step, and it is not efficient if I have a lot of rows. This way:
UPDATE TABLE tablename
SET salary = REPLACE(tablename.salary, 2250, 2352);
and then perform that operation multiple times.
UPDATE TABLE tablename
SET salary = 2250
WHERE salary = 2352
I'm not sure what you're aiming for with the REPLACE() function but if you want to change the values then you need to do it like the above code. Set the salary to what you want WHERE it has a salary of 2250.
You can write it a few times with the different criteria and then run it.
EDIT: Since you're worried about doing this numerous times you can create a table called salaries:
CREATE TABLE t_salary AS
SELECT salary from tablename;
ALTER t_salary add newsalary integer after salary;
In the 'newsalary' column you can add what the new salary should be then do an inner join. I just created a table for this purpose called stackoverflow (which would be your 'tablename'
update stackoverflow s
inner join t_salary ns on s.salary = ns.salary
set s.salary = ns.newsalary;
Now what this will do is join tablename to t_salary where the current salary = the salary in t_salary. Then you set the tablename.salary equal to the new salary, this worked for me I hope it works for you.
Note, the syntax may be slightly different since I don't have Oracle installed on my home machine, I used MySQL.
Since you already a list old salary values and their corresponding new salary values you can place them in a flat file and create an external table in oracle to point to this file.
Once that is done then you can just fire a simple update statement similar to the one given below:
update test1 set salary = ( select newsalary from test2 where test1.empid = test2.empid);

How do I make a query for if value exists in row add a value to another field?

I have a database on access and I want to add a value to a column at the end of each row based on which hospital they are in. This is a separate value. For example - the hospital called "St. James Hospital" has the id of "3" in a separate field. How do I do this using a query rather than manually going through a whole database?
example here
Not the best solution, but you can do something like this:
create table new_table as
select id, case when hospital="St. James Hospital" then 3 else null
from old_table
Or, the better option would be to create a table with the columns hospital_name and hospital_id. You can then create a foreign key relationship that will create the mapping for you, and enforce data integrity. A join across the two tables will produce what you want.
Read about this here:
http://net.tutsplus.com/tutorials/databases/sql-for-beginners-part-3-database-relationships/
The answer to your question is a JOIN+UPDATE. I am fairly sure if you looked up you would find the below link.
Access DB update one table with value from another
You could do this:
update yourTable
set yourFinalColumnWhateverItsNameIs = {your desired value}
where someColumn = 3
Every row in the table that has a 3 in the someColumn column will then have that final column set to your desired value.
If this isn't what you want, please make your question clearer. Are you trying to put the name of the hospital into this table? If so, that is not a good idea and there are better ways to accomplish that.
Furthermore, if every row with a certain value (3) gets this value, you could simply add it to the other (i.e. Hospitals) table. No need to repeat it everywhere in the table that points back to the Hospitals table.
P.S. Here's an example of what I meant:
Let's say you have two tables
HOSPITALS
id
name
city
state
BIRTHS
id
hospitalid
babysname
gender
mothersname
fathername
You could get a baby's city of birth without having to include the City column in the Births table, simply by joining the tables on hospitals.id = births.hospitalid.
After examining your ACCDB file, I suggest you consider setting up the tables differently.
Table Health_Professionals:
ID First Name Second Name Position hospital_id
1 John Doe PI 2
2 Joe Smith Co-PI 1
3 Sarah Johnson Nurse 3
Table Hospitals:
hospital_id Hospital
1 Beaumont
2 St James
3 Letterkenny Hosptial
A key point is to avoid storing both the hospital ID and name in the Health_Professionals table. Store only the ID. When you need to see the name, use the hospital ID to join with the Hospitals table and get the name from there.
A useful side effect of this design is that if anyone ever misspells a hospital name, eg "Hosptial", you need correct that error in only one place. Same holds true whenever a hospital is intentionally renamed.
Based on those tables, the query below returns this result set.
ID Second Name First Name Position hospital_id Hospital
1 Doe John PI 2 St James
3 Johnson Sarah Nurse 3 Letterkenny Hosptial
2 Smith Joe Co-PI 1 Beaumont
SELECT
hp.ID,
hp.[Second Name],
hp.[First Name],
hp.Position,
hp.hospital_id,
h.Hospital
FROM
Health_Professionals AS hp
INNER JOIN Hospitals AS h
ON hp.hospital_id = h.hospital_id
ORDER BY
hp.[Second Name],
hp.[First Name];

UPDATE query that fixes orphaned records

I have an Access database that has two tables that are related by PK/FK. Unfortunately, the database tables have allowed for duplicate/redundant records and has made the database a bit screwy. I am trying to figure out a SQL statement that will fix the problem.
To better explain the problem and goal, I have created example tables to use as reference:
alt text http://img38.imageshack.us/img38/9243/514201074110am.png
You'll notice there are two tables, a Student table and a TestScore table where StudentID is the PK/FK.
The Student table contains duplicate records for students John, Sally, Tommy, and Suzy. In other words the John's with StudentID's 1 and 5 are the same person, Sally 2 and 6 are the same person, and so on.
The TestScore table relates test scores with a student.
Ignoring how/why the Student table allowed duplicates, etc - The goal I'm trying to accomplish is to update the TestScore table so that it replaces the StudentID's that have been disabled with the corresponding enabled StudentID. So, all StudentID's = 1 (John) will be updated to 5; all StudentID's = 2 (Sally) will be updated to 6, and so on. Here's the resultant TestScore table that I'm shooting for (Notice there is no longer any reference to the disabled StudentID's 1-4):
alt text http://img163.imageshack.us/img163/1954/514201091121am.png
Can you think of a query (compatible with MS Access's JET Engine) that can accomplish this goal? Or, maybe, you can offer some tips/perspectives that will point me in the right direction.
Thanks.
The only way to do this is through a series of queries and temporary tables.
First, I would create the following Make Table query that you would use to create a mapping of the bad StudentID to correct StudentID.
Select S1.StudentId As NewStudentId, S2.StudentId As OldStudentId
Into zzStudentMap
From Student As S1
Inner Join Student As S2
On S2.Name = S1.Name
Where S1.Disabled = False
And S2.StudentId <> S1.StudentId
And S2.Disabled = True
Next, you would use that temporary table to update the TestScore table with the correct StudentID.
Update TestScore
Inner Join zzStudentMap
On zzStudentMap.OldStudentId = TestScore.StudentId
Set StudentId = zzStudentMap.NewStudentId
The most common technique to identify duplicates in a table is to group by the fields that represent duplicate records:
ID FIRST_NAME LAST_NAME
1 Brian Smith
3 George Smith
25 Brian Smith
In this case we want to remove one of the Brian Smith Records, or in your case, update the ID field so they both have the value of 25 or 1 (completely arbitrary which one to use).
SELECT min(id)
FROM example
GROUP BY first_name, last_name
Using min on ID will return:
ID FIRST_NAME LAST_NAME
1 Brian Smith
3 George Smith
If you use max you would get
ID FIRST_NAME LAST_NAME
25 Brian Smith
3 George Smith
I usually use this technique to delete the duplicates, not update them:
DELETE FROM example
WHERE ID NOT IN (SELECT MAX (ID)
FROM example
GROUP BY first_name, last_name)