Match All Records - sql

I am having difficulty with writing an SQL query for my application. Below shows a screenshot of some of the tables in my database.
Please let me explain how a section of my application works, and then I can show you the problem I am having with my SQL query.
A User can create an application form on my system (dbo.Form). An application form consists of several sections, one of those sections is Employment History (dbo.FormEmployment). An employment record includes details like employer name, start date etc, but also a gradeID. A User can add one or more employment records to the table dbo.FormEmployment.
A system administrator can add a Shift (dbo.Shift) to the system, and also then assign Grades to a Shift. These Grades are recorded in the dbo.ShiftGrade table. A Shift can be assigned 1 or more Grades, i.e. it could be assigned 1,2,3,4 or 5 Grades.
When the system administrator has added the Shift and Shift Grades, I then want to perform an SQL query to return a list of Users whose Grades match that of the Grades assigned to a Shift (remember the User adds their Grade when they add an employment record).
I have written the following SQL query which works, however, the issue with this query is that it returns a list of Users, that have any Grade that matches that of the Grades assigned to a Shift.
SELECT u.userID, u.userTypeID, u.firstName, u.lastName, u.email, u.password,
u.contactNumber, u.organisationID, u.emailVerificationCode, u.mobileVerificationCode,
u.userStatusID, u.AddedBy, u.AddedDate, u.ModifiedBy, u.ModifiedDate
FROM [User] u
--Check Grades Match
WHERE u.userID IN
(
SELECT f.locumID
FROM dbo.Form f, dbo.FormEmployment emp
WHERE f.formID = emp.formID
AND emp.statusID = 101
AND emp.workYN = 1
AND emp.gradeID IN (
select gradeID from dbo.ShiftGrade where shiftID = #p0
)
)
You can see I am using the IN statement to do this. However, I only want to return a list of Users who can match exactly the same Grades that have been assigned to a Shift. Therefore, if a Shift has been assigned 3 Grades, then I want a List of Users who also have the exact same three Grades to be returned.
I apologise for the lengthy post, I just thought it would be better explained this way.
Any feedback or help with this would be greatly appreciated.

select u.*
from dbo.Users u
join dbo.Form f on u.? = f.formId
join dbo.FormEmployment fe on fe.formId = f.formId
join dbo.Grade g on g.gradeId = fe.gradeId
join dbo.ShiftGrade shg on shg.gradeId =g.gradeId
join dbo.Shift sh on sh.shiftId = shg.shiftId
where
sh.shiftId = -- recently added shift id
and g.gradeId == -- recently added grade id

Related

Having SQL Server choose and show one record over other

Ok, hopefully I can explain this accurately. I work in SQL Server, and I am trying to get one row from a table that will show multiple rows for the same person for various reasons.
There is a column called college_attend which will show either New or Cont for each student.
My issue: my initial query narrows down the rows I'm pulling by Academic Year, which consists of two semesters: Fall of one year, and Spring of the following to create an academic year. This is why there are two rows returned for some students.
Basically, I need to generate an accurate count of those that are "New" and those that are "Cont", but I don't want both records for the same student counted. They will have two records because they will have one for spring and one for fall (usually). So if a student is "New" in fall, they will have a "Cont" record for spring. I want the query to show ONLY the "New" record if they have both a "New' and "Cont" record, and count it (which I will do in Report Builder). The other students will basically have two records that are "Cont": one for fall, and one "Cont" for spring, and so those would be considered the continuing ones or "Cont".
Here is the basic query I have so far:
SELECT DISTINCT
people.people_id,
people.last_name,
people.first_name,
academic.college_attend AS NewORCont,
academic.academic_year,
academic.academic_term,
FROM
academic
INNER JOIN
people ON people.people_id = academic.people_id
INNER JOIN
academiccalendar acc ON acc.academic_year = academic.academic_year
AND acc.academic_term = academic.academic_term
AND acc.true_academic_year = #Academic_year
I'm not sure if this can be done with a CASE statement? I thought of a GROUP BY, but then SQL Server will want me to add all of my columns to the GROUP BY clause, and that ends up negating the purpose of the grouping in the first place.
Just a sample of what I work with for each student:
People ID
Last
First
NeworCont
12345
Soanso
Guy
New
12345
Soanso
Guy
Cont
32345
Person
Nancy
Cont
32345
Person
Nancy
Cont
55555
Smith
John
New
55555
Smith
John
Cont
---------
------
-------
----------
Hopefully this sheds some light on the duplicate record issue I mentioned.
Without sample data its awkward to visualize the problem, and without the expected results specified it's also unclear what you want as the outcome. Perhaps this will assist, it will limit the results to only those who have both 'New' and 'Cont' in a single "true academic year" but the count seems redundant as this (I imagine) will always be 2 (being 1 New term and 1 Cont term)
SELECT
people.people_id
, people.last_name
, people.first_name
, acc.true_academic_year
, count(*) AS count_of
FROM academic
INNER JOIN people ON people.people_id = academic.people_id
INNER JOIN academiccalendar acc ON acc.academic_year = academic.academic_year
AND acc.academic_term = academic.academic_term
AND acc.true_academic_year = #Academic_year
GROUP BY
people.people_id
, people.last_name
, people.first_name
, acc.true_academic_year
HAVING MAX(academic.college_attend) = 'New'
AND MIN(academic.college_attend) = 'Cont'

