GROUP BY clause on multiple joins - sql-server

I need to show Class Wise attendance like this
IN DB i am have separate table (studentattendance) ,which store attendance like this
I Just Need to Show Total students Present Per Class
I try to do Query which give output like this
this is my query
SELECT distinct CM.ClassName ,SB.SubjectName ,(select count(studentattendance.Day1) from studentattendance where day1 = 'P') as Present, convert(varchar(10),AttendanceDate ,126) as AttendancetimeTaken
from studentattendance SA inner join studentmaster SM on SA.StudentID=SM.ID join ProfessorMaster p on SA.ProfessorID =p.Id
join Classmaster CM on SA.ClassID = CM.ID inner join SubjectMaster SB on SA.SubjectID =SB.ID
I need to Group Class Wise . how can I do it

By not having the actual tables, I tried the following modifications, please try it and reply me
SELECT CM.ClassName ,
SB.SubjectName , count(SA.Day1) as Present,
convert(varchar(10),AttendanceDate , 126) as AttendancetimeTaken
from studentattendance SA
inner join studentmaster SM on SA.StudentID=SM.ID
join ProfessorMaster p on SA.ProfessorID =p.Id
join Classmaster CM on SA.ClassID = CM.ID
inner join SubjectMaster SB on SA.SubjectID =SB.ID
where SA.day1 = 'P'
group by CM.ClassName, SB.SubjectName, AttendanceDate

Related

Accessing a new table created after a join

I have joined select columns from 3 tables into a new table using the following:
SELECT A.ExternalID, A.UserDefinedXml.value('(Skin_Sheet/#Label)[1]', 'varchar(3)') AS SS, A.ServiceSiteUid, A.LastModifiedDate, A.PersonUid,
B.FirstName, B.LastName, B.PersonUid,
C.Name
FROM Patient A
INNER JOIN Person B ON B.PersonUid = A.PersonUid
INNER JOIN ListServiceSite C ON C.ServiceSiteUid = A.ServiceSiteUid
WHERE SS IS NOT NULL
ORDER By LastModifiedDate;
This all works but I'm not sure how to reference the column SS created from data extracted from the XML so I can only select the observations in which the value is "Yes" or "No". In R I would have created a new object but I'm not sure how SQL stores this new table if I don't specify what the table name is.
Side note, I did try to insert this into a new table but SQL wasn't letting me because, for some reason, the join resulted in PersonUid being duplicated.
Thank you in advance, I'm very, very new to SQL and trying to learn on the fly.
Conceptually WHERE comes before SELECT, so you need to push the query into a derived table subquery or Common Table Expression (CTE) to reference SS in a WHERE clause. EG
with q as
(
SELECT A.ExternalID, A.UserDefinedXml.value('(Skin_Sheet/#Label)[1]', 'varchar(3)') AS SS, A.ServiceSiteUid, A.LastModifiedDate, A.PersonUid,
B.FirstName, B.LastName, B.PersonUid,
C.Name
FROM Patient A
INNER JOIN Person B ON B.PersonUid = A.PersonUid
INNER JOIN ListServiceSite C ON C.ServiceSiteUid = A.ServiceSiteUid
)
SELECT *
FROM q
WHERE SS IS NOT NULL
ORDER By LastModifiedDate;
This will put your results into a temp table, and avoids the problem of having two columns with the same name:
SELECT
A.ExternalID
,SS = A.UserDefinedXml.value('(Skin_Sheet/#Label)[1]', 'varchar(3)')
,A.ServiceSiteUid
,A.LastModifiedDate
,PersonUid_A = A.PersonUid
,B.FirstName
,B.LastName
,PersonUid_B = B.PersonUid
,C.Name
INTO #TempResults
FROM Patient A
INNER JOIN Person B ON B.PersonUid = A.PersonUid
INNER JOIN ListServiceSite C ON C.ServiceSiteUid = A.ServiceSiteUid
WHERE SS IS NOT NULL
ORDER BY LastModifiedDate;

Group the count values

