Group by in table - sql-server

My code is :
SELECT
Student_ID ,dbo.tblVahed.Vahed_ID,
COUNT(Student_ID) AS State_All,
CASE
WHEN tblStudentsDocument.Student_Sex = N'مرد'
THEN COUNT(Student_ID)
END AS Count_Man,
CASE
WHEN tblStudentsDocument.Student_Sex = N'زن'
THEN COUNT(Student_ID)
END AS Count_Woman
FROM
dbo.tblStudentsDocument
INNER JOIN
dbo.tblVahed ON dbo.tblStudentsDocument.Vahed_ID = dbo.tblVahed.Vahed_ID
GROUP BY
dbo.tblVahed.Vahed_ID, Student_ID, Student_Sex
but I should group by only dbo.tblVahed.Vahed_ID. Any help appreicated.

Anything that's not aggregated in the SELECT field list must be included in the group by. If you don't want to group by it, then you shouldn't include it in the select list unaggregated. Your query should work as follows.
SELECT dbo.tblVahed.Vahed_ID,
COUNT( Student_ID) AS State_All ,
SUM(CASE WHEN tblStudentsDocument.Student_Sex = N'مرد' THEN 1 ELSE 0 END) AS Count_Man ,
SUM(CASE WHEN tblStudentsDocument.Student_Sex = N'زن' THEN 1 ELSE 0 END) AS Count_Woman
FROM dbo.tblStudentsDocument
INNER JOIN dbo.tblVahed ON dbo.tblStudentsDocument.Vahed_ID = dbo.tblVahed.Vahed_ID
GROUP BY dbo.tblVahed.Vahed_ID
Note I've removed student id, and rewritten the case statement to perform the aggregation in a different way.

Related

Adding together separate values from case expression

This query is bringing up separate Total amounts due to the case statement. Is there an easy way to add them together to show up as one total value?
SELECT
ih.customer_id AS [Customer ID],
customer.customer_name AS [Customer],
COUNT(ih.invoice_no) AS [Orders],
CASE
WHEN il.unit_of_measure = 'IN'
THEN (SUM((il.qty_shipped*12) * il.unit_price))
ELSE SUM(il.qty_shipped * il.unit_price)
END AS [Total]
FROM
invoice_hdr ih
INNER JOIN
invoice_line il ON ih.invoice_no = il.invoice_no
INNER JOIN
customer ON customer.customer_id = ih.customer_id
GROUP BY
ih.customer_id, customer.customer_name, il.unit_of_measure
ORDER BY
ih.customer_id
If you remove the unit_of_measure column from your group by you can refer to it within the sum, can you try the following:
Sum(il.qty_shipped * il.unit_price * case when il.unit_of_measure = 'IN' then 12 else 1 end) end as Total

Group by two columns with case query in SQL Server

I'm trying to retrieve drivers data with Total Accepted and Total Ignored ride requests for the current date.
Based on the Drivers and DriverReceivedRequests tables, I get the total count but the twists is I have duplicate rows that reside on the DriverReceivedRequest table against the driverId and the rideId. So there has to be group by clause on both the driverId and RideId, having the driver getting multiple requests for the current date, but also receiving twice or thrice request for the same ride as well.
This is the table structure for DriverReceivedRequests:
Id DriverId RideId ReceivedStatusId DateTime
------------------------------------------------------------------------
0014d26b 93665f55 fef6fb96 NULL 04:55.6
00175c65 6e62a94e cb214a84 NULL 09:32.1
0017c22b ec9e1297 4b47dc8a 4211357D 10:28:5
0014d26b 6e62a94e fef6fb96 NULL 04:56.8
This is the query I have tried:
select
d.Id, d.FirstName, d.LastName,
Sum(case when drrs.Number = 1 then 1 else 0 end) as TotalAccepted,
Sum(case when drrs.Number = 2 or drr.ReceivedStatusId is null then 1 else 0 end) as TotalRejected
from
dbo.[DriverReceivedRequests] drr
inner join
dbo.[Drivers] d on drr.DriverId = d.Id
left join
dbo.[DriverReceivedRequestsStatus] drrs on drr.ReceivedStatusId = drrs.Id
where
Day(drr.Datetime) = Day(getdate())
and month(drr.DateTime) = Month(getdate())
group by
d.FirstName, d.LastName, d.Id
In the above query if I group by with RideId as well, it generates duplicate names of drivers as well with incorrect data. I've also applied partition by clause with DriverId but not the correct result
This also generates the same result
WITH cte AS
(
SELECT
d.Id,
d.FirstName, d.LastName,
TotalAccepted = SUM (CASE WHEN drrs.Number = 1 THEN 1 ELSE 0 END) OVER (PARTITION BY drr.DriverId),
TotalRejected = SUM (CASE WHEN drrs.Number = 2 OR drr.ReceivedStatusId IS NULL THEN 1 ELSE 0 END)
OVER (PARTITION BY drr.DriverId),
rn = ROW_NUMBER() OVER(PARTITION BY drr.DriverId
ORDER BY drr.DateTime DESC)
FROM
DriverReceivedRequests drr
INNER JOIN
dbo.[Drivers] d ON drr.DriverId = d.Id
LEFT JOIN
dbo.[DriverReceivedRequestsStatus] drrs ON drr.ReceivedStatusId = drrs.Id
WHERE
DAY (drr.Datetime) = DAY (GETDATE())
AND MONTH (drr.DateTime) = MONTH (GETDATE())
)
SELECT
Id,
FirstName, LastName,
TotalAccepted, TotalRejected
FROM
cte
WHERE
rn = 1
My question is how can I group by individual driver data in terms of incoming ride requests?
Note: the driver receives same ride request multiple times