Sql Left or Right Join One To Many Pagination

I have one main table and join other tables via left outer or right outer outer join.One row of main table have over 30 row in join query as result. And I try pagination. But the problem is I can not know how many rows will it return for one main table row result.
Example :
Main table first row result is in my query 40 rows.
Main table second row result is 120 row.
Problem(Question) UPDATE:
For pagination I need give the pagesize the count of select result. But I can not know the right count for my select result. Example I give page no 1 and pagesize 50, because of this I cant get the right result.I need give the right pagesize for my main table top 10 result. Maybe for top 10 row will the result row count 200 but my page size is 50 this is the problem.
I am using Sql 2014. I need it for my ASP.NET project but is not important.
Sample UPDATE :
it is like searching an hotel for booking. Your main table is hotel table. And the another things are (mediatable)images, (mediatable)videos, (placetable)location and maybe (commenttable)comments they are more than one rows and have one to many relationship for the hotel. For one hotel the result will like 100, 50 or 10 rows for this all info. And I am trying to paginate this hotels result. I need get always 20 or 30 or 50 hotels for performance in my project.
Sample Query UPDATE :
SELECT
*
FROM
KisiselCoach KC
JOIN WorkPlace WP
ON KC.KisiselCoachId = WP.WorkPlaceOwnerId
JOIN Album A
ON KC.KisiselCoachId = A.AlbumId
JOIN Media M
ON A.AlbumId = M.AlbumId
LEFT JOIN Rating R
ON KC.KisiselCoachId = R.OylananId
JOIN FrUser Fr
ON KC.CoachId = Fr.UserId
JOIN UserJob UJ
ON KC.KisiselCoachId = UJ.UserJobOwnerId
JOIN Job J
ON UJ.JobId = J.JobId
JOIN UserExpertise UserEx
ON KC.KisiselCoachId = UserEx.UserExpertiseOwnerId
JOIN Expertise Ex
ON UserEx.ExpertiseId = Ex.ExpertiseId
Hotel Table :
HotelId HotelName
1 Barcelona
2 Berlin
Media Table :
MediaID MediaUrl HotelId
1 www.xxx.com 1
2 www.xxx.com 1
3 www.xxx.com 1
4 www.xxx.com 1
Location Table :
LocationId Adress HotelId
1 xyz, Berlin 1
2 xyz, Nice 1
3 xyz, Sevilla 1
4 xyz, Barcelona 1
Comment Table :
CommentId Comment HotelId
1 you are cool 1
2 you are great 1
3 you are bad 1
4 hmm you are okey 1
This is only sample! I have 9999999 hotels in my database. Imagine a hotel maybe it has 100 images maybe zero. I can not know this. And I need get 20 hotels in my result(pagination). But 20 hotels means 1000 rows maybe or 100 rows.
First, your query is poorly written for readability flow / relationship of tables. I have updated and indented to try and show how/where tables related in hierarchical relativity.
You also want to paginate, lets get back to that. Are you intending to show every record as a possible item, or did you intend to show a "parent" level set of data... Ex so you have only one instance per Media, Per User, or whatever, then once that entry is selected you would show details for that one entity? if so, I would do a query of DISTINCT at the top-level, or at least grab the few columns with a count(*) of child records it has to show at the next level.
Also, mixing inner, left and right joins can be confusing. Typically a right-join means you want the records from the right-table of the join. Could this be rewritten to have all required tables to the left, and non-required being left-join TO the secondary table?
Clarification of all these relationships would definitely help along with the context you are trying to get out of the pagination. I'll check for comments, but if lengthy, I would edit your original post question with additional details vs a long comment.
Here is my SOMEWHAT clarified query rewritten to what I THINK the relationships are within your database. Notice my indentations showing where table A -> B -> C -> D for readability. All of these are (INNER) JOINs indicating they all must have a match between all respective tables. If some things are NOT always there, they would be changed to LEFT JOINs
SELECT
*
FROM
KisiselCoach KC
JOIN WorkPlace WP
ON KC.KisiselCoachId = WP.WorkPlaceOwnerId
JOIN Album A
ON KC.KisiselCoachId = A.AlbumId
JOIN Media M
ON A.AlbumId = M.AlbumId
LEFT JOIN Rating R
ON KC.KisiselCoachId = R.OylananId
JOIN FrUser Fr
ON KC.CoachId = Fr.UserId
JOIN UserJob UJ
ON KC.KisiselCoachId = UJ.UserJobOwnerId
JOIN Job J
ON UJ.JobId = J.JobId
JOIN UserExpertise UserEx
ON KC.KisiselCoachId = UserEx.UserExpertiseOwnerId
JOIN Expertise Ex
ON UserEx.ExpertiseId = Ex.ExpertiseId
Readability of a query is a BIG help for yourself, and/or anyone assisting or following you. By not having the "on" clauses near the corresponding joins can be very confusing to follow.
Also, which is your PRIMARY table where the rest are lookup reference tables.
ADDITION PER COMMENT
Ok, so I updated a query which appears to have no context to the sample data and what you want in your post. That said, I would start with a list of hotels only and a count(*) of things per hotel so you can give SOME indication of how much stuff you have in detail. Something like
select
H.HotelID,
H.HotelName,
coalesce( MedSum.recs, 0 ) as MediaItems,
coalesce( LocSum.recs, 0 ) as NumberOfLocations,
coalesce( ComSum.recs, 0 ) as NumberOfLocations
from
Hotel H
LEFT JOIN
( select M.HotelID,
count(*) recs
from Media M
group by M.HotelID ) MedSum
on H.HotelID = MedSum.HotelID
LEFT JOIN
( select L.HotelID,
count(*) recs
from Location L
group by L.HotelID ) LocSum
on H.HotelID = LocSum.HotelID
LEFT JOIN
( select C.HotelID,
count(*) recs
from Comment C
group by C.HotelID ) ComSum
on H.HotelID = ComSum.HotelID
order by
H.HotelName
--- apply any limit per pagination
Now this will return every hotel at a top-level and the total count of things per the hotel per the individual counts which may or not exist hence each sub-check is a LEFT-JOIN. Expose a page of 20 different hotels. Now, as soon as one person picks a single hotel, you can then drill-into the locations, media and comments per that one hotel.
Now, although this COULD work, having to do these counts on an every-time query might get very time consuming. You might want to add counter columns to your main hotel table representing such counts as being performed here. Then, via some nightly process, you could re-update the counts ONCE to get them primed across all history, then update counts only for those hotels that have new activity since entered the date prior. Not like you are going to have 1,000,000 posts of new images, new locations, new comments in a day, but of 22,000, then those are the only hotel records you would re-update counts for. Each incremental cycle would be short based on only the newest entries added. For the web, having some pre-aggregate counts, sums, etc is a big time saver where practical.