I want to get the count of property and building and building is linked with property. Below is the query I tried:
select
PT.PropertyTypeName,
Count(PropertyID) as ProperyCount,
Isnull((Select count(B.BuildingID)
from Building B
join Property P1
on B.PropertyID=P1.PropertyID
where B.PropertyID =P.PropertyID), 0) as BuildingsCount
from Property P
join PropertyType PT
on PT.PropertyTypeID = P.PropertyTypeID
left join AssetToFund AF
on AF.AssetID = P.AssetID
left join Fund F
on F.FundID = AF.FundID
left join Asset A
on A.AssetID = P.AssetID
left join Client C
on C.ClientID = F.ClientID
where C.ClientId=10000001
group by PT.PropertyTypeName,P.PropertyID
I expect values group of type
and I want to group the count with out duplicate of property-type name
sry for bad English.
Try to use the SUM() function on this subquery
Returns the sum of all the values, or only the DISTINCT values, in the expression. SUM can be used with numeric columns only. Null values are ignored.
MSDN
SUM(Select count(B.BuildingID)
from Building B
join Property P1
on B.PropertyID=P1.PropertyID
where B.PropertyID = P.PropertyID)
When you use GROUP BY then it groups data by columns which you've written in GROUP BY statement. You've written :
GROUP BY PT.PropertyTypeName,P.PropertyID`
it means that SQL Engine will get all unique combinations of PropertyTypeName, PropertyID. However, you want just unique PropertyTypeName. So write just this field into GROUP BY statement:
GROUP BY PT.PropertyTypeName
So complete query will look like this:
select
PT.PropertyTypeName,
Count(PropertyID) as ProperyCount,
Isnull((Select count(B.BuildingID)
from Building B
join Property P1
on B.PropertyID=P1.PropertyID
where B.PropertyID =P.PropertyID), 0) as BuildingsCount
from Property P
join PropertyType PT
on PT.PropertyTypeID = P.PropertyTypeID
left join AssetToFund AF
on AF.AssetID = P.AssetID
left join Fund F
on F.FundID = AF.FundID
left join Asset A
on A.AssetID = P.AssetID
left join Client C
on C.ClientID = F.ClientID
where C.ClientId=10000001
group by PT.PropertyTypeName

Select data from first date following a specific date (two tables joined)

I've searched but can't seem to get this exactly where I need it. This is in regards to Microsoft SQL Server.
I'm looking to join two tables, but only pull in data from the second table for the first date following the date in the first table. See code below.
I've got a table that shows emails sent to customers that looks like this:
SELECT
e.Name
,se.SubscriberID
,se.SendID
,c1.Id
,ds.Service_Num
,sub.EmailAddress
,se.EventDate as 'SentDate'
into #temp_billing_emails
FROM
bi_views.dbo.sfdcMC_SentEvent se
left join bi_views.dbo.sfdcmc_job j on j.jobid=se.sendid
left join bi_views.dbo.sfdcMC_Email e on e.id=j.emailid
left join bi_views.dbo.sfdcMC_Subscriber sub on sub.id=se.SubscriberID
left join sfdcprod.dbo.contact c1 on sub.subscriberkey=c1.id
left join bi_views.dbo.DIM_SERVICE_RF ds on c1.id=ds.ContractSignerContactID_bk
WHERE
e.name like '%Past Due%'
From there, I want to see how many days it took the email receiver to make their first payment following the received email. That's where I've got this:
SELECT
e.*
,z.zuora__createddate__c
,z.zuora__status__c
,z.zuora__amount__c
,datediff(dd,e.sentdate,z.Zuora__CreatedDate__c) DaysToPay
FROM
#temp_billing_emails e
left join sfdcprod.dbo.Service__C sc on e.Service_Num = right(sc.name,len(sc.name)-2)
left join sfdcprod.dbo.[zuora__customeraccount__c] a on sc.billing_account__c=a.id
left join sfdcprod.dbo.[zuora__payment__c] z on a.id=z.zuora__billingaccount__c
WHERE
datediff(dd,e.sentdate,z.Zuora__CreatedDate__c)>=0
and z.zuora__status__c not like 'Error'
That gets me all payments the customer has made after they received an email. What I need is just their first payment amount and the days it took following the email.
I tried the MIN() function like this:
SELECT TOP 100
e.EmailAddress
,e.SentDate
,e.Service_Num
,z.zuora__createddate__c
,z.zuora__status__c
,z.zuora__amount__c
,datediff(dd,e.sentdate,min(z.Zuora__CreatedDate__c)) DaysToPay
FROM
#temp_billing_emails e
left join sfdcprod.dbo.Service__C sc on e.Service_Num = right(sc.name,len(sc.name)-2)
left join sfdcprod.dbo.[zuora__customeraccount__c] a on sc.billing_account__c=a.id
left join sfdcprod.dbo.[zuora__payment__c] z on a.id=z.zuora__billingaccount__c
WHERE
datediff(dd,e.sentdate,z.Zuora__CreatedDate__c)>=0
and z.zuora__status__c not like 'Error'
GROUP BY
e.EmailAddress
,e.SentDate
,e.Service_Num
,z.zuora__createddate__c
,z.zuora__status__c
,z.zuora__amount__c
Any help would be GREATLY appreciated.
outer apply() is a good solution for this type of problem.
select e.*
, x.*
, DaysToPay = datediff(day,e.sentdate,x.Zuora__CreatedDate__c)
from #temp_billing_emails e
outer apply (
select top 1
z.zuora__createddate__c
, z.zuora__status__c
, z.zuora__amount__c
from sfdcprod.dbo.Service__C sc
inner join sfdcprod.dbo.[zuora__customeraccount__c] a
on sc.billing_account__c=a.id
and ds.Service_Num = right(sc.name,len(sc.name)-2)
inner join sfdcprod.dbo.[zuora__payment__c] z
on a.id=z.zuora__billingaccount__c
and z.zuora__status__c not like 'Error'
and z.Zuora__CreatedDate__c >= se.EventDate
order by z.Zuora__CreatedDate__c asc
) as x
I think this is how it would look without the temp table:
select
e.Name
, se.SubscriberID
, se.SendID
, c1.Id
, ds.Service_Num
, sub.EmailAddress
, se.EventDate as 'SentDate'
, x.zuora__createddate__c
, x.zuora__status__c
, x.zuora__amount__c
, DaysToPay = datediff(day,se.EventDate,x.Zuora__CreatedDate__c)
from bi_views.dbo.sfdcMC_SentEvent se
inner join bi_views.dbo.sfdcmc_job j on j.jobid=se.sendid
inner join bi_views.dbo.sfdcMC_Email e on e.id=j.emailid and e.name like '%Past Due%'
left join bi_views.dbo.sfdcMC_Subscriber sub on sub.id=se.SubscriberID
left join sfdcprod.dbo.contact c1 on sub.subscriberkey=c1.id
left join bi_views.dbo.DIM_SERVICE_RF ds on c1.id=ds.ContractSignerContactID_bk
outer apply (
select top 1
z.zuora__createddate__c
, z.zuora__status__c
, z.zuora__amount__c
from sfdcprod.dbo.Service__C sc
inner join sfdcprod.dbo.[zuora__customeraccount__c] a
on sc.billing_account__c=a.id
and ds.Service_Num = right(sc.name,len(sc.name)-2)
inner join sfdcprod.dbo.[zuora__payment__c] z
on a.id=z.zuora__billingaccount__c
and z.zuora__status__c not like 'Error'
and z.Zuora__CreatedDate__c >= se.EventDate
order by z.Zuora__CreatedDate__c asc
) as x

Group By not working in SQL Server

CREATE VIEW [dbo].[Payment_Transaction_vw]
AS
SELECT payment_trans_id,
Student_Info.student_fname,
Student_Info.student_lname,
Student_Info.ID_Number,
Trimester_Payment.deadline,
Transaction_Info.trans_name,
Payment_Transaction.amount,
Payment_Transaction.date_paid
FROM [Payment_Transaction]
INNER JOIN Student_Info
ON Payment_Transaction.student_info_id = Student_Info.student_info_id
INNER JOIN Trimester_Payment
ON Payment_Transaction.trimester_id = Trimester_Payment.trimester_id
INNER JOIN Transaction_Info
ON Payment_Transaction.trans_info_id = Transaction_Info.trans_info_id
GROUP BY ID_Number,trans_name;
That is my script to make a view in sql server in visual studio, I wanted to group the ID_Number & trans_name which have a repeating values in the table Payment_Transactions. I wanted that this ID_Number with the trans_name will only displayed once. I also want to sum up the amount paid for every ID_number with the same trans_name.
When using group by you want to make sure that any unique value will be aggregated or consolidated so that it can be displayed in one row. As it is right now, payment_trans_id (and others) are still unique and since you chose to display these the group by cannot be done.
What do you want to do with payment_trans_id, date_paid, amount ... all other columns really?
Example using MAX(), MIN() and AVG():
SELECT
MAX(payment_trans_id) AS payment_trans_id,
Transaction_Info.trans_name,
Student_Info.ID_Number,
AVG(Payment_Transaction.amount) AS amount,
MIN(Payment_Transaction.date_paid) AS date_paid
FROM [Payment_Transaction]
INNER JOIN Student_Info ON Payment_Transaction.student_info_id = Student_Info.student_info_id
INNER JOIN Trimester_Payment ON Payment_Transaction.trimester_id = Trimester_Payment.trimester_id
INNER JOIN Transaction_Info ON Payment_Transaction.trans_info_id = Transaction_Info.trans_info_id
GROUP BY ID_Number, trans_name;
For support in EF, perhaps this will be sufficient (perhaps not):
SELECT
ISNULL(MAX(payment_trans_id),0) AS Id,
Transaction_Info.trans_name,
Student_Info.ID_Number,
AVG(Payment_Transaction.amount) AS amount,
MIN(Payment_Transaction.date_paid) AS date_paid
FROM [Payment_Transaction]
INNER JOIN Student_Info ON Payment_Transaction.student_info_id = Student_Info.student_info_id
INNER JOIN Trimester_Payment ON Payment_Transaction.trimester_id = Trimester_Payment.trimester_id
INNER JOIN Transaction_Info ON Payment_Transaction.trans_info_id = Transaction_Info.trans_info_id
GROUP BY ID_Number, trans_name;
You have to aggregate columns that are not in group by clause.
As example, which one of date_paid (for payment_trans_id = 1 and 2) you want to return? 6/25/2015 or 5/6/2015? SQL server cant know, so you get multiple rows.

employee attendance structure using 3 table left innerjoins

SELECT b.Device_Person_ID, a.Personal_id, Date1,
CASE WHEN b.Device_Person_id IS NOT NULL THEN 'A' ELSE 'P' END as Emp_Status
FROM Emp_setting a
LEFT OUTER JOIN (SELECT device_person_id, MAX(logDateTime) AS Date1 FROM tempDeviceLogs
GROUP BY device_person_id) b
ON a.personal_id = b.device_person_id
here i joined only two tables but i need to join 3 tables to show employee details with attendance with specific date.
Required output is
employeename device_person_id designation emptype status
'dbo.persons_profile table
[pesonal_id]
,[Emp_Code]
,[Title]
,[First_name]
,[Middle_name]
,[last_name]
,[Father_Husband_Name]
,[Dob]
,[Age]
,[gender]
,[Marital_status]
,[Nationality]
,[bloodGroup]
,[perAddress]
,[PerStreet]
,[PerLocation]
,[PerCity]
,[PerPincode]
,[CorAddress]
,[CorStreet]
,[CorLocation]
,[CorCity]
,[CorPincode]
,[LandlinePhone]
,[cellNo]
,[EmailId]
,[NosofDependendants]
,[Dependendants_details]
,[Emergency_FirstName]
,[Emergency_Middle_name]
,[Emergency_Last_name]
,[Emergency_WithRelation]
,[Emergency_PhoneNo]
,[Emergency_CellNo]
,[Emergency_emailId]
,[Office_PF_ac_no]
,[ESI_ac_no]
,[JoinedDate]
,[Photofile]
,[ReportTo]
,[Brief_Notes]
,[dateofTermination]
,[termination_note]
,[Print_Priority]
,[DeviceEmployeeID]
,[LogsPermitted]
,[Machin_install_id]
,[Designation]
,[Dept]
,[Section]
,[Groups]
,[EmpWorkingTypeT]'
dbo.tempDeviceLogs table
[LogsID]
,[Device_Person_id]
,[Device_id]
,[logDateTime]
,[logVerifyMode]
,[workCodeID]
,[Machin_install_id]
,[data_loaded_dt]
,[Inout]
dbo.Emp_setting table
[Empset_id]
,[personal_id]
,[DesignationID]
,[DivisionID]
,[Emp_status]
,[Emp_TypeId]
,[Dept_Id]
,[Group_Id]
,[NDIVGRP_CODE]
you need to write to join conditions for achieving what you required.
as an example:
SELECT a.<respective>_id, d.<respective>_title, s.<respective>_id
FROM Emp_setting a
INNER JOIN persons_profile s ON a.<respective>_id = s.<respective>_id
INNER JOIN Emp_setting d ON a.<respective>_id = d.<respective>_id
INNER JOIN tempDeviceLogs b ON s.<respective>_id = b.<respective>_id

Resources