Query on at least and not present in SQL table - sql-server

I have two queries:
Query the id number of the students who at least enrolled subj1 and subj2 courses (I do not know how to code for at least)
Query the id number, name, and age of the students who did not enroll subj2 course.
I coded something as below - which returns an empty table even though I should get some values.
Select sno, sname, age
from student
where not exists (select cno from course where cno ='C2');

I'm assuming you have a table connecting students with courses in a many-to-many, so that each student can enroll in more than one course and each course can contain multiple students.
So for the sake of this example, let's call it StudentsToCourses.
This table should contain the student id and the course id, and it's primary key should contain the combination of both it's columns.
So the first query would be something like (to get student numbers enrolled into at least one of the two courses):
SELECT sno
FROM StudentToCourses
WHERE cno IN ('C1', 'C2')
or this (to get students enrolled into both courses):
SELECT sno
FROM StudentToCourses
WHERE cno IN ('C1', 'C2')
GROUP BY sno
HAVING COUNT(DISTINCT cno) = 2
Note that the subquery in the EXISTS operator is correlated to the main query using the student number.
The second query is almost the same as the first one, except instead of IN you use =, and instead of EXISTS you use NOT EXISTS.
Since this seems like a homework question, I'll leave it up to you to write the code, otherwise you will not learn anything from this.

Related

Why doesn't this "not in" clause do what I expect?