How to join two queries in access

I am incapable of make a query that return me a results as follows:
TABLES: series, usuarios, siguiendo, valoraciones_personales
Each table has got this records:
example: field1(value), field2(value),...
series (I refer a tv show, I am spanish and here we say "serie=tv_show")
1. id_serie(1),id_titulo('Sons of anarchy')
2. id_serie(2),id_titulo('Lost')
usuarios (user)
1. id_usuario(1), nick('david')
siguiendo (a usser follow a series)
1. id_serie(1),id_usuario(1)
2. id_serie(2),id_usuario(1)
valoraciones_personales (personal assessments)
1. id_serie(1),id_usuario(1),nota(8)
Ok, what I want is a result with all records of the table siguiendo, and if that user valued one of that series, it must shows the score (nota in spanish), and if that user didn´t scored that series, I want to show "without score".
The view I want:
*titulo, nota*
- Sons of anarchy, 8
- Lost, without score
Can anyone help me?
Specifically in MSACCESS
Create a query called something like AllUserSeries
SELECT
U.UserID
,U.FullName
,S.SeriesID
,S.SeriesName
FROM
usuarios as U
,series as S
This is the equivalent of a cross join
Then another:
SELECT
A.FullName
,A.SeriesName
,Nz(Cstr(R.Score),"Not Rated") as Rating
FROM
AllUserSeries AS A
LEFT OUTER JOIN valoraciones_personales AS R
ON A.UserID = R.UserID
AND A.SeriesID = R.SeriesID
WHERE
A.UserID = #UserID
The tricky bit is getting a list of all the series a user may have liked. to do this normally i would do a cross join to get all permutations that could exist, then left join from there to the ratings table using Nz to handle null values as you see fit.
*sorry for kinda making up the other column names it was easier for me to use English hope that okay :D

