I want to group by account number, but I am running into problems if I get multiple RATE_CD's for an account - I get a NONCOMPLIANT_CNT of 2, but I want it to be only 1 per account even if there is more than 1 RATE_CD.
Below is the SQL I'm playing around with, any ideas on how I can return the NONCOMPLIANT_CNT per account, and not roll up the count if there is more than 1 RATE_CD?
SELECT ID
,ACCOUNT_NBR SUM(CASE
WHEN GROUP_CD = 'RED'
AND TYPE_CD IN ('CHK')
THEN 1
ELSE 0
END) AS 'COMPLIANT_CNT'
,SUM(CASE
WHEN GROUP_CD = 'RED'
AND TYPE_CD IN (
'CN'
,'RN'
)
AND RATE_CD <> 'BLK'
THEN 1
ELSE 0
END) AS 'NONCOMPLIANT_CNT'
,SUM(CASE
WHEN GROUP_CD = 'RED'
AND TYPE_CD IN (
'CN'
,'RN'
,'CHK'
)
THEN 1
ELSE 0
END) AS 'TOTAL_CNT'
FROM DETAIL
LEFT OUTER JOIN RATE_LOOKUP ACCOUNT_NBR = ACCOUNT_NBR
GROUP BY ID
,ACCOUNT_NBR
,RATE_CD
If you only want 1 instead of how many actual, change your SUM() to MAX(). So if they have 5 entries, it would still show as at least 1, otherwise will be 0 for the given column aggregate.
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
I have two queries and I want to get the maximum value of the two of them.
MAX((SELECT COUNT(p.[ItemID]) FROM [dbo].[Table] p WHERE HasHuman=0),
(SELECT COUNT(p.[ItemID]) FROM [dbo].[Table] p WHERE HasHuman=1))
You can calculate both result in a single query and then apply TOP:
select top 1
HasHuman,
COUNT(p.[ItemID]) as cnt
from [dbo].[Table]
group by HasHuman
order by cnt desc
You could even do this in a single query:
SELECT
CASE WHEN SUM(CASE WHEN HasHuman=0 THEN 1 ELSE 0 END) >
SUM(CASE WHEN HasHuman=1 THEN 1 ELSE 0 END)
THEN SUM(CASE WHEN HasHuman=0 THEN 1 ELSE 0 END)
ELSE SUM(CASE WHEN HasHuman=1 THEN 1 ELSE 0 END) END
FROM [dbo].[Table]
WHERE ItemID IS NOT NULL -- you were not counting NULLs
SELECT MAX(RC)
FROM (SELECT COUNT(p.ItemID) AS RC FROM dbo.[Table]
WHERE HasHuman=0
UNION
SELECT COUNT(p.ItemID) AS RC FROM dbo.[Table]
WHERE HasHuman=1
) A
Table structures:
Solution_Votes:
ID int
SolutionID string
Vote int
Solution:
ID int
Solution
VotesUp
VotesDown
Code:
SELECT
*,
(SELECT SUM(CASE WHEN voteUp = 1 THEN 1 ELSE 0 END)
FROM Solutions_Votes) AS VoteCountUp,
(SELECT SUM(CASE WHEN voteDown = 0 THEN 1 ELSE 0 END)
FROM Solutions_Votes) AS VoteCountDown
FROM
Solution
When I run this query it gives me the count on each row for voteUpCount and voteDownCount. I need the count to be based on the solution ID so that each solution has its count of up votes and down votes. If anybody can help it would be appreciated. Thanks in advance!
Just use conditional aggregation. In your case this is simple:
select sv.solutionid,
sum(case when sv.voteUp = 1 then 1 else 0 end) as VoteCountUp,
sum(case when sv.voteDown = 0 then 1 else 0 end) as VoteCountDown
from solutions_votes sv
group by sv.solutionid;
You only need the solutions table if some solutions have no votes and you want to include them.
EDIT:
You would include solutions in various way. Here is one:
select s.*, ss.VoteCountUp, ss.VoteCountDown
from solutions s left join
(select sv.solutionid,
sum(case when sv.voteUp = 1 then 1 else 0 end) as VoteCountUp,
sum(case when sv.voteDown = 0 then 1 else 0 end) as VoteCountDown
from solutions_votes sv
group by sv.solutionid
) ss
on s.solutionid = ss.solutionid;
I have folllowing select query
SELECT
Table.ID
SUM(CASE WHEN Table.Status = 1 THEN 1 ELSE null END) AS NormalCount,
SUM(CASE WHEN Table.status = 2 THEN 1 ELSE null END) AS AbnormalCount
FROM Table
GROUP BY Table.ID
I want to get above results and generate new result set with following conditions
IF(NormalCount > 0 or AbnormalCount == NULL)
SELECT
Table.ID
Table.Status AS "Normal"
FROM Table
GROUP BY Table.ID
ELSE IF ( AbnormalCount > 0)
SELECT
Table.ID
Table.Status AS "Abnormal"
SUM(CASE WHEN Header.status = 2 THEN 1 ELSE null END) AS AbnormalCount
FROM Table
GROUP BY Table.ID
I think the logic you want is to label each ID group as being abnormal if it has one or more abnormal observation. If so, then you can use another CASE statement to check the conditional abnormal sum and label the status appropriately. Normal groups would have the characteristic of having an abnormal count of zero, but this count would appear for all groups.
SELECT t.ID,
CASE WHEN SUM(CASE WHEN t.status = 2 THEN 1 ELSE 0 END) > 0
THEN "Abnormal"
ELSE "Normal" END AS Status,
SUM(CASE WHEN t.status = 2 THEN 1 ELSE 0 END) AS AbnormalCount
FROM Table t
GROUP BY t.ID