SQL: Multiple select that differ by only one condition - sql

I've got a beginner question. My SQL table looks like:
| Date | Type | Manufacturer |
2016/04/01 A X
2016/04/01 B Y
2016/04/02 B X
2016/05/07 A Z
... ... ...
My aim is to count the quantity of "Types" by manufacturers between two dates. I would like to get a result like following:
| Manufacturer | Quantity_TypeA | Quantity_TypeB |
X 1 1
Y 0 1
Z 1 0
My query looks like:
select Manufacturer as Manufacturer,
COUNT(*) as Quantity_TypeA
From MyTable
Where [Type] = 'A' and
Date between '20150101' and '20160930',
COUNT(*) as Quantity_TypeB
From MyTable
Where [Type] = 'B' and
Date between '20150101' and '20160930'
group by Manufacturer Order by Quantity_TypeA DESC
I have also tried to use functions like CASE on the Type and it didn't work. I am missing something but what?

Try this
select Manufacturer as Manufacturer,
SUM(case when [Type] = 'A' then 1 else 0 end) as Quantity_TypeA,
SUM(case when [Type] = 'B' then 1 else 0 end) as Quantity_TypeB
From MyTable
Where
Date between '20150101' and '20160930'
group by Manufacturer

Use case expressions to do conditional counting:
select Manufacturer as Manufacturer,
COUNT(case when [Type] = 'A' then 1 end) as Quantity_TypeA,
COUNT(case when [Type] = 'B' then 1 end) as Quantity_TypeB
from MyTable
where Date between '20150101' and '20160930',
group by Manufacturer
order by Quantity_TypeA DESC
count() does only count non-null values. The case expressions either return 1 or null, i.e. only A's or B's are counted.

Related

Oracle SQL Developer question from newbie

Sorry could not think of more descriptive title. I have data that looks like:
MEMBERID
TICKETID
STATUS
A
123
Y
A
012
N
A
456
Y
B
XYZ
N
B
ABC
N
C
DEF
Y
C
789
Y
I want to separate the above into three tables:
(1) Members that ONLY have tickets with Status=Y
(2) Members that have mixed status tickets (so at least one ticket with status=Y and at least one ticket with status=N)
(3) Members that ONLY have tickets with Status=N
In Excel I would just do a pivot table that results in something like:
MEMBERID
"Y"
"N"
A
2
1
B
0
2
C
2
0
...then add a 4th column with a formula that allows me to separate member IDs by "Only Y", "Only N", and "Y/N". I'm new to SQL though, and can't seem to get "pivot" to run correctly, or maybe there's a "where" clause that could resolve this without using pivot? Help!
You could pivot but it's probably simpler to just do the aggregation yourself:
select memberid,
count(case when status = 'Y' then ticketid end) as y,
count(case when status = 'N' then ticketid end) as n
from your_table
group by memberid
order by memberid;
To get the fourth column you can either repeat the counts within another case expression:
select memberid,
count(case when status = 'Y' then ticketid end) as y,
count(case when status = 'N' then ticketid end) as n,
case
when count(case when status = 'Y' then ticketid end) > 0
and count(case when status = 'N' then ticketid end) > 0
then 'Y/N'
when count(case when status = 'Y' then ticketid end) > 0
then 'Only Y'
when count(case when status = 'N' then ticketid end) > 0
then 'Only N'
end as yn
from your_table
group by memberid
order by memberid;
Or put the initial query into a CTE or inline view which is clearer and has less repetition, so easier to maintain:
select memberid, y, n,
case
when y > 0 and n > 0 then 'Y/N'
when y > 0 then 'Only Y'
when n > 0 then 'Only N'
end as yn
from (
select memberid,
count(case when status = 'Y' then ticketid end) as y,
count(case when status = 'N' then ticketid end) as n
from your_table
group by memberid
)
order by memberid;
Either way you end up with:
MEMBERID Y N YN
-------- - - ------
A 2 1 Y/N
B 0 2 Only N
C 2 0 Only Y
SQL Fiddle

Flag=1/0 based on multiple criteria on same column