How to combine to values from two records

Hi guys so I have the following code that should look at a event cost, figure out from a transaction table if its been fully paid and from that display the unpaid balance.
Select CASESTUDY_CLIENT.CLEINT_FNAME as First_Name,
casestudy_client.client_sname as Surname,
casestudy_client.client_Phonenumber as Phone_number,
casestudy_event.event_totalcost- casestudy_transaction.transaction_value as Unpaid_balance
from casestudy_client
inner join casestudy_event
on casestudy_client.client_id = casestudy_event.event_clientid
inner join casestudy_transaction
on casestudy_event.event_id = casestudy_transaction.transaction_eventid
where casestudy_event.EVENT_EVENTSTAGE ='complete' and
casestudy_event.event_totalcost > casestudy_transaction.transaction_value;
This works perfectly however if we have a multi part transaction then it fails to pick up the matching event id and assumes its another event.
In my test data I have an event that costs £500, one transaction that has a value of 400 and one transaction with a value of 99. The current output shows the two records one with an unpaid balance of 100 and the other with 401. What I would like to show is just 99
If this is possible in relatively simple way please let me know as I can't figure out how to make it work
You need to add together transactions.
Select CASESTUDY_CLIENT.CLEINT_FNAME as First_Name,
casestudy_client.client_sname as Surname,
casestudy_client.client_Phonenumber as Phone_number,
casestudy_event.event_totalcost- sum(casestudy_transaction.transaction_value) as Unpaid_balance
from casestudy_client
inner join casestudy_event
on casestudy_client.client_id = casestudy_event.event_clientid
inner join casestudy_transaction
on casestudy_event.event_id = casestudy_transaction.transaction_eventid
where casestudy_event.EVENT_EVENTSTAGE ='complete' and
casestudy_event.event_totalcost > casestudy_transaction.transaction_value
GROUP BY CASESTUDY_CLIENT.CLEINT_FNAME, casestudy_client.client_sname, casestudy_client.client_Phonenumber, casestudy_event.event_totalcost
Also, CLEINT_FNAME is probably a typo.
It appears you want to sum the transaction values before subtracting them from the cost.
Select CASESTUDY_CLIENT.CLEINT_FNAME as First_Name,
casestudy_client.client_sname as Surname,
casestudy_client.client_Phonenumber as Phone_number,
casestudy_event.event_totalcost- casestudy_transaction.transaction_value as Unpaid_balance
from casestudy_client
inner join casestudy_event
on casestudy_client.client_id = casestudy_event.event_clientid
inner join (
select casestudy_transaction.transaction_eventid, sum(transaction_value) as transaction_value
from casestudy_transaction
group by casestudy_transaction.transaction_eventid
) as casestudy_transaction
on casestudy_event.event_id = casestudy_transaction.transaction_eventid
where casestudy_event.EVENT_EVENTSTAGE ='complete'
and casestudy_event.event_totalcost> casestudy_transaction.transaction_value ;
I would probably left join the transactions subquery though so you can include the events that haven't been paid for yet, but that just depends on the goal of the query.

