SQL Percentage calculation - sql-server

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

Related

Select from same column under different conditons

I need to join these two tables. I need to select occurrences where:
ex_head of_family_active = 1 AND tax_year = 2017
and also:
ex_head of_family_active = 0 AND tax_year = 2016
The first time I tried to join these two tables I got the warehouse data
dbo.tb_master_ascend AND warehouse_data.dbo.tb_master_ascend in the from clause have the same exposed names. As the query now shown below, I get a syntax error on the "where". What am I doing wrong? Thank you
use [warehouse_data]
select
parcel_number as Account,
pact_code as type,
owner_name as Owner,
case
when ex_head_of_family_active >= 1
then 'X'
else ''
end 'Head_Of_Fam'
from
warehouse_data.dbo.tb_master_ascend
inner join
warehouse_data.dbo.tb_master_ascend on parcel_number = parcel_number
where
warehouse_data.dbo.tb_master_ascend.tax_year = '2016'
and ex_head_of_family_active = 0
where
warehouse_data.dbo.tb_master_ascend.t2.tax_year = '2017'
and ex_head_of_family_active >= 1
and (eff_from_date <= getdate())
and (eff_to_date is null or eff_to_date >= getdate())
#marc_s I changed the where statements and updated my code however the filter is not working now:
use [warehouse_data]
select
wh2.parcel_number as Account
,wh2.pact_code as Class_Type
,wh2.owner_name as Owner_Name
,case when wh2.ex_head_of_family_active >= 1 then 'X'
else ''
end 'Head_Of_Fam_2017'
from warehouse_data.dbo.tb_master_ascend as WH2
left join warehouse_data.dbo.tb_master_ascend as WH1 on ((WH2.parcel_number = wh1.parcel_number)
and (WH1.tax_year = '2016')
and (WH1.ex_head_of_family_active is null))
where WH2.tax_year = '2017'
and wh2.ex_head_of_family_active >= 1
and (wh2.eff_from_date <= getdate())
and (wh2.eff_to_date is null or wh2.eff_to_date >= getdate())
I would use a CTE to get all your parcels that meet your 2016 rules.
Then join that against your 2017 rules on parcel ID.
I'm summarizing:
with cte as
(
select parcelID
from
where [2016 rules]
group by parcelID --If this isn't unique you will cartisian your results
)
select columns
from table
join cte on table.parcelid=cte.parcelID
where [2017 rules]

Group by in table

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.

How to pivot and get total amount each month

I have data like :
My table
My final results should be like this:
My SQL Statement:
SELECT 'Q'+cast([Month_Quarter] as varchar) Month_Quarter,COALESCE([Zugänge],0) Zugänge,COALESCE([Abgänge],0) Abgänge
FROM
(
SELECT DATEPART(QUARTER,[Monat]) [Month_Quarter],
[Zu-, Abgang],
Count(DISTINCT [Projektdefinition DB]) NoProjects
FROM AbZugänge
GROUP BY DATEPART(QUARTER,[Monat]), [Zu-, Abgang]
) proj
PIVOT (SUM(NoProjects) FOR [Zu-, Abgang] IN (Zugänge, Abgänge)) As pvt
WHERE [Month_Quarter] is not null
ORDER BY Month_Quarter
BUT with this statement I am getting the results without the Amount column Zugang and column Abgang:
How can I edit the statement to get the aggregation amount columns?
I suppose you can just wrap your query inside another select statement, then use GROUP BY. Something like this:
SELECT Month, SUM(ISNULL(column_name,0))
FROM (Your Query in here)
GROUP BY Month
Not sure I understand the point of the PIVOT in your original query. This looks like a typical aggregate is all that is required. See if this is what you need.
SELECT DATENAME(MONTH,Monat) [Month]
, sum(case when [Zu-, Abgang] = 'Zugänge' then [Zu-, Abgang] else 0 end) as Zugänge
, SUM(case when [Zu-, Abgang] = 'Abgänge' then [Zu-, Abgang] else 0 end) as Abgänge
, SUM([GWU aktuell]) as [GWU Total]
, SUM([GWU Planung aktuell]) AS [Plan Total]
, COUNT(DISTINCT [Projektdefinition DB]) NoProjects
FROM AbZugänge
group by DATENAME(MONTH,Monat)

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

How do I pivot this SQL result?

Whats the best way to PIVOT this SQL result? I was wondering if the count(*) can be done as part of the pivot instead of having to group the data prior?
SELECT
e.fullname,
e.BusinessUnit,
COUNT(*) as total
FROM EmpComplaints e
WHERE e.BusinessUnit in ('1-Sales', '2-Tech', '3-Marketing')
GROUP BY e.fullname, e.BusinessUnit
order by e.fullname, e.BusinessUnit
I am basically reporting on each employee the amount of reports they have in each of the three business units: sales, tech, marketing. and looking to get a result that will list fullnames on the left with each name appearing once and each name having a column for ('1-Sales', '2-Tech', '3-Marketing') with a number in it that would be the count(*)
Is this MS SQL Server? This might work, sorry, don't have it running, so can't verify:
select fullname,
sum(case BusinessUnit when '1-Sales' then 1 else 0 end) as Sales,
sum(case BusinessUnit when '2-Tech' then 1 else 0 end) as Tech,
sum(case BusinessUnit when '3-Marketing' then 1 else 0 end) as Marketing
FROM EmpComplaints
GROUP BY fullname;
Here is how to do it in SQL Server 2005/2008:
SELECT
FullName
,[1-Sales]
,[2-Tech]
,[3-Marketing]
FROM
(
SELECT
e.fullname,
e.BusinessUnit,
COUNT(*) AS Total
FROM EmpComplaints e
WHERE e.BusinessUnit in ('1-Sales', '2-Tech', '3-Marketing')
GROUP BY e.fullname,e.BusinessUnit
) AS bu
PIVOT
(
SUM(Total)
FOR BusinessUnit IN ([1-Sales], [2-Tech], [3-Marketing])
) AS pvt
ORDER by fullname

Resources