Aggregate function is return incorrect value when joining more table

I am getting the Total sale using the following query.
SELECT SUM([B].[TotalSale])
FROM [dbo].[BookingDetail] [BF] WITH (READPAST)
INNER JOIN [dbo].[Booking] [B] WITH (READPAST) ON [B].[BookingDetailID] = [BF].[ID]
WHERE [BF].[MarketID] = '2'
I want to add another column to get the Gross Sale .
For that I have to make a join with another table called AirTraveler.
But once I add a new table to the query
SELECT
SUM([B].[TotalSale]) ,
SUM(CASE WHEN [B].[TravelSectorID] = 3 AND [B].[BookingStatusID] IN (16, 20, 22, 23) THEN COALESCE([B].[TotalSale], 0.0)
WHEN ([B].[TravelSectorID] = 1 AND [B].[IsDomestic] = 1 AND CONVERT(varchar, [AT].[FareDetails].query('string(/AirFareInfo[1]/PT[1])')) = 'FlightAndHotel') THEN [AT].[TotalSale]
ELSE 0 END) AS [GrossSale]
FROM [dbo].[BookingDetail] [BF] WITH (READPAST)
INNER JOIN [dbo].[Booking] [B] WITH (READPAST) ON [B].[BookingDetailID] = [BF].[ID]
LEFT OUTER JOIN [dbo].[AirTraveler] [AT] WITH(READPAST) ON [B].[ID] = [AT].[BookingID]
WHERE [BF].[MarketID] = '2'
it is giving incorrect result of [TotalSale] .the aggregate functions return wrong values because there may be multiple AirTraveler per Booking ID, which is correct. What can I do to solve the aggregate function problem?
I am actually stuck.
I am using SQL Server .
Thanks in advance.
Not tested or anything, but when you are joining to a lower level table that causes a header table to double count, you can pre-aggregate it before it joins
This is probably missing some opening/closing brackets and aliases but hopefully you can work it out
SELECT
SUM([B].[TotalSale]) ,
SUM(CASE WHEN [B].[TravelSectorID] = 3
AND [B].[BookingStatusID] IN (16, 20, 22, 23)
THEN COALESCE([B].[TotalSale], 0.0)
WHEN ([B].[TravelSectorID] = 1 AND [B].[IsDomestic] = 1
THEN [AT].[TotalSale]
ELSE 0 END) AS [GrossSale]
FROM [dbo].[BookingDetail] [BF] WITH (READPAST)
INNER JOIN [dbo].[Booking] [B] WITH (READPAST) ON [B].[BookingDetailID] = [BF].[ID]
LEFT OUTER JOIN
(
SELECT BookingID, SUM(CASE WHEN
CONVERT(varchar(50), [FareDetails].query('string(/AirFareInfo[1]/PT[1])'))
= 'FlightAndHotel') THEN [TotalSale] ELSE 0 END) TotalSale
FROM [dbo].[AirTraveler] [AT] WITH(READPAST)
GROUP BY BookingID
) AT
ON [B].[ID] = [AT].[BookingID]
WHERE [BF].[MarketID] = '2'
Also I gave your varchar cast a size - I think if you don't do this it'll be 1 so your case is never true

SQL Percentage calculation

