Additional inner join modifying results of previous calculations - sql

I am having issues with using the count() function in an sql plus query.. say if
SELECT B.ID COUNT(S.BRANCH_ID) FROM BRANCH B
INNER JOIN STAFF S ON S.BRANCH_ID = B.ID
GROUP BY B.ID;
from doing this I'll get the results
b.id count
1 6
2 6
3 6
4 7
5 6
which is fine.. However if I even add an extra inner join i'll get completely different and wrong results.. So if I put for example..
SELECT COUNT(S.BRANCH_ID) FROM BRANCH B
INNER JOIN STAFF S ON S.BRANCH_ID = B.ID
INNER JOIN TOOL_STOCK TS ON TS.BRANCH_ID = B.ID
GROUP BY B.ID;
Now the results I get will be...
b.id count
1 96
2 96
3 96
4 112
5 96
Why is this and how do I stop it? Cheers!

Try
SELECT B.ID, COUNT(DISTINCT S.STAFF_ID) FROM BRANCH B
INNER JOIN STAFF S ON S.BRANCH_ID = B.ID
INNER JOIN TOOL_STOCK TS ON TS.BRANCH_ID = B.ID
GROUP BY B.ID;
replacing S.STAFF_ID with the primary key field from the STAFF table.
Your problem is that the COUNT function returns the number of rows matching the GROUP BY clause after all rows have been joined and returned.
In your initial query you are finding the number of employees for each branch, In the second the number of employees is multiplied by the number of stock items.

When you add the second join, you are getting the counts for STAFF + TOOLS at each branch.
You will likely need to add a subquery if you want all the data returned, but only counts of one record type.
I think the key to your issue is, which are you actually trying to count?

Related

Pl/sql query to display results for 900+ records using loop

Here's the query that I've made for only 1 data(site_serial_number)
I need to find all the 900+ rows. How to proceed from here? How to make this query for single row run in a loop for the rest of the records. Total rows are 957.
Below is the table given in picture, I want to find if the eam_group =transformer is present in site_serial_number.thus I've made the query for the 1st row.
Select B.*
From xxeam_mr_assets A, xxeam_mr_assets B
Where A.Eamid ='SITE-00266799' and A.end_date is null and
B. Eam_group='TRANSFORMER' and B.end_date is null and SDO_RELATE(A.MR_GEOM, B.MR_GEOM, 'mask=ANYINTERACT') ='True';
Need this Where clause for 900 records". Eg there are 900 SITES
Don't use a PL/SQL or loops, just JOIN the tables:
SELECT b.*
FROM XXEAM.XXEAM_WACS_Child_RM_transl#APPS_SP_TO_EAM w
INNER JOIN xxeam_mr_assets A
ON a.Eamid = w.site_serial_number
INNER JOIN xxeam_mr_assets B
ON SDO_RELATE(A.MR_GEOM, B.MR_GEOM, 'mask=ANYINTERACT') ='True'
WHERE a.end_date is null
AND b. Eam_group='TRANSFORMER'
AND b.end_date is null;

Left join vs. inner join not returning expected records

I am trying to find all of the most recent records (attempt_date) for a given "course" for each user. The query below returns the correct date for each user, unless the user doesn't have an attempt_date. In that case, the query does not return a row with the user at all.
If I change the inner joins on gradebook_grade and attempt to left join, it returns all enrolled users, but the query then returns null values if a null value exists for the any submission in the "course" rather than just the most recent attempt_date. Query here (forgive the weird naming conventions for term in the where clause, I did not choose those):
select distinct on (cu.pk1)
cu.pk1
,cm.course_id
,a.attempt_date
from course_users cu
inner join course_main cm on cm.pk1 = cu.crsmain_pk1
inner join course_term ct on ct.crsmain_pk1 = cm.pk1 /* through table */
inner join term t on t.pk1 = ct.term_pk1
inner join gradebook_grade gg on gg.course_users_pk1 = cu.pk1
inner join attempt a on a.gradebook_grade_pk1 = gg.pk1
where t.name like '%Fall 2021%'
and cu.role = 'S'
and cu.row_status = '0'
order by cu.pk1, course_id, attempt_date desc
How can I sidestep this behavior? If a student only has null values in a course for submission dates, I want the null value. If a student has anything other than a null value for submission dates in a course, I want the most recent last attempt date.
*Edited to give minimal reproducible example.
If you can, please write the structure of tables (create table DDL commands) and sample data. I will help you. But, I understood that: For example, we have 5 records in course_users table, and in the gradebook_grade may be have 7-8-10 records for only linked user3 and user4. Which users are not data in gradebook_grade table, we must select these users as null values, but which users have data in the gradebook_grade table, these users must be selected as one by one with the last attempt_date field.
For Example:
course_users.pk1
course_main.course_id
attempt_date
1
30
2
30
3
30
2021-03-10
4
20
2021-08-01
5
20
In this example, user3 and user4 have courses, but other users don't have.
Firstly we write a query that will select only users, which has courses and group these users by the last attaempt_date
select g1.course_users_pk1, max(a1.attempt_date) as attempt_date from attempt a1
inner join gradebook_grade g1 on a1.gradebook_grade_pk1 = g1.pk1
group by g1.course_users_pk1
Result:
course_users_pk1
attempt_date
3
2021-03-10
4
2021-08-01
Then completing our full query, with left joining this query to our main tables. Our final query:
select distinct on (cu.pk1)
cu.pk1,
cm.course_id,
gg.attempt_date
from course_users cu
left join course_main cm on cm.pk1 = cu.crsmain_pk1
left join course_term ct on ct.crsmain_pk1 = cm.pk1 /* through table */
left join term t on t.pk1 = ct.term_pk1 and t.name like '%2021%'
left join (
select g1.course_users_pk1, max(a1.attempt_date) as attempt_date from attempt a1
inner join gradebook_grade g1 on a1.gradebook_grade_pk1 = g1.pk1
group by g1.course_users_pk1
) gg on cu.pk1 = gg.course_users_pk1
where
cu.role = 'S'
and cu.row_status = '0'
order by cu.pk1, course_id, attempt_date desc
Maybe I misunderstood your question or your table structure, I am sorry, but if you can write create tables and some samples data I'm trying to help you.