I have a temp table that is being created, we will say that column 1 is YearMonth, column2 as user_id, Column 3 is Type.
YearMonth User_id Type
200101 1 x
200101 2 y
200101 2 z
200102 1 x
200103 2 x
200103 2 p
200103 2 q
I want to count userids based on flag based on type. Hence I am trying to set flag to 1 and 0 but it always results in 0.
So for e.g. when the type contains x or y or z AND type contains P or Q then flag=1 by YearMonth.
I am trying something like
SELECT count (distinct t1.user_id) as count,
t1.YearMonth,
case when t1.type in ('x','y','z')
and
t1.type in ('p','q') then 1 else 0 end as flag
FROM table t1
group by 2,3;
I would like to know why it doesn't give output as below:
count YearMonth Flag
0 200001 1
2 200001 0
1 200002 1
1 200002 0
What am I missing here? Thanks
If I follow you correctly, you can use two levels of aggregation:
select yearmonth, flag, count(*) cnt
from (
select yearmonth, id,
case when max(case when t1.type in ('x', 'y', 'z') then 1 else 0 end) = 1
and max(case when t1.type in ('p', 'q') then 1 else 0 end) = 1
then 1
else 0
end as flag
from mytable
group by yearmonth, id
) t
group by yearmonth, flag
This first flags users for each month, using conditional aggregation, then aggregates by flag and month.
If you also want to display 0 for flags that do not appear for a given month, then you can generate the combinations with a cross join first, then brin the above resultset with a left join:
select y.yearmonth, f.flag, count(t.id) cnt
from (select distinct yearmonth from mytable) y
cross join (values (0), (1)) f(flag)
left join (
select yearmonth, id,
case when max(case when t1.type in ('x', 'y', 'z') then 1 else 0 end) = 1
and max(case when t1.type in ('p', 'q') then 1 else 0 end) = 1
then 1
else 0
end as flag
from mytable
group by yearmonth, id
) t on t.yearmonth = y.yearmonth and t.flag = f.flag
group by y.yearmonth, f.flag
I thought a very similar idea as GMB, however, like him, I don't get the expected results. Likely, however, we both are assuming the expected results are wrong:
SELECT COUNT(DISTINCT UserID) AS [Count],
YearMonth,
CASE WHEN COUNT(CASE WHEN [Type] IN ('x','y','z') THEN 1 END) > 0
AND COUNT(CASE WHEN [Type] IN ('p','q') THEN 1 END) > 0 THEN 1 ELSE 0
END AS Flag
FROM (VALUES(200101,1,'x'),
(200101,2,'y'),
(200101,2,'z'),
(200102,1,'x'),
(200103,2,'x'),
(200103,2,'p'),
(200103,2,'q')) V(YearMonth,UserID,[Type])
GROUP BY YearMonth;

Combine multiple rows into 1 row

Say for example I have a table that contains a description of a customer's activities while in a cafe. (Metaphor of the actual table I am working on)
Customer Borrowed Book Ordered Drink Has Company
1 1
1 1
1 Yes
2 1
3 1
3 Yes
4 1 1
4 1
I wish to combine the rows in this way
Customer Borrowed Book Ordered Drink Has Company
1 1 1 Yes
2 1
3 1 Yes
4 1 2
I did self join with coalesce, but it did not give my desired results.
You can do this by group by,
select Customer,sum([borrowed book]), sum([ordered drink]), max([has company])
from customeractivity group by Customer
As per your comment, initial table is a temp table,
Try to make the result as a cte result, then do aggregation on that, like the below query.
; WITH cte_1
AS
( //your query to return the result set)
SELECT customer,sum([borrowed book]) BorrowedBook,
sum([ordered drink]) OrderedDrink,
max([has company]) HasCompany
FROM cte_1
GROUP BY Customer
Use Group By:
DECLARE #tblTest as Table(
Customer INT,
BorrowedBook INT,
OrderedDrink INT,
HasCompany BIt
)
INSERT INTO #tblTest VALUES
(1,1,NULL,NULL)
,(1,NULL,1,NULL)
,(1,NULL,NULL,1)
,(2,NULL,1,NULL)
,(3,NULL,1,NULL)
,(3,NULL,NULL,1)
,(4,1,1,NULL)
,(4,NULL,1,NULL)
SELECT
Customer,
SUM(ISNULL(BorrowedBook,0)) AS BorrowedBook,
SUM(ISNULL(OrderedDrink,0)) AS OrderedDrink,
CASE MIN(CAST(HasCompany AS INT)) WHEN 1 THEN 'YES' ELSE '' END AS HasCompany
FROM #tblTest
GROUP BY Customer
Not sure, why you are getting error with group by.
Your coalesce should be correct. Refer below way.
Select customer
, case when [borrowed] = 0 then NULL else [borrowed] end as [borrowed]
, case when [ordered] = 0 then NULL else [ordered] end as [ordered]
, case when [company] = 1 then 'Yes' end as company
from
(
Select customer,
coalesce(
case when (case when borrowed = '' then null else borrowed end) = 1 then 'borrowed' end,
case when (case when ordered = '' then null else ordered end) = 1 then 'ordered' end,
case when (case when company = '' then null else company end) = 'Yes' then 'company' end
) val
from Table
) main
PIVOT
(
COUNT (val)
FOR val IN ( [borrowed], [ordered], [company] )
) piv
OUTPUT:
customer | borrowed | ordered | company
---------------------------------------
1 1 1 Yes
2 NULL 1 NULL
3 NULL 1 Yes