Find records that do not have a specific value attached

I am fairly new to SQL and I'm completely stuck in this query.
I have written a query for a health organization that pulls patients info, their appointment/which provider seen the patient, what location they were seen at and what documents were created during that visit and a signoff status.
When the results return, that part of the query is accurate. (Many rows for 1 patient because of many different types of documents were generated in that one appointment)
What I am looking for, however, is to have a list of patients that have had an appointment yet "X" document was NOT created. I dont want to see the list of other documents created; specifically the appointments where "X" was not created.
Please help!
This is the query that I first explained showing the patient/appointment info, and specific documents that have been generated.
SELECT prs.person_nbr, prs.last_name + ', '+ prs.first_name as Patient, prs.date_of_birth
, pm.description AS Provider
, lm.site_id
, appts.appt_type, appts.appt_date
, pd.document_desc, pd.signoff_status
FROM person prs
, patient_documents pd
, location_mstr lm
, provider_mstr pm
, appointments appts
WHERE prs.person_id = appts.person_id
and appts.enc_id = pd.enc_id
and appts.location_id = lm.location_id
and lm.site_id is not null
and appts.rendering_provider_id = pm.provider_id
and ((pd.document_desc IN ('bms_master_im', 'Master_Im', 'BMS_ob_master','BMS_GYN_master', 'BMS_bh_master')
and pd.signoff_status = 'P')
OR (pd.document_desc IN ('bms_master_im', 'Master_Im', 'BMS_ob_master', 'BMS_GYN_master', 'BMS_bh_master')
AND pd.signoff_status IS NULL ))
ORDER BY lm.site_id, Provider
Additional info:
Tried everything suggested.
To elaborate, here's an example.
Patient: JOHN SMITH
Appointment: 20111201
Documents created: work_letter, lab_req, master_im (master_im is one of the listed to be included in the results by the IN clause)
Patient: JANE WILCOX
Appointment: 20120704
Documents created: lab_results, test_action, immunization_record.
For JOHN SMITH, the results would show that he has a master_im. Based on the already written query.
For JANE WILCOX, the results would exclude her since her documents are not listed in the IN clause. However, I want to see her in the results so that I see that she does not have a master_im or any of the other documents listed in the IN clause created.
What i'm looking for in the end is to exclude JOHN SMITH because his appointment does have the master_im document created; and to include JANE WILCOX because she has an appointment that does not have the master_im. (master_im can be substituted by any of the document values in the IN clause of my query)
***All patients who have an appointment that a) does not have "x" document created, or b) does have the "x" document created but the signoff status = P or NULL. (B is easy to figure out, only need help with part a). And we want to ignore all other documents that are not included in x.
x= 'bms_master_im', 'master_im',' bms_ob_master', 'bms_gyn_master', 'bms_bh_master', 'ob_master', 'gyn_master', 'bh_master')
You need to expand your WHERE clause by adding a condition on the field that contain the "X" values you speak of. Assuming this field is located in patient_documents.code, your WHERE clause becomes:
WHERE prs.person_id = appts.person_id
and appts.enc_id = pd.enc_id
and appts.location_id = lm.location_id
and lm.site_id is not null
and appts.rendering_provider_id = pm.provider_id
and pd.code not in ('X', '...')
and ((pd.document_desc IN ('bms_master_im', 'Master_Im', 'BMS_ob_master','BMS_GYN_master', 'BMS_bh_master')
and pd.signoff_status = 'P')
OR (pd.document_desc IN ('bms_master_im', 'Master_Im', 'BMS_ob_master', 'BMS_GYN_master', 'BMS_bh_master')
AND pd.signoff_status IS NULL ))
Note that I added the line with the whitespace on top and below. Of course, if the field containing the code is named differently, you should modify the field reference.
Edited:
You need to use JOIN clauses on your tables, and a left join on the documents table.
For Example:
FROM person prs,
JOIN appointments appts ON prs.person_id = appts.person_id
JOIN location_mstr lm ON appts.location_id = lm.location_id
JOIN provider_mstr pm ON ...
Then
LEFT JOIN patient_documents pd ON ...