how to find the rows not matched by the left join and perform some operations on top of it in sql server?

I'm trying to delete using left join from my sql server studio and my question is how do i get the list of ids that are getting deleted as part of the left join also i would like to compare the difference between the sum from both the tables
Table A:
ID NAME LOC SUM
4 abc NY 500
5 seq CA 100
15 juv TX 120
Table B:
ID NAME LOC SUM INFO
5 seq CA 90 x
18 jay AL 94 x
15 juv CL 190 x
I want to get to the number of rows that are getting removed as part of the left join and i want to see the difference in the sum
DELETE MYDB
FROM MYDB.A
LEFT JOIN MYDB.B
ON A.ID=B.ID
WHERE A.ID=B.ID
It is not clear why you would be using a LEFT JOIN for the JOIN. Your WHERE clause -- which is otherwise redundant -- is turning the outer join into an inner join.
I would suggest using exists:
delete from mydb.a
where exists (select 1 from mydb.b where b.id = a.id);
For a count, you can use:
select count(*)
from mydb.a
where exists (select 1 from mydb.b where b.id = a.id);
Do note: If you run these as two separate operations, the underlying data can change between the operations.
After running the delete, you can use ##ROWCOUNT to get the number of records deleted.

Inner join query

Please go thourgh Attached Image where i descirbed my scenario:
I want SQL Join query.
Have a look at something like
SELECT *
FROM Orders o
WHERE EXISTS (
SELECT 1
FROM OrderBooks ob INNER JOIN
Books b ON ob.BookID = b.BookID
WHERE o.OrderID = ob.OrderID
AND b.IsBook = #IsBook
)
The query will return all orders based on the given criteria.
So, what it does is, when #IsBook = 1 it will return all Orders where there exists 1 or more entries linked to this order that are Books. And if #IsBook = 0 it will return all Orders where there exists 1 or more entries linked to this order that are not Books.
Inner join is a method that is used to combine two or more tables together on base of common field from both tables. the both keys must be of same type and of length in regardless of name.
here is an example,
Table1
id Name Sex
1 Akash Male
2 Kedar Male
similarly another table
Table2
id Address Number
1 Nadipur 18281794
2 Pokhara 54689712
Now we can perform inner join operation using the following Sql statements
select A.id, A.Name, B.Address, B.Number from Table1 A
INNER JOIN Table2 B
ON A.id = B.id
Now the above query gives one to one relation details.

Count DIFFDATE Exceeding A Specified Value - Step 2

Further to my earlier question. Now I have two different queries that work. The first query returns a result of 5092 and the second returns a result of 1885 adding up to 6977. I would like to combine them into one query to return a result of 6977. How can I make one query count the number of conditionassessmentdates that are active, overdue by more than 14 days and null (counts as overdue)? Thanks in advance.
select count (*)
from task_conditionassessment t
inner join taskitems_conditionassessment ti on
t.task_conditionassessmentguid=ti.task_conditionassessmentguid
inner join conditionassessmentassignmentitem c on
ti.taskitems_conditionassessmentid=c.taskitems_conditionassessmentid
where datediff(dd,c.conditionassessmentdate,t.nextduedate)>14 and t.isactive=1
select t.taskname,t.nextduedate,c.conditionassessmentdate
from task_conditionassessment t
inner join taskitems_conditionassessment ti on
t.task_conditionassessmentguid=ti.task_conditionassessmentguid
inner join conditionassessmentassignmentitem c on
ti.taskitems_conditionassessmentid=c.taskitems_conditionassessmentid
where c.conditionassessmentdate IS NULL and t.isactive=1
If you just want a count of records that fit either set of criteria, just use an or in your where clause:
select count (*)
from task_conditionassessment t
inner join taskitems_conditionassessment ti on
t.task_conditionassessmentguid=ti.task_conditionassessmentguid
inner join conditionassessmentassignmentitem c on
ti.taskitems_conditionassessmentid=c.taskitems_conditionassessmentid
where (c.conditionassessmentdate IS NULL or
datediff(dd,c.conditionassessmentdate,t.nextduedate)>14) and
t.isactive=1
Providing that I understand correctly, just OR the two conditions together:
select count (*)
from task_conditionassessment t
inner join taskitems_conditionassessment ti on t.task_conditionassessmentguid=ti.task_conditionassessmentguid
inner join conditionassessmentassignmentitem c on ti.taskitems_conditionassessmentid=c.taskitems_conditionassessmentid
where (datediff(dd,c.conditionassessmentdate,t.nextduedate)>14
or c.conditionassessmentdate IS NULL)
and t.isactive=1