SQL fundamentals practise select statement - sql

I am preparing for the Oracle SQL Fundamentals I exam and am having trouble with this question:
Examine the structure of the EMP table:
Name Null? Type
EMPNO NOT NULL NUMBER(3)
ENAME VARCHAR2(25)
SALARY NUMBER(10,2)
COMM_PCT NUMBER(4,2)
I want to generate a report that fulfills the following requirements:
1. Displays employees' names and commission amounts
2. Excludes employees who do not have a commission
3. Displays a zero for employees whose SALARY does not have a value
You issue the following SQL statement:
SQL>SELECT ename, NVL(salary * comm_pct, 0)
FROM emp
WHERE comm_pct <> NULL;
What is the outcome?
ANSWER is It executes successfully but displays no result.
Why does nothing display though?
Also if you guys have any resources for good SQL fundamentals practise questions please let me know.

Be careful with nulls and comparisons. If you want rows where there is some data, you would have "WHERE comm_pct IS NOT NULL". Using the comparison operator <> with NULL will return nothing.
select * from dual where dummy <> NULL
is not the same as
select * from dual where dummy is not null;
The other stuff in the question is just a distraction from this point. You can't compare a NULL to something else (null really means "I don't know what the heck the value is").
Same thing with = comparison. You don't say "WHERE comm_pct = NULL", you say "WHERE comm_pct IS NULL".
As a reference, here's the online SQL Reference Guide. Here is the link that refers to NULLs and comparisons.

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.

SQL, Displaying string instead of NULL/actual value

I'm working on an assignment and am having trouble with this question:
*Display the department name and the name of all employees plus their manager status. Status should show message ‘is a Manager’ for those who are managers. For those who are not managers show the message ‘is NOT a Manager’.
Include also empty departments as well, where the status value should be ‘NO Manager yet’
Display those people who are managers first followed by those whoa are NOT managers and empty departments last. Within those groupings sort by the employee name alphabetically.
Here is the heading sample.
Department Name Employee Manager Status*
I know NVL can be used to account for null values, but this question's stumped me.
The tables relevant to this question are:
emp:
Name Null Type
-------- -------- ------------
EMPNO NOT NULL NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NOT NULL NUMBER(2)
dept:
desc dept
Name Null Type
------ -------- ------------
DEPTNO NOT NULL NUMBER(2)
DNAME VARCHAR2(14)
LOC VARCHAR2(13)
If anyone could give me even a hint as to which function I could possibly use to display the strings, instead of the values I would be very greatful!
Depending of which database you use there is several ways to view strings instead of NULL results.
For your DB try look at NVL, NULLIF, NVL2, COALESCE, CASE-WHEN clauses (Oracle) or IIF function (Firebird/Interbase). I don't know which DB you use but most of these are common for most popular DBs.
Here is your hint: Use a CASE expression to assign values to your "Manager Status" column, something like:
CASE WHEN condition
THEN 'is a Manager'
ELSE 'is NOT a Manager'
END as Manager_Status
"condition" will be some value that, if "true" identifies a manager.

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

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'

Add a tuple-based check to this relation

In relation Person (SSN, State, Name), add a tuple-based check: if a
person’s State is NY, then the first three digits of his SSN has to be
between ‘050’ and ‘134’. (Hint: use LEFT function in SQL).
CREATE TABLE Person (
SSN INT PRIMARY KEY,
State CHAR(50),
Name CHAR(100),
CHECK (
SELECT LEFT (SSN, 3) AS FirstThreeDigits, SSN FROM Person,
WHERE Person.State == ‘NY’) between '050' and between '134'
);
I am not comfortable with the CHECK condition here. I am not sure if this is the right way doing conditional check. Can someone please verify this? If not, how do we do a conditional check?
We need this:
if state == 'NY', perform CHECK
Do we need a trigger? I was thinking that if a new insert / update occurs, check the value. But the question doesn't ask that.
Ok so its generic but DDL typically isn't but lets use the doc on SQL Server CHECK Constraints as a guide anyway
You can create a CHECK constraint with any logical (Boolean)
expression that returns TRUE or FALSE based on the logical operators.
For the previous example, the logical expression is:
salary >= 15000 AND salary <= 100000.
Note that the above example from the docs is not a SELECT statement but and expression. This means all you need to do is come up with a expression that returns TRUE
when all of the following are true
State is NY
The Left three digits of the SSN is => ‘050’
The Left three digits of the SSN is <= 134.
Or
Sate is not NY
Remembering that you can Group a set of logical expressions in a Parens
e.g.
(Group of logical expressions) OR (Group of logical expressions)
It shouldn't be too hard

SQL Query giving error

What is wrong with this query :
SELECT count() as total_students
FROM student_information;
SELECT
(
SELECT student_project_marks
from students_project
WHERE student_project_id=student_information.student_project_id
)
+ student_assignment_marks
+ student_exam_marks AS total_marks
FROM student_information
ORDER BY total_marks DESC;
UPDATE student_information
SET (
SELECT student_grade
FROM student_information
LIMIT 0.1*total_students
ORDER BY total_marks DESC
)="A";
Iam trying to select 0.1*total_students number of students ordered by their total marks obtained and update their grades.... Top 10% will be awarded as A.
I am getting error :
syntax error near '('
I have 2 tables :
created them via following query:
create table if not exists student_information (
student_name varchar(80),
student_roll_num int primary key,
student_email varchar(64),
student_assignment_marks int(2) check(student_assignment_marks<=30),
student_exam_marks int(2) check(student_exam_marks<=50),
student_project_id varchar(25),
student_grade varchar(2)
)
create table if not exist students_project (
student_project_id varchar(25),
student_project_title varchar(25),
student_project_marks int(2) check(student_project_marks>=0 and student_project_marks<=20)
)
Marks in the project is accessed from the student_project table via the student_project_id.
Now how do I award the grade based on the total marks...
Top 10% have to be awarded A, next 10% B and so on...
I know how to calculate total marks...
I have writen a query like this:
select student_roll_num,
(SELECT student_project_marks
from students_project
WHERE student_project_id=student_information.student_project_id )+
student_assignment_marks+student_exam_marks as total_marks from student_information;
It works.
This is not even approximately correct SQL. Also, it's not clear how you're executing these statements (from a console, from a program, etc).
A few comments to help get you on your way:
SQL does not "remember" the results of previous statements from one statement to the next. Therefore, your calculation of total_students in the first SQL statement has no connection with your attempt to actually use that value in your third statement. Similarly, your attempt to derive total_marks in the second query is not available in your third query.
Your second statement only makes sense if the internal query is guaranteed to produce only a single record for each row in student_information. I'm reasonable certain that what you're attempting to do would be better done using a JOIN rather than a sub-query.
The third query (UPDATE) is the one that's furthest away from SQL. UPDATE operates on one or more columns in a table. Each column is assigned a new value. The columns it operates on must be literally named with the correct identifiers. You can use a sub-query on the right side of the equals sign, but not on the left (although you don't have any reason to use one here). The conditions for the set of rows on which to operate belong in a WHERE clause at the end of the UPDATE statement, not within any kind of sub-query.
Guessing at your intent, I think you probably need to SUM or AVG the grades from student_projects (assuming each student has several projects to consider), and there's no aggregation in any of your queries.