How can I set and change the value in one field from query? Can I get the exact results some other way? - Access 2010 - sql

I have two tables. One is the -reqtable- in which i have
ID_request, PK
ID_Student,
ID_Professor,
Date,
ID_TypeofReq 1 meaning 'change mentor' , 3 meaning ' rejected by mentor'
ID_approved-rejected 1 menains approved , 2 meaning rejected
The other table is STUDENTStable:
ID_STUDENT as primary key
ID_Professor acting like a foreign key but not directly connected to any table.
The idea is to get the current mentor for each student. Students can change mentors and I want to always have the current one. I tried to achieve that with query but I didn't get the right results jet.
So I got an idea to to make a query that will update the ID_professor in the table STUDENTStable and I want the query to be that connection.
Type of request-> ID_typeofreq can be 1 meaning 'choosing mentor' and if the professor approves (ID_approved-rejected = 1) then the student has its mentor.
Type of request can also be 3, which means that mentor was mentoring the student but doesn't want to mentor the student anymore (the id_approved-rejected in that case is always 1 meaning approved). If that is the last entry than the student doesn't have the mentor anymore and should not be in the result of 'currently mentoring query'. But the student can later choose a new mentor and if is accepted he will get into the result 'currently mentoring query' again
The two tables are not connected, but its no problem to join them if will do the job.
SELECT a.ID_request,
a.ID_Student,
a.ID_Professor,
a.Date,
a.ID_typeofreq
FROM [reqtable] AS a
WHERE (((a.ID_typeofreq)=1 Or (a.ID_typeofreq)=3) AND ((a.ID_approved-rejected)=1)
AND ((a.Date)=(SELECT MAX(b.date)
FROM [reqtable] AS b
WHERE b.ID_request = a.ID_request)))
ORDER BY a.ID_Student DESC;
I need the code that will catch the last entry and if the type of request is 1 and ID_ aprooved-rejected = 1 to put the new id_professor in the STUDENTStable
And if the last ID_typeofreq is 3 and ID_aprooved-rejected = 1 to set the value of ID_Professor to Null again.

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'

LEFT JOIN is killing my query - how to speed up?

I have two tables:
a list of documents created in our system (offers and invoices) when something is logged as "done".
BELEG_ART
BELEG_NR
DATUM
BELEG_TYPE
160
337691
11.01.2021
Invoice
10
195475
04.01.2021
Offer
20
195444
04.01.2021
Confirmation
A list of transactions (sales etc) with article information AND the document info
ANUMMER
KDNR
NAME1
REC_LIST
181557
59301205
Fred
332240
195973
59306391
John
338225
189661
59304599
Steve
335495
189718
49302475
Ed
196483
59303491
Mark
338204
190021
49302595
Jones
You can see that the Offers and Confirmation... they start with a "1". Invoices with "3".
I need everything to be linked and identified by it's ANUMMER with "1". Later on, I'll pull other tables based on this number, thus it's the critical point for me.
The problem is - in the documents table, when you see the invoice, you don't see the ANUMMER. You only see the "3".
So, I have created a join as below to pull everything together.
SELECT
DAB700.BELEG_ART,DAB700.BELEG_NR,DAB700.DATUM,DAB700.BUCH_DATUM,
case // rename the documents to something more meaningful
when DAB700.BELEG_ART = 10 then 'Angebote'
when DAB700.BELEG_ART = 20 then 'Auftrag'
when DAB700.BELEG_ART = 60 then 'Lieferschein'
when DAB700.BELEG_ART = 160 then 'Rechnung'
else 'not defined'
end as "BELEG_TYPE",
DAB050.ANUMMER,
case // if the document is an offer, then copy it to order_number. If it's a invoice, copy that number to order_number.
when DAB700.BELEG_ART = 10 then DAB700.BELEG_NR
when DAB700.BELEG_ART = 160 then DAB050.ANUMMER
else 'NA'
end as "order_number"
FROM "DAB700.ADT" DAB700
// if the document is an invoice, then join to the table DAB050 and reference the same key field REC_LIST.
left join "DAB050.ADT" DAB050 on
Case
When DAB700.BELEG_ART = 160 then DAB700.BELEG_NR = DAB050.REC_LIST
End
WHERE (DAB700.DATUM={d '2021-01-12'})
So - to my problem and question: when running this join query, it's much slower than I'd like (even with small datasets). Is there a way to restructure this, so it's faster?
Long story short - to simplify:
I want to add some columns to table 1
when table 1-BELEG_NR starts with a "1", good - just move the number into a new column
when table 1-BELEG_NR starts with a "3", then I have to link to table 3, and pull in the ANUMMER
thanks for your help
The problem is that the join condition is not optimizable because 1. it is a complex expression, and 2. it involves a memo/clob columen (REC_LIST is probably a memo based on your other question). What that mean is that the joint condition has to be evaluated for each combination of rows in DAB700 and DAB050.
It seems to me that the join condition can be simplified to:
DAB700.BELEG_ART = 160 And DAB700.BELEG_NR = DAB050.REC_LIST
There is no need for the Case because the default case is null or false. That will cut down the number of rows in DAB700 participating in the join. However, the second part of the join is still not optimal if REC_LIST is MEMO or CLOB data type.
In any case, I would also suggest checking to see if REC_LIST should be a fixed length string column (CHAR, NCHAR, VARCHAR or NVARCHAR) instead of MEMO which cannot be indexed and thus not useful for optimization.

