Update column value when their other column values are same - sql

The Problem is, StudentId in row number 2 should be 1 because their Name and Father Name are the same. Similarly, StudentId in row number 4 should be 3 because Name and Father Name are the same
I have revised my query according to my requirement as I have to update my student_id when student_name, student dob, student father, email, countryId, and skype id will same now updated query will be
Merge into student_new_Backup
using ( select min(student_id) as stid, student_name, student_father,student_dob,email_id,skype_id,country
from student_new_Backup
group by student_name, student_father,student_dob,email_id,skype_id,country) a
on (student_new_Backup.student_name= a.student_name
and student_new_Backup.student_father=a.student_father
and student_new_Backup.student_dob=a.student_dob
unfortunately no student_id is update
and student_new_Backup.email_id=a.email_id
and student_new_Backup.skype_id=a.skype_id
and student_new_Backup.country=a.country)
when matched then
UPDATE SET student_new_Backup.student_id=a.stid
;
commit;
unfortunately, no student_id is an update

I think you want:
update t
set studentId = (select min(t2.studentId)
from t t2
where t2.name = t.name and t2.fathername = t.fathername
);
EDIT:
If you want NULL safe comparisons, then you need be be explicit:
update t
set studentId = (select min(t2.studentId)
from t t2
where (t2.name = t.name or t2.name is null and t.name is null) and
(t2.fathername = t.fathername or t2.fathername is null and t.fathername is null)
);

you can use merge for update
Merge into table_name
using ( select min(studentId) as stid, Name, fathername
from table_name
group by Name, fathername) a
on (table_name.Name= a.Name
and table_name.fatherName=a.fatherName)
when matched then
UPDATE SET table_name.studentId=a.stid
online demo

Related

Merge / Update query to update

I have two tables named CONTACT AND ROLES.
CONTACT TABLE LOOKS LIKE BELOW
CONTACT_ID
FIRST_NAME
LAST_NAME
PHONE
59285
AAA
BBB
99999
59281
AAA
BBB
99999
59288
ZZZ
YYY
11111
59282
ZZZ
YYY
11111
basically diff contact ids but same FIRST_NAME, LAST_NAME, PHONE
ROLES TABLE LOOKS LIKE
CONTACT_ID
59285
59281
59288
59282
I want to update the ROLES table, referencing the contact table to the minimum of the duplicate contact id so that the ROLES table looks like
CONTACT_ID
59281
59281
59282
59282
I am trying using merge
MERGE INTO ROLES T1 USING(
SELECT
MIN(CONTACT_ID) OVER (PARTITION BY FIRST_NAME, LAST_NAME, PHONE) AS min_contact_id
FROM CONTACT
) T2 ON (T1.ROWID = T2.ROWID) WHEN MATCHED THEN
UPDATE
SET T1.CONTACT_ID = T2.min_contact_id;
but it just gives output as 0 rows merged.
with cte as (
select distinct a.first_name,b.contact_id, a.min_id
from (
select first_name, min(contact_id) as min_id
from contact
group by contact_id) as a inner join contact b on a.first_name = b.first_name
)
update roles set roles.contact_id = cte.min_id
from cte inner join roles on roles.contact_id = cte.contact_id
You need to update your MERGE statement to a simple UPDATE statement -
UPDATE ROLES R
SET CONTACT_ID = (SELECT MIN_CONTACT_NO
FROM (SELECT CONTACT_ID, MIN(CONTACT_ID) OVER (PARTITION BY FIRST_NAME, LAST_NAME, PHONE) MIN_CONTACT_NO
FROM LOOKS) L
WHERE L.CONTACT_ID = R.CONTACT_ID);
As their ROWIDs never going to be same which was not correct in your query.
DB Fiddle.

delete duplicates and retain MAX(id) mysql