Is it possible in SQL to calculate the percentage of the 'StaffEntered' column's "Yes" values (case when calculated column) out of the grand total number of orders by that user (RequestedBy)? I'm basically doing this function now myself in Excel with a Pivot table, but thought it may be easier to build it into the query. Here is the existing sample SQL code:
Select
Distinct
RequestedBy = HStaff.Name,
AccountID = isnull(pv.AccountID, ''),
StaffEntered = Case When DictionaryItem2.Name like '%PLB%' Then 'Yes' Else 'No' end
FROM
[dbo].[HOrd] HOrd WITH ( NOLOCK )
left outer join HStaff HStaff with (nolock)
on HOrd.Requestedby_oid = HStaff.ObjectID
and HStaff.Active = 1
left outer join DictionaryItem DictionaryItem2 WITH (NOLOCK)
ON HSUser1.PreferenceGroup_oid = DictionaryItem2.ObjectID
AND DictionaryItem2.ItemType_oid = 98
Here is what I am doing in Excel currently with the query results, I have a pivot table and I am dividing the "Yes" values of the "StaffEntered" field out of the Grand Total number of entries for that specific "RequestedBy" user. Essentially Excel is doing the summarization and then I am doing a simple division calculation to obtain the percentage.
Thanks in advance!
You didn't provide a lot in the way of details but I think this should be pretty close to what you are looking for.
select HStaff.Name as RequestedBy
, isnull(pv.AccountID, '') as AccountID
, Case When DictionaryItem2.Name like '%PLB%' Then 'Yes' Else 'No' end as StaffEntered
, sum(Case When DictionaryItem2.Name like '%PLB%' Then 1 Else 0 end) / GrandTotal
From SomeTable
group by HStaff.Name
, isnull(pv.AccountID, '')
, GrandTotal
Giving the FROM part of your SQL Statement would allow us to create a more correct answer. This statement will get the totals of yes/no per HStaff name and add it to each detail record in your SQL statement:
WITH cte
AS ( SELECT HStaff.Name ,
SUM(CASE WHEN dictionaryItem2.Name LIKE '%PLB%' THEN 1
ELSE 0
END) AS YesCount ,
SUM(CASE WHEN dictionaryItem2.Name NOT LIKE '%PLB%'
THEN 1
ELSE 0
END) AS NotCount
FROM YourTable
GROUP BY HStaff.Name
)
SELECT HStaff.Name AS requestedBy ,
ISNULL(pv.AccountID, '') AS AccountID ,
CASE WHEN DictionaryItem2.Name LIKE '%PLB%' THEN 'Yes'
ELSE 'No'
END AS StaffEntered ,
cte.YesCount / ( cte.YesCount + cte.NotCount ) AS PLB_Percentage
FROM yourtable
INNER JOIN cte ON yourtable.Hstaff.Name = cte.NAME

Count unique IDs with Case

I have this Query(using SQL Server 2008):
SELECT
ISNULL(tt.strType,'Random'),
COUNT(DISTINCT t.intTestID) as Qt_Tests,
COUNT(CASE WHEN sd.intResult=4 THEN 1 ELSE NULL END) as Positives
FROM TB_Test t
LEFT JOIN TB_Sample s ON t.intTestID=s.intTestID
LEFT JOIN TB_Sample_Drug sd ON s.intSampleID=sd.intSampleID
LEFT JOIN TB_Employee e ON t.intEmployeeID=e.intEmployeeID
LEFT JOIN TB_Test_Type tt ON t.intTestTypeID=tt.intTestTypeID
WHERE
s.dtmCollection BETWEEN '2013-06-01 00:00' AND '2013-08-31 23:59'
AND f.intCompanyID = 91
GROUP BY
tt.strType
The thing is each sample has four records on sample_drug, which represents the drugs tested on that sample. And the result of the sample can be positive from one to four drugs at the same time.
What I need to show in the third column is just if the sample was positive, no matter how many drugs.
And I can't find a way to do that, because i need the CASE WHEN to know that i want all the Results = 4 but just from unique intSampleIDs.
Thanks in advance!
If I understand correctly, the easiest way is to use max() instead of count():
SELECT ISNULL(tt.strType,'Random'),
COUNT(DISTINCT t.intTestID) as Qt_Tests,
max(CASE WHEN sd.intResult = 4 THEN 1 ELSE NULL END) as HasPositives
. . .
EDIT:
If you want the number of samples with a positive result, then use count(distinct) with a case statement.
SELECT ISNULL(tt.strType,'Random'),
COUNT(DISTINCT t.intTestID) as Qt_Tests,
count(distinct CASE WHEN sd.intResult = 4 THEN s.intSampleID end) as NumPositiveSamples
instead of this:
COUNT(CASE WHEN sd.intResult=4 THEN 1 ELSE NULL END) as Positives
try this:
SUM(CASE WHEN sd.intResult=4 THEN 1 ELSE 0 END) as Positives
Should work if i undestood correctly that you want show that a row in TB_Sample_Drug marked with intResult = 4 (1) or not (null) in the positives column.
SELECT
ISNULL(tt.strType,'Random'),
COUNT(DISTINCT t.intTestID) as Qt_Tests,
CASE WHEN sd.Positives > 0 THEN 1 ELSE NULL END as Positives
FROM TB_Test t
LEFT JOIN TB_Sample s ON t.intTestID=s.intTestID
LEFT JOIN TB_Employee e ON t.intEmployeeID=e.intEmployeeID
LEFT JOIN TB_Test_Type tt ON t.intTestTypeID=tt.intTestTypeID
CROSS APPLY (select count(*) as Positives from TB_Sample_Drug sd where s.intSampleID=sd.intSampleID and sd.intResult=4) sd
WHERE
s.dtmCollection BETWEEN '2013-06-01 00:00' AND '2013-08-31 23:59'
AND f.intCompanyID = 91
GROUP BY
tt.strType

Resources