question on Group by clause in Sql server - sql

Table: Customer
Name Type Amount
James P 125.00
James P 125.00
James P 125.00
James R 225.00
James R 225.00
Rajiv R 155.00
Rajiv R 155.00
Rajiv R 155.00
Rajiv P 150.00
Rajiv P 150.00
Saran R 175.00
In this table structure I want a output which will give each person’s count of P, count of R, sum of Amount where type = P, Sum of amount where type = R
Any clues for me as stuck up with group by did not help me much in this scenario.

If you want the result as separate records, you simply group on the name and type:
select Name, Type, count(*) as Cnt, sum(Amount) as AmountSum
from Customer
Group by Name, Type
order by Name, Type
Result:
Name Type Cnt AmountSum
James P 3 375.00
James R 2 450.00
Rajiv P 2 300.00
Rajiv R 3 465.00
Saran R 1 175.00
If you want the count and sum for a person in the same record, you have to do some comparisons:
select
Name,
count(case Type when 'P' then 1 else null end) as CntP,
sum(case Type when 'P' then Amount else 0 end) as AmountSumP,
count(case Type when 'R' then 1 else null end) as CntR,
sum(case Type when 'R' then Amount else 0 end) as AmountSumR,
from Customer
Group by Name
order by Name
Result:
Name CntP AmountSumP CntR AmountSumR
James 3 375.00 2 450.00
Rajiv 2 300.00 3 465.00
Saran 0 0.00 1 175.00

One query, no CTE, no derived tables:
SELECT
Name,
SUM(CASE WHEN Type = 'P' THEN 1 ELSE 0 END) AS PCount,
SUM(CASE WHEN Type = 'R' THEN 1 ELSE 0 END) AS RCount,
SUM(CASE WHEN Type = 'P' THEN Amount ELSE 0 END) AS PAmount,
SUM(CASE WHEN Type = 'R' THEN Amount ELSE 0 END) AS RAmount
FROM yourTable
GROUP BY Name
using the
CREATE TABLE customer (name varchar(50), type char(1), amount decimal(6,2));
INSERT INTO customer VALUES ('James', 'P', 125.00);
INSERT INTO customer VALUES ('James', 'P', 125.00);
INSERT INTO customer VALUES ('James', 'P', 125.00);
INSERT INTO customer VALUES ('James', 'R', 225.00);
INSERT INTO customer VALUES ('James', 'R', 225.00);
INSERT INTO customer VALUES ('Rajiv', 'R', 155.00);
INSERT INTO customer VALUES ('Rajiv', 'R', 155.00);
INSERT INTO customer VALUES ('Rajiv', 'R', 155.00);
INSERT INTO customer VALUES ('Rajiv', 'P', 150.00);
INSERT INTO customer VALUES ('Rajiv', 'P', 150.00);
INSERT INTO customer VALUES ('Saran', 'R', 175.00);
SELECT
Name,
SUM(CASE WHEN Type = 'P' THEN 1 ELSE 0 END) AS PCount,
SUM(CASE WHEN Type = 'R' THEN 1 ELSE 0 END) AS RCount,
SUM(CASE WHEN Type = 'P' THEN Amount ELSE 0 END) AS PAmount,
SUM(CASE WHEN Type = 'R' THEN Amount ELSE 0 END) AS RAmount
FROM customer
GROUP BY Name
James 3 2 375.00 450.00
Rajiv 2 3 300.00 465.00
Saran 0 1 0.00 175.00

Edited Answer: After gbn pointed out a mistake in my original answer
SELECT name,
SUM( CASE WHEN [type] = 'P' THEN 1 ELSE 0 END) CountOfP ,
SUM( CASE WHEN [type] = 'R' THEN 1 ELSE 0 END) CountOfR,
SUM( CASE WHEN [type] = 'P' THEN Amount End) SumOfP ,
SUM( CASE WHEN [type] = 'R' THEN Amount END) SumOfR
FROM customer
GROUP BY name
Original Answer
SELECT name,
COUNT( CASE WHEN [type] = 'P' THEN 1 ELSE 0 END) CountOfP ,
COUNT( CASE WHEN [type] = 'R' THEN 1 ELSE 0 END) CountOfR,
SUM( CASE WHEN [type] = 'P' THEN Amount End) SumOfP ,
SUM( CASE WHEN [type] = 'R' THEN Amount END) SumOfR
FROM customer
GROUP BY name