VS SR Report joining data from multiple Data sets?

Wondering if anyone can help me, I am currently learning, SRSS Reports and have been tasked with a Pay & Display vehicle registration report, for staff and student carparks, to show if they are registered for P&D. I have the report laid out as a 3 table column; Name, Vehicle Number and Vehicle Registration. I have from the below code set out in my datasets the Vehicle Number and Vehicle Registrations pulling through, with a parameter to filter out if is staff or student pay and display. However I am having difficulty with pulling the Staff and Student names into one name column as they are through two different datasets. Can anyone be of help at all please? TIA
**-- Pay & Display Carpark Details Dataset**
SELECT * FROM Carpark_Vehicles
WHERE VehicleCustNo IN (SELECT CustID FROM [dbo].[Carpark_Customer]
WHERE CarParkID IN (SELECT CarParkID FROM [dbo].[Carpark_CarPark]
WHERE CTypeID IN ('PD', 'SPD')))
--and CTypeID IN (#Carpark_type))
**--Vehicle Details Dataset**
SELECT
Carpark_Vehicles.VehicleID
,Carpark_Vehicles.RegNo
,VehicleCustNo
FROM
Carpark_Vehicles
WHERE CarPark_Vehicles.RegNo = #RegNo
**--Staff details dataset**
SELECT
StaffDetails_StaffandLeaverDetails.StaffNumber
,StaffDetails_StaffandLeaverDetails.LastName
,StaffDetails_StaffandLeaverDetails.Name1
FROM
StaffDetails_StaffandLeaverDetails
**--Student details dataset**
SELECT
Student_CurrentStudentDetails.StudentNumber
,Student_CurrentStudentDetails.StudentID
,Student_CurrentStudentDetails.LastName
,Student_CurrentStudentDetails.FirstName
FROM
Student_CurrentStudentDetails
**--Carpark permit type (Pay & Display) parameter**
SELECT DISTINCT
CTypeID, CASE CTypeID WHEN 'abc' THEN 'Students' WHEN 'abc' THEN 'Staff' END AS Label
FROM
Carpark_Customer
WHERE CTypeID IN ('abc', 'Abc')
For your req I just took some sample data. This entire example will give you Idea how to achieve your final result.
Note: this is just showing you way how to achieve it, you have to modify as per your req.
Student and Staff Info from 2 different Tables
Registration Info from another separate Table
Your Final Result when Student as parameter is selected
Your Final Result when Staff as parameter is selected
Now how did I achieved this?
My Design for Final Result
Row visibilty expression for your final result Table in SSRS
Expressiion as below
=IIF(Parameters!ReportParameter1.Value=1,
IIF(Isnothing(Lookup(Fields!PersonId.Value,Fields!PersonId.Value,Fields!Name.Value, "DSStudentInfo")),true,false),
IIF(Isnothing(Lookup(Fields!PersonId.Value,Fields!PersonId.Value,Fields!Name.Value, "DSStaffInfo")),true,
false)
)
first Name column visibility
second column name visibility
First Name data value expression
=Lookup(Fields!PersonId.Value,Fields!PersonId.Value,Fields!Name.Value, "DSStudentInfo")
second name data value expression
=Lookup(Fields!PersonId.Value,Fields!PersonId.Value,Fields!Name.Value, "DSStaffInfo")

SQL query , group by only one column

i want to group this query by project only because there are two records of same project but i only want one.
But when i add group by clause it asks me to add other columns as well by which grouping does not work.
*
DECLARE #Year varchar(75) = '2018'
DECLARE #von DateTime = '1.09.2018'
DECLARE #bis DateTime = '30.09.2018'
select new_projekt ,new_geschftsartname, new_mitarbeitername, new_stundensatz
from Filterednew_projektkondition ps
left join Filterednew_fakturierungsplan fp on ps.new_projekt = fp.new_hauptprojekt1
where ps.statecodename = 'Aktiv'
and fp.new_startdatum >= #von +'00:00:00'
and fp.new_enddatum <= #bis +'23:59:59'
--and new_projekt= Filterednew_projekt.new_
--group by new_projekt
*
look at the column new_projekt . row 2 and 3 has same project, but i want it to appear only once. Due to different other columns this is not possible.
if its of interested , there is another coluim projectcondition id which is unique for both
You can't ask a database to decide arbitrarily for you, which records should be thrown away when doing a group. You have to be precise and specific
Example, here is some data about a person:
Name, AddressZipCode
John Doe, 90210
John Doe, 12345
SELECT name, addresszipcode FROM person INNER JOIN address on address.personid = person.id
There are two addresses stored for this one guy, the person data is repeated in the output!
"I don't want that. I only want to see one line for this guy, together with his address"
Which address?
That's what you have to tell the database
"Well, obviously his current address"
And how do you denote that an address is current?
"It's the one with the null enddate"
SELECT name, addresszipcode FROM person INNER JOIN address on address.personid = person.id WHERE address.enddate = null
If you still get two addresses out, there are two address records that are null - you have data that is in violation of your business data modelling principles ("a person's address history shall have at most one adddress that is current, denoted by a null end date") - fix the data
"Why can't i just group by name?"
You can, but if you do, you still have to tell the database how to accumulate the non-name data that it shows you. You want an address data out of it, it has 2 it wants to show you, you have to tell it which to discard. You could do this:
SELECT name, MAX(addresszipcode) FROM person INNER JOIN address on address.personid = person.id GROUP BY name
"But I don't want the max zipcode? That doesn't make sense"
OK, use the MIN, the SUM, the AVG, anything that makes sense. If none of these make sense, then use something that does, like the address line that has the highest end date, or the lowest end date that is a future end date. If you only want one address on show you must decide how to boil that data down to just one record - you have to write the rule for the database to follow and no question about it you have to create a rule so make it a rule that describes what you actually want
Ok, so you created a rule - you want only the rows with the minimum new_stundenstatz
DECLARE #Year varchar(75) = '2018'
DECLARE #von DateTime = '1.09.2018'
DECLARE #bis DateTime = '30.09.2018'
select new_projekt ,new_geschftsartname, new_mitarbeitername, new_stundensatz
from
(SELECT *, ROW_NUMBER() OVER(PARTITON BY new_projekt ORDER BY new_stundensatz) rown FROM Filterednew_projektkondition) ps
left join
Filterednew_fakturierungsplan fp on ps.new_projekt = fp.new_hauptprojekt1
where ps.statecodename = 'Aktiv'
and fp.new_startdatum >= #von +'00:00:00'
and fp.new_enddatum <= #bis +'23:59:59'
and ps.rown = 1
Here I've used an analytic operation to number the rows in your PS table. They're numbered in order of ascending new_stundensatz, starting with 1. The numbering restarts when the new_projekt changes, so each new_projekt will have a number 1 row.. and then we make that a condition of the where
(Helpful side note for applying this technique in future.. Ff it were the FP table we were adding a row number to, we would need to put AND fp.rown= 1 in the ON clause, not the WHERE clause, because putting it in the where would make the LEFT join behave like an INNER, hiding rows that don't have any FP matching record)

SQL query for crystal reports produces duplicate results

I created 3 tables TstInvoice, TstProd, TstPersons and added some data:
INVOICE_NBR CLIENT_NR VK_CONTACT
A10304 003145 AT
A10305 000079 EA
A10306 004458 AT
A10307 003331 JDJ
PROD_NR INVOICE_NBR
P29366 A10304
P29367 A10304
P29368 A10305
P29369 A10306
P29370 A10306
P29371 A10307
PERS_NR INITIALEN STATUS PERSOON
0001 AT 7 Alice Thompson
0002 EA 1 Edgar Allen
0003 JDJ 1 John Doe Joe
0004 AT 1 Arthur Twins
The parameter that is passed to the crystal report is the INVOICE_NBR.
On my crystal report I put some fields from the databases and one sql expression:
(
SELECT "TstPersons"."PERSOON" FROM "TstPersons"
WHERE "TstPersons"."INITIALEN" = "TstInvoice"."VK_CONTACT" AND "TstPersons"."STATUS" = 1
)
The full query that is generated:
SELECT "TstInvoice"."INVOICE_NBR", "TstInvoice"."CLIENT_NR", "TstPersons"."STATUS", "TstPersons"."PERSOON", "TstProd"."PROD_NR", "TstProd"."INVOICE_NBR", (
SELECT "TstPersons"."PERSOON" FROM "TstPersons"
WHERE "TstPersons"."INITIALEN" = "TstInvoice"."VK_CONTACT" AND "TstPersons"."STATUS" = 1
)
FROM ("GCCTEST"."dbo"."TstInvoice" "TstInvoice" INNER JOIN "GCCTEST"."dbo"."TstProd" "TstProd" ON "TstInvoice"."INVOICE_NBR"="TstProd"."INVOICE_NBR") INNER JOIN "GCCTEST"."dbo"."TstPersons" "TstPersons" ON "TstInvoice"."VK_CONTACT"="TstPersons"."INITIALEN"
WHERE "TstInvoice"."INVOICE_NBR"='A10304'
The result is as shown in the screenshot:
As you can see the TstPersons.PERSOON field is populated with Alice Thompson and the sql expression field is correctly populated with Arthur Twins. However, I would like only to see the prod_nr once. With this query it produces the prod numbers twice because of the double entry for "AT" despite the fact that I ask for only status 1. I could just delete the old entry but I want to know if it's possible this way.
* edit * I added the status = 1 to the "record selection formula editor" and that seems to work. Not need the sql expression field at all. Not sure if this is the correct way to go though.
So now it looks like this:
SELECT "TstInvoice"."INVOICE_NBR", "TstInvoice"."CLIENT_NR", "TstPersons"."STATUS", "TstPersons"."PERSOON", "TstProd"."PROD_NR", "TstProd"."INVOICE_NBR"
FROM ("GCCTEST"."dbo"."TstInvoice" "TstInvoice" INNER JOIN "GCCTEST"."dbo"."TstProd" "TstProd" ON "TstInvoice"."INVOICE_NBR"="TstProd"."INVOICE_NBR") INNER JOIN "GCCTEST"."dbo"."TstPersons" "TstPersons" ON "TstInvoice"."VK_CONTACT"="TstPersons"."INITIALEN"
WHERE "TstInvoice"."INVOICE_NBR"='A10304' AND "TstPersons"."STATUS"=1
You have a very weak join in your query due to the duplicate values found in the INITIALEN column. Using the STATUS = 1 criteria is a work-around more than a solution because if you ever need to report on an invoice where the contact has a status other than 1, you will need to modify the report's design to allow your join to work because the STATUS value is not found on the invoice to allow a proper join to occur.
You are also running a risk of this work-around breaking down completely should you have another contact with both the same initials and status values as another.
The correct way to solve this problem would be to join TstInvoice to TstPersons through a field that has unique values. The PERS_NR column appears to be a good choice for this.
This is also going to require a redesign of the TstInvoice table to include the PERS_NR column as a Foreign Key.
A stronger join between invoices and persons would also remove the need for that sub-query in you selection statement. This would simplify your query down to the following:
SELECT "TstInvoice"."INVOICE_NBR", "TstInvoice"."CLIENT_NR", "TstPersons"."STATUS", "TstPersons"."PERSOON", "TstProd"."PROD_NR", "TstProd"."INVOICE_NBR"
FROM "GCCTEST"."dbo"."TstInvoice" "TstInvoice"
INNER JOIN "GCCTEST"."dbo"."TstProd" "TstProd"
ON "TstInvoice"."INVOICE_NBR"="TstProd"."INVOICE_NBR"
INNER JOIN "GCCTEST"."dbo"."TstPersons" "TstPersons"
ON "TstInvoice"."PERS_NR"="TstPersons"."PERS_NR"
WHERE "TstInvoice"."INVOICE_NBR"='A10304'