Adding together separate values from case expression - sql-server

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

Related

Sum group of rows based on value in a column

I am new to SQL and I have the below tables
that I need to select and get the desired result below.
Try a query like below.
select
[Account Group] =AG.Name,
[Ledger Name] =AL.Name,
DR =SUM(CASE WHEN TT.Name='DR' THEN Amount ELSE NULL END),-- case based SUM expression
CR =SUM(CASE WHEN TT.Name='CR' THEN Amount ELSE NULL END)
from Account_Group AG
join Account_ledgers AL -- NOTE we have used INNER JOIN throughout
on AG.Id=AL.AccountGroupId
join Transactions T
on T.AccountLedgerId=AL.Id
join Transaction_Type TT
on TT.Id= T.TransactionTypeId
group by AG.Name,AL.Name -- Group by contains all the things we need in SELECT list

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 use GROUPING function in SQL common table expression - CTE

I have the below T-SQL CTE code where i'm trying to do some row grouping on four columns i.e Product, ItemClassification, Name & Number.
;WITH CTE_FieldData
AS (
SELECT
CASE(GROUPING(M.CodeName))
WHEN 0 THEN M.CodeName
WHEN 1 THEN 'Total'
END AS Product,
CASE(GROUPING(KK.ItemClassification))
WHEN 0 THEN KK.[ItemClassification]
WHEN 1 THEN 'N/A'
END AS [ItemClassification],
CASE(GROUPING(C.[Name]))
WHEN 0 THEN ''
WHEN 1 THEN 'Category - '+ '('+ItemClassification+')'
END AS [Name],
CASE(GROUPING(PYO.Number))
WHEN 0 THEN PYO.Number
WHEN 1 THEN '0'
END AS [Number],
ISNULL(C.[Name],'') AS ItemCode,
MAX(ISNULL(PYO.Unit, '')) AS Unit,
MAX(ISNULL(BT.TypeName, '')) AS [Water Type],
MAX(ISNULL(PYO.OrderTime, '')) AS OrderTime,
MAX(ISNULL(BUA.Event, '')) AS Event,
MAX(ISNULL(PYO.Remarks, '')) AS Remarks,
GROUPING(M.CodeName) AS ProductGrouping,
GROUPING(KK.ItemClassification) AS CategoryGrouping,
GROUPING(C.[Name]) AS ItemGrouping
FROM CTable C INNER JOIN CTableProducts CM ON C.Id = CM.Id
INNER JOIN MyData R ON R.PId = CM.PId
INNER JOIN MyDataDetails PYO ON PYO.CId = C.CId AND PYO.ReportId = R.ReportId
INNER JOIN ItemCategory KK ON C.KId = KK.KId
INNER JOIN Product M ON R.ProductId = M.ProductId
INNER JOIN WaterType BT ON PYO.WId = BT.WId
INNER JOIN WaterUnit BUA ON PYO.WUId = BUA.WUId
WHERE R.ReportId = 4360
GROUP BY M.CodeName, KK.ItemClassification, C.Name, PYO.Number
WITH ROLLUP
)
SELECT
Product,
[Name] AS Category,
Number,
Unit as ItemCode,
[Water Type],
OrderTime,
[Event],
[Comment]
FROM CTE_FieldData
Below are the issues/problems with the data being returned by the script above and they are the ones i'm trying to fix.
At the end of each ItemClassification grouping, i extra record is being added yet it does not exist in the table. (See line number 4 & 10 in the sample query results screenshot attached).
I want the ItemClassification grouping in column 2 to be at the beginning of the group not at the end of the group.
That way, ItemClassification "Category- (One)" would be at line 1 not the current line 5.
Also ItemClassification "Category- (Two)" would be at line 5 not the current line 11
Where the "ItemClassification" is displaying i would like to have columns (Number, ItemCode, [Water Type], [OrderTime], [Event], [Comment]) display null.
In the attached sample query results screenshot, those would be rows 11 & 5
The last row (13) is also unwanted.
I'm trying to understand SQL CTE and the GROUPING function but i'm not getting things right.
It looks like this is mostly caused by WITH ROLLUP and GROUPING. ROLLUP allows you to make essentially a sum line for your groupings. When you have WITH ROLLUP, it will give you NULL values for all of your non-aggregated fields in your select statement. You use GROUPING() in conjunction with ROLLUP to then label those NULL's as 'Total' or '0' or 'Category' as your query does.
1) Caused by GROUPING and ROLLUP. Take away both and this should be resolved.
2) Not sure what determines your groups and what would be defined as beginning or end. Order BY should suffice
3) Use ISNULL or CASE WHEN. If the Item Classification has a non null or non blank value, NULL each field out.
4) Take off WITH ROLLUP.

SQL Inner join show numeric value once

I know my question is not very logical but I have the folowing chalenge:
HeadTab (Uniq_Id N(10)
Name C(30)
Tax N(18,2))
TrsTab (Uniq_Id N(10)
MonthlyDesc C(20)
Amount N(18,2))
What I want is the following select * from headtab inner join Trstab on uniq_id = Uniq_id
the issue is that I want to see the tax field only once per name other related should be 0...(Eventhough I have many lines in the details tab).
Thank you for any help
If you give the query a row number to determine the first row for each Name you can use a case statement to select which value you want for Tax.
SELECT
ht.Uniq_ID,
ht.NAME,
(CASE WHEN ROW_NUMBER() OVER (PARTITION BY ht.NAME ORDER BY ht.Uniq_ID) = 1 THEN ht.Tax ELSE 0 END) Tax,
tt.*
FROM
headtab ht
INNER JOIN Trstab tt ON ht.uniq_id = tt.Uniq_id

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