I'm writing what I think should be a simple query using the "not in" operator, and it's not doing what I expect.
Background:
I have two tables, Contact and Company.
Contact includes columns ContactID (person's identity) and CompanyID (which company they work for)
CompanyID values are expected to be equivalent to the CompanyIDs in the Company table
I want to write a query that checks how many people from the Contact table that have an "invalid" CompanyID (i.e., listed as working for a Company that isn't in the Company table)
I have a working query that does this:
select
count(ContactID)
from
Contact left join Company on Contact.CompanyID = Company.CompanyID
where
Company.CompanyID is null;
This query returns the value 2725538, which I believe to be the correct answer (I've done some simple "show me the top 10 rows" debugging, and it appears to be counting the right rows).
I wrote a second query which I expected to return the same result:
select
count(ContactID)
from
Contact
where
CompanyID not in
(select
CompanyID
from
Company)
However, this query instead returns 0.
To help me debug this, I checked two additional queries.
First, I tried commenting out the WHERE clause, which should give me all of the ContactIDs, regardless of whether they work for an invalid company:
select
count(ContactID)
from
Contact
This query returns 29722995.
Second, I tried removing the NOT from my query, which should give me the inverse of what I'm looking for (i.e., it should count the Contacts who work for valid companies):
select
count(ContactID)
from
Contact
where
CompanyID in
(select
CompanyID
from
Company)
This query returns 26997457.
Notably, these two numbers differ by exactly 2725538, the number returned by the first, working query. This is what I would expect if my second query was working. The total number of Contacts, minus the number of Contacts whose CompanyIDs are in the Company table, should equal the number of Contacts whose CompanyIDs are not in the Company table, shouldn't it?
So, why is the "not in" version of the query returning 0 instead of the correct answer?
the only issue could be of NULL CompanyID. Not In doesn't work with NULLs because of non-comparability of NULL.
try the following:
select
count(ContactID)
from
Contact
where
CompanyID not in
(select
ISNULL(CompanyID,'')
from
Company)
you can see the example in db<>fiddle here.
Please find more details HERE.

SQL server INSERT Using WITH

I have two tables
student and course_log
I have Students already in students table, I need to insert into course_log for each student a standard course (UNI 101) that all have to take or have take.
So if there are 10 students there will be 10 entries in the course_log table for each student with course UNI 101
I was thinking of using a with clause but it does not work that way i think
USE [university]
GO
with studentid as ( select id as stdID from student)
INSERT INTO [dbo].[course_log]
([course_name]
,[course_code]
,[STUDENT_ID])
VALUES
('STANDARD COURSE FOR ALL STUDENTS'
,'UNI 101'
,studentid.stdID)
The other one that was coming to my mind was to use a while loop ( as MSSQL does not have for loop) but i was actually thinking if the above would be much easier and doable.
No need of WITH clause
INSERT INTO [dbo].[course_log]
([course_name]
,[course_code]
,[STUDENT_ID])
SELECT
'STANDARD COURSE FOR ALL STUDENTS'
,'UNI 101'
,stdID
FROM student

SQL - Insert multiple records from select

I have been searching all day but could not find answer to this:
I have a table on SQL Server:
dbo.Program
with fields:
Program.id...PK autoincrement
Program.user...varchar
Program.program...varchar
Program.installed...boolean
Program.department...varchar
Program.wheninstalled...date
Now, I want to insert a new record for every distinct user and copy the department from his latest(Program.wheninstalled) record with other values the same for every user:
Program.user...every unique user
Program.program...MyMostAwesomeProgram
Program.installed...false
Program.department...department of the record with the latest program.wheninstalled field of all the records of the unique user in program.user
Program.wheninstalled...null
I know how to do it in an ugly way:
select the latest records for every user and their department in that record
extract values from 1) and make it into insert into
(field1, field2...fieldX) values
(1records_value1, 1records_value2...1records_valueX),
(2records_value1, 2records_value2...2records_valueX),
...
(Nrecords_value1, Nrecords_value2...Nrecords_valueX)
but I would like to know how to do it in a better way. Oh I cannot use some proper HR databse to make my life easier so this is what I got to work with now.
I'm a postgres guy, but something akin to the below should work:
insert into Program (user, program, installed, department, wheninstalled)
select user,
'MyMostAwesomeProgram',
false,
(select department from someTable where u.user = ...),
null
from users as u;
from https://stackoverflow.com/a/23905173/3430807
you said you know how to do the select
insert into Program (user, program, installed, department, wheninstalled)
select user, 'MyMostAwesomeProgram', 'false' , department, null
from ...
This should do it:
insert into Program (user, program, installed, department, whenInstalled)
select user, program, installed, department, whenInstalled
from
(
select User
, 'MyMostAwesomeProgram' program
, 0 installed
, department
, null whenInstalled
, row_number() over (partition by user order by whenInstalled desc, id desc) r
from Program
) p
where p.r = 1
The interesting bit is the row_number() over (partition by user order by whenInstalled desc, id desc) r.
This says to return a column, r, which holds values 1..n for each user, counting up according to the order by clause (i.e. starting with the most recent whenInstalled and working backwards).
I also included the id field in the order by clause in case there were two installs for the same user on the same date; in such a case the most recently added (the one with the higher id is used first).
We then put this in a subquery, and select only the first record; thus we have 1 record per user, and it's the most recent.
The only values we use from this record are the user and department fields; all else is defined per your defaults.
So I am gonna answer this for some other people who might google this:
To get a records from a table to another table you need to use Select into statement
I like using With XXX as ( some select) to specify, say, "virtual" table with which you can work during the query
As JohnLBevan meantioned a very useful function Row_number, over, partition by and what i missed is a rank
So once you read on these you should be able to understand how to do what I wanted to do.

SQL SERVER - Retrieve Last Entered Data

I've searched for long time for getting last entered data in a table. But I got same answer.
SELECT TOP 1 CustomerName FROM Customers
ORDER BY CustomerID DESC;
My scenario is, how to get last data if that Customers table is having CustomerName column only? No other columns such as ID or createdDate I entered four names in following order.
James
Arun
Suresh
Bryen
Now I want to select last entered CustomerName, i.e., Bryen. How can I get it..?
If the table is not properly designed (IDENTITY, TIMESTAMP, identifier generated using SEQUENCE etc.), INSERT order is not kept by SQL Server. So, "last" record is meaningless without some criteria to use for ordering.
One possible workaround is if, by chance, records in this table are linked to some other table records (FKs, 1:1 or 1:n connection) and that table has a timestamp or something similar and you can deduct insertion order.
More details about "ordering without criteria" can be found here and here.
; with cte_new as (
select *,row_number() over(order by(select 1000)) as new from tablename
)
select * from cte_new where new=4

break normalization rules , creat table /view from muliple tables

I have a question and am not sure if this is the correct forum to post it .
I have two tables, StudentTable and CourseTable, where each student takes more than one course.
Example: Student1 takes 2 courses: (C1, C2).
Student2 takes 3 courses (C1, C2, C3).
I need to create a table/view that contains student information from StudentTable, plus all the courses and the score for each course from CourseTable - in one row.
Example:
Row1= Student1_Id, C1_code, C1_name, C1_Score, C2_code, C2_name, C2_Score
Row2=
Student2_Id, C1_code, C1_name, C1_Score, C2_code, C2_name, C2_Score, C3_code, C3_name, C3_Score
Since Student1 has just two courses, I should enter NULL in 'Course 3 fields'
My struggle is in the insert statement. I tried the following but it showed an error.
Insert Into Newtable
( St_ID, C1_code,c1_name, C1_Score ,C2_code ,C2_name,C2_score,C3_code ,C3_name,C3_score)
Select
(Select St_ID from StudentTable)
,
(Select C_code,c_name,c_Score
from Coursetable,SudentTable
where course.Stid =Studet.stid)
,
(Select C_code,c_name,c_Score
from course ,student
where course.Stid =Studet.stid ),
(Select C_code,c_name,c_Score
from course ,student
where course.Stid =Studet.stid );
I'm fully aware that the New table/View will break the rules of normalization, but I need it for a specific purpose.
I tried also the PIVOT BY functionality but no luck with it.
FYI, I'm not expert in SQL syntax. I just know the basics.
I will be great full for any helpful suggestions to try.
I added My DB structure so you can have better Idea
First Table is Member table which Represent Students Information .The fields in this table are
member_sk (PrimaryKey), full_or_part_time, gender, age_at_entry, age_band_at_entry, disability, ethnicity,
widening_participation_level, nationality
Second Table is Modules table which include the Courses' scores that Student took .
The fields in this table are
Module_result_k(Primary Key), member_sk(Foreign key to connect to Member table), member_stage_sk ,module_k(Foreign key to connect to Module table), module_confirmed_grade_src, credit_or_result
Third Table is AllModuleInfo which is include general information for each course .The fields in this table are
Module_k (Primary key), module_name ,module_code, Module_credit, Module stage.
The New table that I will create has the following fields
member_sk (PrimaryKey), full_or_part_time, gender, age_at_entry, age_band_at_entry, disability, ethnicity,
widening_participation_level, nationality " This will be retrieved from Member table"
Also will include
Module 1_name ,module1_code, Module1_credit, Module1_ stage, member1_stage_sk , module1_confirmed_grade_src, credit1_or_result
Module 2_name ,module2_code, Module2_credit, Module2_ stage, member2_stage_sk , module2_confirmed_grade_src, credit2_or_result
-
-
-
I will repeat this fields 14 times which is equal to Maximum courses number that any of the students took.
//// I hope now my questions become more clear

Resources