Count records in same column with and without parameter - sql

I am having some trouble with a query and was hoping someone could help. I have tried searching for a solution, but can't seem to find a similar scenario with my search terms.
Here is what I am looking for:
I have a table with three columns and need to return the values in the first column, and two counts of the values in the second column. One count is based on a parameter and the other is the total count. Ideally, I would only like to return the values in column one that have equal counts.
For example:
Part Number | Make ID
ABC123 | 1<br>
ABC123 | 1<br>
ABC123 | 3<br>
DEF456 | 1<br>
DEF456 | 1
Part Number | Count of Apps Where Make ID = 1| Count of Total Apps
ABC123 | 2 | 3
DEF456 | 2 | 2
The query I have so far will return the total count of apps for part numbers that have the parameter value, but I need it to return both counts:
SELECT apps.part#,
COUNT(DISTINCT application#)apps
FROM [mytable] AS apps
INNER JOIN (SELECT part#
FROM [mytable]
WHERE make = '1') AS sz
ON sz.part# = apps.part#
GROUP BY apps.part#
ORDER BY 1
Any help is greatly appreciated!
Thanks, everyone! I received several correct answers, and selected the one that was give first:
SELECT part#,
COUNT(DISTINCT CASE WHEN make = '1' THEN application# END) make1_apps,
COUNT(DISTINCT application#) total_apps
FROM [mytable]
GROUP BY part#
HAVING COUNT(DISTINCT CASE WHEN make = '1' THEN application# END)
= COUNT(DISTINCT application#)
ORDER BY part#
Thanks again!

Try this:
SELECT
apps.part#
, COUNT(*)
, SUM(CASE WHEN make = '1' THEN 1 ELSE 0 END)
FROM [mytable]
GROUP BY apps.part#
This solution replaces counting with calculating a sum, and supplying 1 for matching items and 0 for non-matching ones.
To filter out the records where the two counts are different, add a HAVING clause:
SELECT
apps.part#
, COUNT(*)
, SUM(CASE WHEN make = '1' THEN 1 ELSE 0 END)
FROM [mytable]
GROUP BY apps.part#
HAVING SUM(CASE WHEN make = '1' THEN 1 ELSE 0 END) = COUNT(*)

SELECT [Part Number],
SUM(CASE WHEN [Make ID] = 1 THEN 1 ELSE 0 END),
COUNT(*)
FROM tableName
GROUP BY [Part Number]
SQLFiddle Demo
UPDATE 1
SELECT [Part Number],
SUM(CASE WHEN [Make ID] = 1 THEN 1 ELSE 0 END),
COUNT(*)
FROM tableName
GROUP BY [Part Number]
HAVING SUM(CASE WHEN [Make ID] = 1 THEN 1 ELSE 0 END) = COUNT(*)
SQLFiddle Demo

another way more similar to yours:
select d.[Part Number], count(d.[Part Number]), o.ones
from
data d
cross apply
(
select count(*)
from data d2
where d2.[Part Number] = d.[Part Number]
and d2.[Make ID] = 1
) o (ones)
group by d.[Part Number], o.ones
SQLFiddle
to fullfill your second request add:
having count(d.[Part Number]) = o.ones

SELECT part#,
COUNT(DISTINCT CASE WHEN make = '1' THEN application# END) make1_apps,
COUNT(DISTINCT application#) total_apps
FROM [mytable]
GROUP BY part#
HAVING COUNT(DISTINCT CASE WHEN make = '1' THEN application# END)
= COUNT(DISTINCT application#)
ORDER BY part#;
The HAVING clause ensures the two counts match.

Related

Single SQL query for getting count based of 2 condition in same table

I have data like this
Now I need a single query to get count of id where Info is 'Yes' and count of id which are in both 'yes' and 'no'
Single query for:
SELECT COUNT(id) FROM table WHERE info = 'yes'
and
SELECT COUNT(id) FROM table WHERE info = 'yes' AND info = 'No'
Since
Id having Yes are 7 (1,2,3,4,5,6,7)
and Id having and Yes and No both vaules are only 3 (1,4, 6)
it should give me id_as_yes = 7 and id_as_yes_no = 3
You can do it with aggregation and window functions:
SELECT DISTINCT
SUM(MAX(CASE WHEN info = 'yes' THEN 1 ELSE 0 END)) OVER () id_as_yes,
COUNT(CASE WHEN COUNT(DISTINCT info) = 2 THEN 1 END) OVER () id_as_yes_no
FROM tablename
GROUP BY id
See the demo.
Results:
> id_as_yes | id_as_yes_no
> --------: | -----------:
> 7 | 3
You need conditional aggregation.
Select id,
Count(case when info = 'y' then 1 end) as y_count,
Count(case when info = 'y' and has_n = 1 then 1 end) as yn_count
From (SELECT id, info,
Max(case when info = 'no' then 1 end) over (partirion by id) as has_n
From your_table) t
You can do this without a subquery. This relies on the observation that the number of ids that are "no" only is:
count(distinct id) - count(distinct case when info = 'yes' then id end)
And similarly for the number of yeses. So, the number that have both is the number of ids minus the number of no only minus the number of yes only:
select count(distinct case when info = 'yes' then id end) as num_yeses,
(count(distinct id) -
(count(distinct id) - count(distinct case when info = 'yes' then id end)) -
(count(distinct id) - count(distinct case when info = 'no' then id end))
)
from t;
This should do the trick...it's definitely not efficient or elegant, but no null value aggregate warnings
dbFiddle link
Select
(select count(distinct id) from mytest where info = 'yes') as yeses
,(select count(distinct id) from mytest where info = 'no' and id in (select distinct id from mytest where info = 'yes' )) as [yes and no]

Pivot Multiple columns together in SQL

I've table like this
I need to get a result like this
RT Team PI Committed Done-Partial Done-Full
----------------------------------------------------------------
ART1 Team1 10 5 1 3
ART2 Team2 7 5 4 1
-----------------------------------------------------------------------
The way I tried is as follows
;with RecentPI as(
select * from (
select rt,Team,pi,[Finish Date],DENSE_RANK() over( partition by rt order by [Finish Date] desc) PIRank from Schedule_Manual S inner join TFS_ARTs_Teams T on T.ART=S.RT
group by RT,Team,PI,[Finish Date]
)tbl
where PIRank=1
)
select * from (select Obj.RT,Obj.[TFS Team], Obj.Type,Obj.PI,[PI Status] from Objectives Obj inner join RecentPI RP on RP.RT=Obj.RT and RP.Team=Obj.[TFS Team] and RP.PI=Obj.PI) as query
PIVOT (count(type) for [Type] in ([Committed])) p1
PIVOT (Count([PI Status]) for [pi status] in ([Done-Partial],[Done-Full])) p2
But it doesnt seems to be correct and also Im not getting full columns in the query. Sorry Im very beginner with SQL Pivot
You can Use this simple Query...your problem will be solved....
select RT,Team,[PI],
sum(case when [Type] = 'Committed' then 1 else 0 end) AS 'Committed',
sum(case when PIStatus = 'Done-Partial' then 1 else 0 end) AS 'Done-Partial',
sum(case when PIStatus = 'Done-Full' then 1 else 0 end) AS 'Done-Full'
from tbl_Pivot
group by RT,Team,[PI]
Output:-

Sum a column and perform more calculations on the result? [duplicate]

This question already has an answer here:
How to use an Alias in a Calculation for Another Field
(1 answer)
Closed 3 years ago.
In my query below I am counting occurrences in a table based on the Status column. I also want to perform calculations based on the counts I am returning. For example, let's say I want to add 100 to the Snoozed value... how do I do this? Below is what I thought would do it:
SELECT
pu.ID Id, pu.Name Name,
COUNT(*) LeadCount,
SUM(CASE WHEN Status = 'Working' THEN 1 ELSE 0 END) AS Working,
SUM(CASE WHEN Status = 'Uninterested' THEN 1 ELSE 0 END) AS Uninterested,
SUM(CASE WHEN Status = 'Converted' THEN 1 ELSE 0 END) AS Converted,
SUM(CASE WHEN SnoozedId > 0 THEN 1 ELSE 0 END) AS Snoozed,
Snoozed + 100 AS Test
FROM
Prospects p
INNER JOIN
ProspectsUsers pu on p.OwnerId = pu.SalesForceId
WHERE
p.Store = '108'
GROUP BY
pu.Name, pu.Id
ORDER BY
Name
I get this error:
Invalid column name 'Snoozed'.
How can I take the value of the previous SUM statement, add 100 to it, and return it as another column? What I was aiming for is an additional column labeled Test that has the Snooze count + 100.
You can't use one column to create another column in the same way that you are attempting. You have 2 options:
Do the full calculation (as #forpas has mentioned in the comments above)
Use a temp table or table variable to store the data, this way you can get the first 5 columns, and then you can add the last column or you can select from the temp table and do the last column calculations from there.
You can not use an alias as a column reference in the same query. The correct script is:
SELECT
pu.ID Id, pu.Name Name,
COUNT(*) LeadCount,
SUM(CASE WHEN Status = 'Working' THEN 1 ELSE 0 END) AS Working,
SUM(CASE WHEN Status = 'Uninterested' THEN 1 ELSE 0 END) AS Uninterested,
SUM(CASE WHEN Status = 'Converted' THEN 1 ELSE 0 END) AS Converted,
SUM(CASE WHEN SnoozedId > 0 THEN 1 ELSE 0 END)+100 AS Snoozed
FROM
Prospects p
INNER JOIN
ProspectsUsers pu on p.OwnerId = pu.SalesForceId
WHERE
p.Store = '108'
GROUP BY
pu.Name, pu.Id
ORDER BY
Name
MSSQL does not allow you to reference fields (or aliases) in the SELECT statement from within the same SELECT statement.
To work around this:
Use a CTE. Define the columns you want to select from in the CTE, and then select from them outside the CTE.
;WITH OurCte AS (
SELECT
5 + 5 - 3 AS OurInitialValue
)
SELECT
OurInitialValue / 2 AS OurFinalValue
FROM OurCte
Use a temp table. This is very similar in functionality to using a CTE, however, it does have different performance implications.
SELECT
5 + 5 - 3 AS OurInitialValue
INTO #OurTempTable
SELECT
OurInitialValue / 2 AS OurFinalValue
FROM #OurTempTable
Use a subquery. This tends to be more difficult to read than the above. I'm not certain what the advantage is to this - maybe someone in the comments can enlighten me.
SELECT
5 + 5 - 3 AS OurInitialValue
FROM (
SELECT
OurInitialValue / 2 AS OurFinalValue
) OurSubquery
Embed your calculations. opinion warning This is really sloppy, and not a great approach as you end up having to duplicate code, and can easily throw columns out-of-sync if you update the calculation in one location and not the other.
SELECT
5 + 5 - 3 AS OurInitialValue
, (5 + 5 - 3) / 2 AS OurFinalValue
You can't use a column alias in the same select. The column alias do not precedence / sequence; they are all created after the eval of the select result, just before group by and order by.
You must repeat code :
SELECT
pu.ID Id,pu.Name Name,
COUNT(*) LeadCount,
SUM(CASE WHEN Status = 'Working' THEN 1 ELSE 0 END) AS Working,
SUM(CASE WHEN Status = 'Uninterested' THEN 1 ELSE 0 END) AS Uninterested,
SUM(CASE WHEN Status = 'Converted' THEN 1 ELSE 0 END) AS Converted,
SUM(CASE WHEN SnoozedId > 0 THEN 1 ELSE 0 END) AS Snoozed,
SUM(CASE WHEN SnoozedId > 0 THEN 1 ELSE 0 END)+ 100 AS Test
FROM
Prospects p
INNER JOIN
ProspectsUsers pu on p.OwnerId = pu.SalesForceId
WHERE
p.Store = '108'
GROUP BY
pu.Name, pu.Id
ORDER BY
Name
If you don't want to repeat the code, use a subquery
SELECT
ID, Name, LeadCount, Working, Uninterested,Converted, Snoozed, Snoozed +100 AS test
FROM
(SELECT
pu.ID Id,pu.Name Name,
COUNT(*) LeadCount,
SUM(CASE WHEN Status = 'Working' THEN 1 ELSE 0 END) AS Working,
SUM(CASE WHEN Status = 'Uninterested' THEN 1 ELSE 0 END) AS Uninterested,
SUM(CASE WHEN Status = 'Converted' THEN 1 ELSE 0 END) AS Converted,
SUM(CASE WHEN SnoozedId > 0 THEN 1 ELSE 0 END) AS Snoozed
FROM Prospects p
INNER JOIN ProspectsUsers pu on p.OwnerId = pu.SalesForceId
WHERE p.Store = '108'
GROUP BY pu.Name, pu.Id) t
ORDER BY Name
or a view

SQL query for count all(unknown, known), unknown, known customer, identify uniquely by Phone Mac address

Table 1(Customer Table)
Id, CustomerId, IsKnownCustomer,phonemacaddress
1, NULL 0 00:9a:34:cf:a4
2, 004024 1 00:6f:64:cf:a0:93
3, 004024 1 00:6f:64:cf:a0:93
4, 004003 1 2c:0e:3d:15:12:43
6, NULL 0 2c:0e:3d:15:125
7, 004003 1 34:f3:9a:ee:53:a9
8, 004023 1 38:0B:40:DC:BA:3A
9, NULL 0 4c:66:41:11:26:16
This is the table, and data is required for all customer, unknown customer and known customer.
output like: uniquely find the records by phonemacaddress.
count Customer,| customer type|
7 all
3 unknown customer
4 known customer
You could use union and count
select count(*), 'all'
from customer
union
select count(*), 'unknown customer'
from customer
where isKnowCustomer = 0
union
select count(*), 'known customer'
from customer
where isKnowCustomer = 1
I would just put this in one row:
select count(*) as all,
sum(IsKnownCustomer) as known,
sum(1 - IsKnownCustomer) as unknown
from t;
I'm not sure why you would want three rows rather than three columns.
If you do, you can do:
select (case when isKnownCustomer = 0 then 'Unknown'
when isKnownCustomer = 1 then 'Known'
else 'All'
end) as which, count(*)
from t
group by grouping sets ( (IsKnownCustomer), () )
Below SQL would help you.
SELECT
SUM(CASE WHEN Isknown = 1 THEN 1 ELSE 0 END) AS 'Known Customer',
SUM(CASE WHEN Isknown = 0 THEN 1 ELSE 0 END) AS 'Unknown Customer',
COUNT(*) AS 'All'
FROM YourTable
You can aggregate the table with one scan, then use UNPIVOT.
SELECT [count customer], [customer type]
FROM ( --aggregations will be placed side-by-side
SELECT COUNT(*) [all]
,COUNT(CASE WHEN IsKnownCustomer = 0 THEN 1 END) [unknown customer]
,COUNT(CASE WHEN IsKnownCustomer = 1 THEN 1 END) [known customer]
FROM CustomerTable
) AS dT
UNPIVOT( --unpivot, will separate aggregations by row
[count customer] FOR [customer type] IN ([all], [unknown customer], [known customer])
) AS unp
Creates Output:
count customer customer type
9 all
3 unknown customer
6 known customer
Here is the full code in SQL fiddle: http://sqlfiddle.com/#!6/54e54/2/0

What does a multiple count query in SQL return?

I have a product table and every product might be delivered, idle, shipping, preparing.
I want to show a list with the counts of products for each state, and I can see how to query for that here:
How to get multiple counts with one SQL query?
However, what does this query return, and how do I assign the return value to lets say, 4 integers, called deliveredCount, idleCount, shippingCount, preparingCount?
PS: For the record, I am using SQLite with OrmLite in Android with JAVA
EDIT: In this SO question people explain what Query to do when you want to get multiple counts, but they don't tell us what does that query return and in what format. For example:
SELECT a.distributor_id,
(SELECT COUNT(*) FROM myTable WHERE level='personal' and distributor_id = a.distributor_id) as PersonalCount,
(SELECT COUNT(*) FROM myTable WHERE level='exec' and distributor_id = a.distributor_id) as ExecCount,
(SELECT COUNT(*) FROM myTable WHERE distributor_id = a.distributor_id) as TotalCount
FROM myTable a ;
What is the return type of this and what is the format?
PS2: Someone was really quick to downvote my question because it lacked sufficient information. Then I edited it, but the downvote still remains :(
Hard to say for sure but sounds like you need to use a version of the top answer in the link you have provided.
Something like;
SELECT ProductID,
COUNT(*) AS Total,
SUM(CASE WHEN pStatus = 'delivered' THEN 1 ELSE 0 END) DeliveredCount,
SUM(CASE WHEN pStatus = 'idle' THEN 1 ELSE 0 END) IdleCount,
SUM(CASE WHEN pStatus = 'shipping' THEN 1 ELSE 0 END) ShippingCount,
SUM(CASE WHEN pStatus = 'preparing' THEN 1 ELSE 0 END) PreparingCount
FROM ProductTable
GROUP BY ProductID
This will return something like;
ProductID | DeliveredCount | IdleCount | ...
1 | 250 | 3250 | ...
You might want to try this.
SELECT
SUM(CASE WHEN Prod = 'delivered' THEN 1 ELSE 0 END) as deliveredCount,
SUM(CASE WHEN Prod = 'idle' THEN 1 ELSE 0 END) as idleCount,
SUM(CASE WHEN Prod = 'shipping' THEN 1 ELSE 0 END) as shippingCount,
SUM(CASE WHEN Prod = 'preparing' THEN 1 ELSE 0 END) as preparingCount
FROM Product
select
concat(state, "Count"),
count(*)
from product
group by state
Which would return 4 rows (assuming four unique values of state):
fooCount | 15
etc