Related

How to sum up unique values using case statements having certain conditions

I have a table that may have the same item but with different sizes, I would like to count those items with more than one size (e.g. marvel shirt with S, M sizes will count as "1"), but still be able to count how many S and M. I have 2 outcomes I would like to get. Please see below for more detail.
TABLE B
ITEM_NO ITEM
=========================
3130C MARVEL_SHIRT
1845C SPONGEBOB_BOXERS
A900C CK_COAT
A988C RIDER_JEANS
TABLE C
ITEM_NO SIZE
===============
3130C S
3130C M
1845C M
A900C L
A988C M -
I tried just counting it but it is incorrect since it counts how many distinct sizes are there
select (case substr(item_no, 5, 1)
when 'C' then 'clothes'
when 'T' then 'toys'
else 'misc'
end) inv,
count(item_no) total
,sum (case when C.size = 'S' then 1 else 0 end) AS small
,sum (case when C.size = 'M' then 1 else 0 end) AS med
,sum (case when C.size = 'L' then 1 else 0 end) AS large
,count (distinct C.size) AS multiple_sizes
from B left outer join C on B.item_no = C.item_no
group by substr(item_no, 5, 1);
Actual outcome (incorrect):
INV TOTAL Small Med Large Multiple_Sizes
==========================================================
CLOTHES 4 1 3 1 3
Desired/expected outcome:
INV TOTAL Small Med Large Multiple_Sizes
==========================================================
CLOTHES 4 1 3 1 1
Below is another possible desired outcome given this scenario: What if those with multiple sizes shouldn't be counted separately (i.e. Marvel shirt has multiple sizes, thus it won't count the S or M since it's already counted under Multiple_Sizes)?
INV TOTAL Small Med Large Multiple_Sizes
==========================================================
CLOTHES 4 0 2 1 1
You probably need to group twice (1) by item number (2) by item category:
SELECT SUBSTR(item_no, 5, 1) AS category
, COUNT(*) AS count_products
, SUM(count_small) AS small
, SUM(count_med) AS med
, SUM(count_large) AS large
, SUM(CASE WHEN count_small + count_med + count_large > 1 THEN 1 END) AS has_multiple
FROM (
SELECT b.ITEM_NO
, COUNT(CASE WHEN c.SIZE = 'S' THEN 1 END) AS count_small
, COUNT(CASE WHEN c.SIZE = 'M' THEN 1 END) AS count_med
, COUNT(CASE WHEN c.SIZE = 'L' THEN 1 END) AS count_large
FROM b
LEFT JOIN c ON b.item_no = c.item_no
GROUP BY b.ITEM_NO
) x
GROUP BY SUBSTR(item_no, 5, 1)
| category | count_products | small | med | large | has_multiple |
| C | 4 | 1 | 3 | 1 | 1 |
And the variation:
SELECT SUBSTR(item_no, 5, 1) AS category
, COUNT(*) AS count_products
, SUM(CASE WHEN count_small + count_med + count_large = 1 THEN count_small END) AS small
, SUM(CASE WHEN count_small + count_med + count_large = 1 THEN count_med END) AS med
, SUM(CASE WHEN count_small + count_med + count_large = 1 THEN count_large END) AS large
, SUM(CASE WHEN count_small + count_med + count_large > 1 THEN 1 END) AS has_multiple
FROM (
SELECT b.ITEM_NO
, COUNT(CASE WHEN c.SIZE = 'S' THEN 1 END) AS count_small
, COUNT(CASE WHEN c.SIZE = 'M' THEN 1 END) AS count_med
, COUNT(CASE WHEN c.SIZE = 'L' THEN 1 END) AS count_large
FROM b
LEFT JOIN c ON b.item_no = c.item_no
GROUP BY b.ITEM_NO
) x
GROUP BY SUBSTR(item_no, 5, 1)
| category | count_products | small | med | large | has_multiple |
| C | 4 | 0 | 2 | 1 | 1 |
--creando tabla
create table #temp (itemId int, size nvarchar(1))
--insertando valores
insert into #temp values (1,'S')
insert into #temp values (1,'M')
insert into #temp values (2,'M')
insert into #temp values (3,'L')
insert into #temp values (4,'M')
-- table of Different Item Codes
select
itemId
into #masDeUnItem
from
(select itemId,size from #temp group by itemId,size) t1
group by itemId
having count(1) > 1
-- Variable of Counting different Items
declare #itemsDistintos int
-- Providing Value to Variable
select #itemsDistintos = count(1) from
(
select * from #masDeUnItem
) t1
--Outcome 1
select count(distinct(itemId)) TOTAL
,
sum(case when size = 'S' then 1 else 0 end) SMALL
, sum(case when size = 'M' then 1 else 0 end) MEDIUM
, sum(case when size = 'L' then 1 else 0 end) LARGE
, #itemsDistintos as Multiple_Sizes
from #temp
--Outcome 2
select count(distinct(a.itemId)) TOTAL
,
sum(case when size = 'S' and b.itemId is null then 1 else 0 end) SMALL
, sum(case when size = 'M' and b.itemId is null then 1 else 0 end) MEDIUM
, sum(case when size = 'L' and b.itemId is null then 1 else 0 end) LARGE
, #itemsDistintos as Multiple_Sizes
from #temp a
left join #masDeUnItem b
on a.itemId = b.itemId

How can I retrieve this schema by SQL query?

This is my table and its data :
-------------------------------------
rid mid qty price tname
-------------------------------------
10 A 1000 400 Buy
11 A 2000 420 Buy
12 B 1700 600 Buy
13 A 600 450 Sell
And I want to have such output :
----------------------------------------------------------------
mid SUM_Buy tname SUM_Sell tname SUM_Buy_minus_SUM_Sell
----------------------------------------------------------------
A 3000 Buy 600 Sell 2400
B 1700 Buy NULL NULL NULL
Thank you for updating your question with consumable data. An even better approach is posting ddl and sample data so people can just grab it and roll. I did that for you.
declare #something table
(
rid int
, mid char(1)
, qty int
, price int
, tname varchar(10)
)
insert #something values
(10, 'A', 1000, 400, 'Buy')
, (11, 'A', 2000, 420, 'Buy')
, (12, 'B', 1700, 600, 'Buy')
, (13, 'A', 600 , 450, 'Sell')
In that type of format it is super easy for others to help.
You can solve this using conditional aggregation. I used tname1 and tname2 because outside of SSMS you don't want multiple columns to have the same name. But those are probably just noise and not really needed as they provide no benefit to the results.
select s.mid
, Sum_Buy = sum(case when tname = 'Buy' then qty end)
, tname1 = 'Buy'
, Sum_Sell = sum(case when tname = 'Sell' then qty end)
, tname2 = 'Sell'
, SUM_Buy_minus_SUM_Sell = sum(case when tname = 'Buy' then qty end) - sum(case when tname = 'Sell' then qty end)
from #something s
group by s.mid
order by s.mid
You might try this ( use grouping by mid column with aggregations by contribution of case..when statements ) :
with t(rid,mid,qty,price,tname) as
(
select 10,'A',1000,400,'Buy' union all
select 11,'A',2000,420,'Buy' union all
select 12,'B',1700,600,'Buy' union all
select 13,'A',600,450,'Sell'
)
select t.mid, sum(case when tname='Buy' then qty else 0 end) as SUM_Buy,
min(case when tname='Buy' then tname else null end) as tname,
sum(case when tname='Sell' then qty else null end) as SUM_Sell,
max(case when tname='Sell' then tname else null end) as tname,
(sum(case when tname='Buy' then qty else 0 end) -
sum(case when tname='Sell' then qty else null end)) as
SUM_Buy_minus_SUM_Sell
from t
group by t.mid

Comparing values in two columns and returning values on conditional bases using sql hive

I have two columns, I want to get an output based on a comparative basis of both. My data is somewhat like:
Customer Id status
100 A
100 B
101 B
102 A
103 A
103 B
So a customer can have a status A or B or both, I have to segrerate them on customer id basis for a status. If status A and B then return happy, if only A, return Avg and if only B return Sad.
try the below query,
SELECT DISTINCT Customer_Id,
(CASE WHEN COUNT(*) OVER(PARTITION BY Customer_Id) > 1 THEN 'happy'
WHEN Tstatus = 'A' THEN 'Avg'
ELSE 'Sad'END) AS New_Status
FROM #table1
GROUP BY Customer_Id,Tstatus
if Customer Id and status is a unique combination then
STEP 1: use case to determine a or b
SELECT customer id
,CASE WHEN avg(case when [status] ='A' then 0 else 2 end)
FROM [Your Table]
group by[customer id]
and step 2 will be casing avg into result: like this
SELECT customer id
,CASE WHEN (avg(case when [status] ='A' then 0 else 2 end)) = 1 THEN 'happy' ELSE WHEN (avg(case when [status] ='A' then 0 else 2 end)) = 0 THEN 'Avg' ELSE 'Sad' END
FROM [Your Table]
group by[customer id]
I would do this simply as:
select customer_id,
(case when min(status) <> max(status) then 'happy'
when min(status) = 'A' then 'avg'
else 'sad'
end)
from t
where status in ('A', 'B')
group by customer_id

Case statement with grouping

Can you help me write a SELECT statement that returns a single row having columns for each TypeId involved for the transaction number 55?
CREATE TABLE Types
(
Id INT IDENTITY(1,1) NOT NULL,
Name VARCHAR(100) NOT NULL,
CONSTRAINT PK_Types PRIMARY KEY CLUSTERED(Id)
)
GO
INSERT INTO Types
VALUES
('Type1')
,('Type2')
,('Type3')
,('Type4')
,('Type5')
GO
CREATE TABLE Transactions
(
Id INT IDENTITY(1000,1) NOT NULL,
TypeId INT NULL,
TransactionNumber INT NOT NULL,
Amount MONEY NULL,
DateRecorded DATETIME2 NOT NULL,
CONSTRAINT PK_Transactions PRIMARY KEY CLUSTERED(Id),
CONSTRAINT FK_Types FOREIGN KEY(TypeId) REFERENCES Types(Id)
)
GO
INSERT INTO Transactions
VALUES
(1,55,2555.50,SYSDATETIME())
,(3,55,3555.50,SYSDATETIME())
,(4,55,4555.50,SYSDATETIME())
,(5,55,5555.50,SYSDATETIME())
GO
I need a single row returned for each transaction number in the Transactions table.
What I already tried:
SELECT TransactionNumber
,(CASE WHEN TypeId = 1 THEN Amount ELSE 0 END) AS Type1
,(CASE WHEN TypeId = 2 THEN Amount ELSE 0 END) AS Type2
,(CASE WHEN TypeId = 3 THEN Amount ELSE 0 END) AS Type3
,(CASE WHEN TypeId = 4 THEN Amount ELSE 0 END) AS Type4
,(CASE WHEN TypeId = 5 THEN Amount ELSE 0 END) AS Type5
FROM Transactions
SELECT TransactionNumber
,sum(CASE WHEN TypeId = 1 THEN Amount ELSE 0 END) AS Type1
,sum(CASE WHEN TypeId = 2 THEN Amount ELSE 0 END) AS Type2
,sum(CASE WHEN TypeId = 3 THEN Amount ELSE 0 END) AS Type3
,sum(CASE WHEN TypeId = 4 THEN Amount ELSE 0 END) AS Type4
,sum(CASE WHEN TypeId = 5 THEN Amount ELSE 0 END) AS Type5
FROM Transactions group by TransactionNumber;
I think you can do a PIVOT to get required output:
SELECT *
FROM (
SELECT ty.NAME, ISNULL(Amount,0)Amount
FROM TRANSACTIONS t
INNER JOIN Types ty ON ty.Id = t.TypeId
WHERE TransactionNumber = 55
) sub
PIVOT(
SUM(Amount) FOR [Name] IN ([Type1], [Type2], [Type3], [Type4], [Type5])
) AS pivottable
SQL Fiddle
With conditional aggregation:
select Id,
sum(case TypeId when 1 then Amount end) Type1,
sum(case TypeId when 2 then Amount end) Type2,
...
from Transactions
group by Id
I think this would be the query you are looking for:
SELECT
COUNT(CASE WHEN TypeID = 1 THEN 1 ELSE NULL END) '# Transactions Type 1'
, COUNT(CASE WHEN TypeID = 2 THEN 1 ELSE NULL END) '# Transactions Type 2'
, COUNT(CASE WHEN TypeID = 3 THEN 1 ELSE NULL END) '# Transactions Type 3'
, COUNT(CASE WHEN TypeID = 4 THEN 1 ELSE NULL END) '# Transactions Type 4'
, COUNT(CASE WHEN TypeID = 5 THEN 1 ELSE NULL END) '# Transactions Type 5'
FROM TRANSACTIONS
Where TransactionNumber = 55
You can find a working SQLFiddle here.
EDIT:
After you comment I think what you are actually looking for is SUM().
SELECT TransactionNumber
, SUM(CASE WHEN TypeId = 1 THEN Amount ELSE 0 END) AS Type1
, SUM(CASE WHEN TypeId = 2 THEN Amount ELSE 0 END) AS Type2
, SUM(CASE WHEN TypeId = 3 THEN Amount ELSE 0 END) AS Type3
, SUM(CASE WHEN TypeId = 4 THEN Amount ELSE 0 END) AS Type4
, SUM(CASE WHEN TypeId = 5 THEN Amount ELSE 0 END) AS Type5
FROM Transactions
GROUP BY TransactionNumber
SQLFiddle for 2nd query here.

count(*) based on the gender condition

I have the following table in oracle10g.
state gender avg_sal status
NC M 5200 Single
OH F 3800 Married
AR M 8800 Married
AR F 6200 Single
TN M 4200 Single
NC F 4500 Single
I am trying to form the following report based on some condition. The report should look like the one below. I tried the below query but count(*) is not working as expected
state gender no.of males no.of females avg_sal_men avg_sal_women
NC M 10 0 5200 0
OH F 0 5 0 3800
AR M 16 0 8800 0
AR F 0 12 0 6200
TN M 22 0 4200 0
NC F 0 8 0 4500
I tried the following query but I am not able to count based onthe no.of males and no.of females..
select State, "NO_OF MALES", "$AVG_sal", "NO_OF_FEMALES", "$AVG_SAL_FEMALE"
from(
select State,
to_char(SUM((CASE WHEN gender = 'M' THEN average_price ELSE 0 END)),'$999,999,999') as "$Avg_sal_men,
to_char(SUM((CASE WHEN gender = 'F' THEN average_price ELSE 0 END)), '$999,999,999') as "$Avg_sal_women,
(select count (*) from table where gender='M')"NO_OF MALES",
(select count (*) from table where gender='F')"NO_OF_FEMALES"
from table group by State order by state);
You can use case as an expression (which you already know...). And the subquery is unnecessary.
select State
, sum(case gender when 'M' then 1 else 0 end) as "no.of males"
, sum(case gender when 'F' then 1 else 0 end) as "no.of females"
, to_char(
SUM(
(
CASE
WHEN gender = 'M' THEN average_price
ELSE 0
END
)
)
, '$999,999,999'
) as "Avg_sal_men",
to_char(SUM((CASE WHEN gender = 'F' THEN average_price ELSE 0 END))
,'$999,999,999'
) as "Avg_sal_women"
from table
group by State;
You are Conting by this sub-query select count (*) from table where gender='M' which always count the total number of male in your whole table....and you are doing same for counting female...
So you Can Try like this...
select State, "NO_OF MALES", "$AVG_sal", "NO_OF_FEMALES", "$AVG_SAL_FEMALE"
from(
select State,
to_char(SUM((CASE WHEN gender = 'M' THEN average_price ELSE 0 END)),'$999,999,999') as "$Avg_sal_men",
to_char(SUM((CASE WHEN gender = 'F' THEN average_price ELSE 0 END)), '$999,999,999') as "$Avg_sal_women,
Sum(Case when gender='M' then 1 else 0 end) "NO_OF MALES",
Sum(Case when gender='F' then 1 else 0 end) "NO_OF_FEMALES"
from table group by State order by state);
Try the following.
select state
,sum(case when gender = 'M' then 1 else 0 end) as nof_males
,sum(case when gender = 'F' then 1 else 0 end) as nof_females
,avg(case when gender = 'M' then average_price end) as avg_sal_male
,avg(case when gender = 'F' then average_price end) as avg_sal_female
from table
group
by state;
..add formatting as required.