I have a code where it list all the duplicates of the data on database
SELECT MAX(id) id
FROM el_student_class_relation
GROUP BY student_id, class_id
HAVING COUNT(*) > 1
Now, I'm trying to retain the MAX(id), then the rest of the duplicates should be deleted
I tried the code
DELETE us
FROM el_student_class_relation us
INNER JOIN(SELECT MAX(id) id
FROM el_student_class_relation
GROUP BY student_id, class_id HAVING COUNT(*) > 1) t ON t.id = us.id
But it deletes the MAX(ID) and it is retaining the the other duplicates and it is the opposite of what I want.
Try this
DELETE FROM el_student_class_relation
WHERE id not in
(
SELECT * from
(SELECT MAX(id) id
FROM el_student_class_relation
GROUP BY student_id, class_id) temp_tbl
)
Please note:
do not use the HAVING COUNT(*) > 1 in inner query.
it will create issue when there is only single record with same id.
You might try the following query that deletes all elements for which another one with a higher ID (and same class and student) exists:
DELETE
FROM el_student_class_relation el1
WHERE EXISTS (SELECT el2.id
FROM el_student_class_relation el2
WHERE el1.student_id = el2.student_id
AND el1.class_id = el2.class_id
AND el2.id > el1.id);
The direct fix for your query is to use an "anti-join", where NOT joining is the important feature. This can be done with LEFT JOIN.
DELETE
us
FROM
el_student_class_relation us
LEFT JOIN
(
SELECT student_id, class_id, MAX(id) id
FROM el_student_class_relation
GROUP BY student_id, class_id
-- HAVING COUNT(*) > 1 [Don't do this, you need to return ALL the rows you want to keep]
)
gr
ON gr.id = us.id
WHERE
gr.id IS NULL -- WHERE there wasn't a match in the "good rows" table
EDIT MariaDB and MySQL aren't the same thing. MariaDB DOES allow self joins on the table being deleted from.
in mysql(lower version) in case of delete sub-query work a little bit different way, you have to use a layer more than required
DELETE FROM el_student_class_relation us
WHERE us.id not in
(
select * from (
SELECT MAX(id) id
FROM el_student_class_relation
GROUP BY student_id, class_id
) t1
)

SQL Select entries where none of the entities have a value in a particular column

I have a table of data which has students and their subject results in it. The students will appear multiple times, once for each subject they have a result for.
**tableID,studentID,lastName,firstName,subject,grade**
1,1a,Student1,Name1,English,A
2,1a,Student1,Name1,Maths,A
3,1a,Student1,Name1,Science,A
4,2a,Student2,Name2,English,A
5,2a,Student2,Name2,Maths,B
6,2a,Student2,Name2,Science,A
7,3a,Student3,Name3,English,A
8,3a,Student3,Name3,Maths,A
Using Microsoft Access SQL, how can I select only the students who have received an A for all of their subjects? E.g. In the above table, I only want to select all instances of Student1 and Student3, I don't want Student2 as they have not received all A's.
Get all students with grade A except students with any other grade
SELECT
studentID,lastName,firstName
FROM
(SELECT
studentID,lastName,firstName
FROM
result
WHERE
grade = 'A'
GROUP BY
studentID,lastName,firstName) GradeA
LEFT OUTER JOIN
(SELECT
studentID,lastName,firstName
FROM
result
WHERE
grade <> 'A'
GROUP BY
studentID,lastName,firstName) GradeOther
ON GradeA.studentId = GradeOther.StudentID AND GradeA.LAstName = GradeOther.LastName AND GradeA.FirstName = GradeOther.FirstName
WHERE
GradeOther.StudentID IS NULL
One way is using GROUP BY and HAVING:
select StudentId
from t
group by StudentId
having max(grade) = min(grade) and max(grade) = 'A';
I was able to get the results I want by using a sub-query:
SELECT studentID, lastName, firstName
FROM table
WHERE grade = "A"
AND studentID NOT IN (SELECT studentID FROM table WHERE grade <> "A" GROUP BY studentID)
GROUP BY studentID, lastName, firstName
This seems to exclude all students who received a result other than an A.

Help with query

I'm trying to make a query that looks at a single table to see if a student is in a team called CMHT and in a medic team - if they are I don't want to see the result.
I only want see the record if they're only in CMHT or medic, not both.
Would the right direction be using sub query to filter it out? I've done a search on NOT IN but how could you get to see check if its in more then 2 teams are not?
Student Team ref
1 CMHT 1
1 Medic 2
2 Medic 3 this would be in the result
3 CMHT 5 this would be in the result
So far I've done the following code would I need use a sub query or do a self join and filter it that way?
SELECT Table1.Student, Table1.Team, Table1.refnumber
FROM Table1
WHERE (((Table1.Team) In ('Medics','CMHT'))
This is Mark Byers's answer with a HAVING clause instead of a subquery:
SELECT Student, Team, ref
FROM Table1
GROUP BY Student
HAVING COUNT(Student) = 1
SELECT *
FROM students
WHERE NOT EXISTS
(
SELECT NULL
FROM students si
WHERE si.student = s.student
AND si.team = 'CMHT'
)
OR NOT EXISTS
(
SELECT NULL
FROM students si
WHERE si.student = s.student
AND si.team = 'Medic'
)
SELECT a.*
FROM Table1 a
INNER JOIN
( SELECT Student, COUNT(*) FROM Table1
GROUP BY Student
HAVING COUNT(*) = 1)b
ON (a.Student = b.Student)
how could you get to see check if its in 2 or more teams?
You can count the number of teams per student and then filter only those you want to see:
SELECT student FROM
(
SELECT student, COUNT(*) AS cnt
FROM Table1
GROUP BY student
) T1
WHERE cnt = 1
You can do it with outer join
select COALESCE(t1.Student, t2.Student) as Student,
COALESCE(t1.Team, t2.Team) as Team,
COALESCE(t1.ref, t2.ref) as ref
from
(select * from Student where Team = 'CMHT') t1
outer join
(select * from Student where Team = 'Medic') t2
on t1.Student = t2.Student
where
t1.Student is null or
t2.Student is null;

How to combine three SELECT statements with very tricky requirements

I have a SQL query with three SELECT statements. A picture of the data tables generated by these three select statements is located at www.britestudent.com/pub/1.png. Each of the three data tables have identical columns. I want to combine these three tables into one table such that:
(1) All rows in top table (Table1) are always included.
(2) Rows in the middle table (Table2) are included only when the values in column1 (UserName) and column4 (CourseName) do not match with any row from Table1. Both columns need to match for the row in Table2 to not be included.
(3) Rows in the bottom table (Table3) are included only when the value in column4 (CourseName) is not already in any row of the results from combining Table1 and Table2.
I have had success in implementing (1) and (2) with an SQL query like this:
SELECT DISTINCT
UserName AS UserName,
MAX(AmountUsed) AS AmountUsed,
MAX(AnsweredCorrectly) AS AnsweredCorrectly,
CourseName,
MAX(course_code) AS course_code,
MAX(NoOfQuestionsInCourse) AS NoOfQuestionsInCourse,
MAX(NoOfQuestionSetsInCourse) AS NoOfQuestionSetsInCourse
FROM
( "SELECT statement 1" UNION "SELECT statement 2" ) dt_derivedTable_1
GROUP BY CourseName, UserName
Where "SELECT statement 1" is the query that generates Table1 and "SELECT statement 2" is the query that generates Table2. A picture of the data table generated by this query is located at www.britestudent.com/pub/2.png. I can get away with using the MAX() function because values in the AmountUsed and AnsweredCorrectly columns in Table1 will always be larger than those in Table2 (and they are identical in the last three columns of both tables).
What I fail at is implementing (3). Any suggestions on how to do this will be appreciated. It is tricky because the UserName values in Table3 are null, and because the CourseName values in the combined Table1 and Table2 results are not unique (but they are unique in Table3).
After implementing (3), the final table should look like the table in picture 2.png with the addition of the last row from Table3 (the row with the CourseName value starting with "4. Klasse..."
I have tried to implement (3) using another derived table using SELECT, MAX() and UNION, but I could not get it to work. Below is my full SQL query with the lines from this failed attempt to implement (3) commented out.
Cheers,
Frederick
PS--I am new to this forum (and new to SQL as well), but I have had more of my previous problems answered by reading other people's posts on this forum than from reading any other forum or Web site. This forum is a great resources.
-- SELECT DISTINCT MAX(UserName), MAX(AmountUsed) AS AmountUsed, MAX(AnsweredCorrectly) AS AnsweredCorrectly, CourseName, MAX(course_code) AS course_code, MAX(NoOfQuestionsInCourse) AS NoOfQuestionsInCourse, MAX(NoOfQuestionSetsInCourse) AS NoOfQuestionSetsInCourse
-- FROM (
SELECT DISTINCT UserName AS UserName, MAX(AmountUsed) AS AmountUsed, MAX(AnsweredCorrectly) AS AnsweredCorrectly, CourseName, MAX(course_code) AS course_code, MAX(NoOfQuestionsInCourse) AS NoOfQuestionsInCourse, MAX(NoOfQuestionSetsInCourse) AS NoOfQuestionSetsInCourse
FROM (
-- Table 1 - All UserAccount/Course combinations that have had quizzez.
SELECT DISTINCT dbo.win_user.user_name AS UserName,
cast(dbo.GetAmountUsed(dbo.session_header.win_user_id, dbo.course.course_id, dbo.course.no_of_questionsets_in_course) as nvarchar(10)) AS AmountUsed,
Isnull(cast(dbo.GetAnswerCorrectly(dbo.session_header.win_user_id, dbo.course.course_id, dbo.question_set.no_of_questions) as nvarchar(10)),0) AS AnsweredCorrectly,
dbo.course.course_name AS CourseName,
dbo.course.course_code,
dbo.course.no_of_questions_in_course AS NoOfQuestionsInCourse,
dbo.course.no_of_questionsets_in_course AS NoOfQuestionSetsInCourse
FROM dbo.session_detail
INNER JOIN dbo.session_header ON dbo.session_detail.session_header_id = dbo.session_header.session_header_id
INNER JOIN dbo.win_user ON dbo.session_header.win_user_id = dbo.win_user.win_user_id
INNER JOIN dbo.win_user_course ON dbo.win_user_course.win_user_id = dbo.win_user.win_user_id
INNER JOIN dbo.question_set ON dbo.session_header.question_set_id = dbo.question_set.question_set_id
RIGHT OUTER JOIN dbo.course ON dbo.win_user_course.course_id = dbo.course.course_id
WHERE (dbo.session_detail.no_of_attempts = 1 OR dbo.session_detail.no_of_attempts IS NULL)
AND (dbo.session_detail.is_correct = 1 OR dbo.session_detail.is_correct IS NULL)
AND (dbo.win_user_course.is_active = 'True')
GROUP BY dbo.win_user.user_name, dbo.course.course_name, dbo.question_set.no_of_questions, dbo.course.no_of_questions_in_course,
dbo.course.no_of_questionsets_in_course, dbo.session_header.win_user_id, dbo.course.course_id, dbo.course.course_code
UNION ALL
-- Table 2 - All UserAccount/Course combinations that do or do not have quizzes but where the Course is selected for quizzes for that User Account.
SELECT dbo.win_user.user_name AS UserName,
-1 AS AmountUsed,
-1 AS AnsweredCorrectly,
dbo.course.course_name AS CourseName,
dbo.course.course_code,
dbo.course.no_of_questions_in_course AS NoOfQuestionsInCourse,
dbo.course.no_of_questionsets_in_course AS NoOfQuestionSetsInCourse
FROM dbo.win_user_course
INNER JOIN dbo.win_user ON dbo.win_user_course.win_user_id = dbo.win_user.win_user_id
RIGHT OUTER JOIN dbo.course ON dbo.win_user_course.course_id = dbo.course.course_id
WHERE (dbo.win_user_course.is_active = 'True')
GROUP BY dbo.win_user.user_name, dbo.course.course_name, dbo.course.no_of_questions_in_course,
dbo.course.no_of_questionsets_in_course, dbo.course.course_id, dbo.course.course_code
) dt_derivedTable_1
GROUP BY CourseName, UserName
-- UNION ALL
-- Table 3 - All Courses.
-- SELECT DISTINCT null AS UserName,
-- -2 AS AmountUsed,
-- -2 AS AnsweredCorrectly,
-- dbo.course.course_name AS CourseName,
-- dbo.course.course_code,
-- dbo.course.no_of_questions_in_course AS NoOfQuestionsInCourse,
-- dbo.course.no_of_questionsets_in_course AS NoOfQuestionSetsInCourse
-- FROM dbo.course
-- WHERE is_active = 'True'
-- ) dt_derivedTable_2
-- GROUP BY CourseName
-- ORDER BY CourseName
With such filtering requirements (depending on the rows of prior queries), I recommend a table variable.
DECLARE #MyTable TABLE
(
ID int PRIMARY KEY,
Name varchar(50),
QueryNumber int
)
INSERT INTO #MyTable (ID, Name, QueryNumber)
SELECT CustomerID, CustomerName, 1
FROM Customer
WHERE Name = "Bob"
INSERT INTO #MyTable (ID, Name, QueryNumber)
SELECT CustomerID, CustomerName, 2
FROM Customer
WHERE Name = "Joe" and CustomerID not in (SELECT ID FROM #MyTable)
INSERT INTO #MyTable (ID, Name, QueryNumber)
SELECT CustomerID, CustomerName, 3
FROM Customer
WHERE CustomerID not in (SELECT ID FROM #MyTable)
SELECT *
FROM #MyTable
Here is an Oracle flavored solution:
Select
*
from table1
UNION
select
*
from table2
where not exists(
select 'x'
from table1
where
table2.username = table1.username
and table2.coursename = table1.coursename
)
UNION
select
*
from table3
where
coursename not in (
Select
coursename
from table1
UNION /* the union operator implies distinct, so
there will be no duplicates */
select
coursename
from table2
where not exists(
select 'x'
from table1
where
table2.username = table1.username
and table2.coursename = table1.coursename
)
)