SQL count of values from different columns

I've got a Dog table. Each dog has Breed and can have 0 to 2 photos. I need to recieve count of photos of all dogs for each breed: table with BreedId and matching PhotosCount. So result table should be:
BreedID|PhotosCount
-------------------
1 |3
-------------------
2 |1
-------------------
This should do the trick:
SELECT BreedID AS B, COUNT(Photo1) + COUNT(Photo2) AS C
FROM Dog
GROUP BY BreedID
COUNT aggregate function simply doesn't take into consideration NULL values. If, for a specific BreedID, all values of either Photo1 or Photo2 are NULL, then COUNT returns 0.
This should work in single scan:
SELECT
BreedID,
SUM(CASE WHEN Photo1 IS NOT NULL THEN 1 ELSE 0 END)
+ SUM(CASE WHEN Photo2 IS NOT NULL THEN 1 ELSE 0 END) [Count]
FROM Table
GROUP BY BreedID
Use Group By and SUM Of Photo1 and Photo2:
Note: If you wants the output for each dog you have to include DogId in group clause.
;WITH T AS
(
SELECT
BreedId,
SUM (CASE ISNULL(Photo1,0) WHEN 1 THEN 1 ELSE 0 END) AS Photo1,
SUM (CASE ISNULL(Photo2,0) WHEN 1 THEN 1 ELSE 0 END) AS Photo2
FROM TableName
Group By BreedId
)
SELECT
BreedId,
SUM(Photo1+Photo2) AS TotalPhoto
FROM T
Or Simply
SELECT
BreedId,
SUM (CASE ISNULL(Photo1,0) WHEN 1 THEN 1 ELSE 0 END + CASE ISNULL(Photo2,0) WHEN 1 THEN 1 ELSE 0 END) AS TotalPhoto
FROM TableName
Group By BreedId
SELECT BreedID AS Breed, COUNT(Photo1) + COUNT(Photo2) AS #ofPhotos
FROM Dog
GROUP BY BreedID;

Count Values from Table for each type

I have the following table
UserId [nvarchar(128)], Rating [varchar(170)] :values will be mostly 1,2,3 but can have exceptions
Rating contains 3 values [1,2, or 3]
I want to get a result something like
UserId Count(1's),Count(2's) Count(3's)
1. 1001 10 8 2
2. 1002 5 10 3
Is it possible in a single query
Do a GROUP BY UserId to count for each user-id. Use CASE to count 1's, 2's and 3's separately:
select UserId,
count(case when Rating = 1 then 1 end) as [Count(1's)],
count(case when Rating = 2 then 1 end) as [Count(2's)],
count(case when Rating = 3 then 1 end) as [Count(3's)]
from tablename
group by UserId
Use a CASE statement in each COUNT and then GROUP BY UserId.
SELECT UserId, COUNT(CASE WHEN value = '1' THEN 1 END) AS [Count(1's)], COUNT(CASE WHEN value = '2' THEN 1 END) AS [Count(2's)], COUNT(CASE WHEN value = '3' THEN 1 END) AS [Count(3's)]
FROM yourtable
GROUP BY UserId
Use PIVOT:
SELECT
UserId,
COALESCE([1],0) [Count(1's)],
COALESCE([2],0) [Count(2's)],
COALESCE([3],0) [Count(3's)]
FROM
ýour_table
PIVOT
(COUNT([Rating])
FOR Rating
in([1],[2],[3])
)AS p
ORDER BY
UserId