SQL Case and Cast in Count function - sql

I am trying to count records from two fields only if they meet a specific criteria.
This [Is it possible to specify condition in Count()? ] post was helpful, but it doesn't account for casting varchar to int.
Here is my code:
SELECT Mailing_Id ,Mailing_Nm,Subject_Line,Campaign_Nm,Start_Ts,End_Ts, Mailed_Cnt, Invalid_Cnt ,Actual_Sent_Cnt ,Bounce_Cnt ,Open_Cnt ,Click_Cnt
,count(case ag.logtype when '7' then 1 end) as Unsubs
,count(case ag.category when '1' then 1 end) as Block
,count(case ag.category when '2' then 1 end) as Hard
,count(case ag.category when '3' then 1 end) as Soft
,count(case ag.category when '4' then 1 end) as Tech
,count(case ag.category when '9' then 1 end) as Unknown
FROM [StrongMailTracking].[dbo].[SM_MAILING_SUMMARY] ms left join sm_aggregate_log ag on ms.mailing_id = ag.mailingid
WHERE datepart(year,start_ts) = 2015 and (mailing_nm not like '%delivery report%' and mailing_nm not like '%daily helpdesk%' and mailing_nm not like '%test%')
GROUP BY Mailing_Id ,Mailing_Nm ,Subject_Line ,Campaign_Nm ,Start_Ts ,End_Ts ,Mailed_Cnt ,Invalid_Cnt ,Actual_Sent_Cnt ,Bounce_Cnt ,Open_Cnt ,Click_Cnt
ORDER BY mailing_id asc
Please draw your attention to the 6 case statements. Logtype is int, Category is varchar.
I've tried:
removing the single quotes
adding ... case cast( - as int) when ...
removing single quotes while casting
casting as numeric first then int
But I keep getting this error: "Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the varchar value 'dynamic-preview-7179' to data type int."
Does anyone have ideas on what to do?

According to your description of the data types, this should work:
count(case ag.logtype when 7 then 1 end) as Unsubs,
count(case ag.category when '1' then 1 end) as Block,
count(case ag.category when '2' then 1 end) as Hard,
count(case ag.category when '3' then 1 end) as Soft,
count(case ag.category when '4' then 1 end) as Tech,
count(case ag.category when '9' then 1 end) as Unknown
Numbers should be compared to numeric constants; strings to string constants.
Although equivalent, I would write the logic as:
sum(case when ag.logtype = 7 then 1 else 0 end) as Unsubs,
Why? Two reasons that are merely preferences:
I prefer the more general case statement because I find that when modifying code, I often need to add in new conditions. I prefer IN to using multiple WHENs.
I prefer sum() over count() because count(2) = count(1).

as I commented before, ms.Mailing_Id is an int and ag.mailingid is a varchar. a colleague helped me out with this:
FROM [StrongMailTracking].[dbo].[SM_MAILING_SUMMARY] ms left join sm_aggregate_log ag on CAST(ms.mailing_id As varchar(255)) = ag.mailingid

Related

Cleaning "SUM" Query

I have a bit of sql code that look similar to this:
select sum(case when latitude = '0' then 1 else 0 end) as count_zero,
sum(case when latitude is NULL then 1 else 0 end) as count_null,
sum((case when latitude = '0' then 1 else 0 end) +
(case when latitude is NULL then 1 else 0 end)
) as total_zero,
count(latitude) as count_not_nulls,
count(*) as total
from sites_database
Is there a "cleaner" way to write this same query. I have tried using the "sum" expression using the column alias, something like:
Sum(count_zero + count_null) as total_null
But this doesn't seem to work for some reason
You could use COUNT instead of SUM:
SELECT
COUNT(CASE WHEN latitude = '0' THEN 1 END) As count_zero,
COUNT(CASE WHEN latitude IS NULL THEN 1 END) AS count_null,
COUNT(CASE WHEN COALESCE(latitude, '0') = '0' THEN 1 END) AS total_zero,
COUNT(latitude) As count_not_nulls,
COUNT(*) as total
FROM sites_database;
Using COUNT here saves a bit of coding, because we don't have to provide an explicit ELSE condition (the default ELSE is NULL, which just isn't counted at all). Also note that for the total_zero conditional sum, I used COALESCE to merge the two counts into just one.

SUM with CASE and LEFT Syntax

With the code below, I'm trying to get the total Net_Value and Eaches for the three years 2015-2017. However I cannot, for the life of me figure out what the syntax error is
[Microsoft][SQL Server Native Client 10.0][SQL Server]Incorrect syntax near '2015'.
SELECT
SUM(CASE WHEN LEFT(STR(FP_Based_on_Comm_Date),4) = '2015' THEN Net_Value ELSE 0 END) AS 2015Sales,
SUM(CASE WHEN LEFT(STR(FP_Based_on_Comm_Date),4) = '2016' THEN Net_Value ELSE 0 END) AS 2016Sales,
SUM(CASE WHEN LEFT(STR(FP_Based_on_Comm_Date),4) = '2017' THEN Net_Value ELSE 0 END) AS 2017Sales,
SUM(CASE WHEN LEFT(STR(FP_Based_on_Comm_Date),4) = '2015' THEN Eaches ELSE 0 END) AS 2015Eaches,
SUM(CASE WHEN LEFT(STR(FP_Based_on_Comm_Date),4) = '2016' THEN Eaches ELSE 0 END) AS 2016Eaches,
SUM(CASE WHEN LEFT(STR(FP_Based_on_Comm_Date),4) = '2017' THEN Eaches ELSE 0 END) AS 2017Eaches
FROM DB;
The field itself is a numerical field, and am trying to use it as a string. Those values typically come through as 2015001 where the format is yyyymmm
The problem are the column alias you're using - a valid SQL Server / T-SQL identifier cannot begin with a number.
If you really want to keep this, you must put these in square brackets like this:
SELECT
SUM(CASE
WHEN LEFT(FP_Based_on_Comm_Date, 4) = 2015
THEN Net_Value
ELSE 0
END) AS [2015Sales],
and you need to apply this to all your column aliases.
Assuming your dates are stored as dates, why aren't you using the YEAR() function. I would also suggest putting the year at the end of the column alias.
SELECT SUM(CASE WHEN YEAR(FP_Based_on_Comm_Date) = 2015 THEN Net_Value ELSE 0 END) AS Sales_2015
I think it is bad idea to use identifiers that need to be escaped -- they just make queries harder to write and to read.
And, if you just care about the results, why not use GROUP BY:
select year(FP_Based_on_Comm_Date), sum(net_value) as sales, sum(eaches) as eaches
from db
group by year(FP_Based_on_Comm_Date),
order by year(FP_Based_on_Comm_Date);

How do I change a constant value to a column header in SQL?

The SQL query:
select type,count(*), 'Active'
from file where removed = '0'
union all
select type,count(*), 'Removed'
from file where removed = '1'
gives:
TYPE COUNT ( * ) Constant value
A 24,168 Active
A 1 Removed
B 8,280 Active
B 1,263 Removed
However, how can I change the SQL to get:
TYPE Active Removed
A 24,168 1
B 8,280 1,263
Supplementary optional question: and what's the best way to include the following total?
TYPE Active Removed
A 24,168 1
B 8,280 1,263
Total 32,448 1,264
This is my best answer to the supplementary, please let me know if you see any flaws or improvements:
select
type,
sum(CASE WHEN removed = '0' THEN 1 ELSE 0 END) 'Active',
sum(CASE WHEN removed = '1' THEN 1 ELSE 0 END) 'Removed'
from file
Group by type
union all
select 'Total',
sum(CASE WHEN removed = '0' THEN 1 ELSE 0 END) 'Active',
sum(CASE WHEN removed = '1' THEN 1 ELSE 0 END) 'Removed'
from file
Thank you to everyone who commented or answered, your help is appreciated.
You can try:
select
type,
sum(CASE WHEN removed = '0' THEN 1 ELSE 0 END) 'Active',
sum(CASE WHEN removed = '1' THEN 1 ELSE 0 END) 'Removed'
from file
Group by type
Use case expressions to do conditional aggregation:
select type,
count(case when removed = '0' then 1 end) as "Active",
count(case when removed = '1' then 1 end) as "Removed"
from file
group by type
If there are many rows with other removed values than 0/1, and the column is indexed, you can throw in a
WHERE removed IN ('0','1')
to speed things up!
In order to get totals into the answer without union try:
select
coalesce(type, 'Totals') type,
sum(CASE WHEN removed = '0' THEN 1 ELSE 0 END) Active,
sum(CASE WHEN removed = '1' THEN 1 ELSE 0 END) Removed
from file
Group by rollup(type)
This works for v6.1 and later.

How to use multiple where clause in one sql query

Hello guys i need to use mutiple where clause in one sql query as follows but it can't work please help me.
select (select count(total) as 'studentMarks1' from School where total <60 ),
(select count(total) as 'studentMarks2' from School where total >80 )
from School
where Id = '8'
You rather need to use CASE statement like
select SUM(case when total < 60 then 1 else 0 end) as 'studentMarks1',
sum(case when total > 80 then 1 else 0 end) as 'studentMarks2'
from School
where Id = '8'
You cau usually do this with an appropriate CASE statement:
SELECT COUNT(CASE WHEN total < 60 then 1 else NULL END)
, COUNT(CASE WHEN total > 80 then 1 else NULL END)
FROM School
WHERE ID = '8'

SQL get number of entries satisfying different conditions

the goal is to retrieve the number of users in one table which have:
field EXPIREDATE > CURRENT_TIMESTAMP as nUsersActive
field EXPIREDATE < CURRENT_TIMESTAMP as nUsersExpired
field EXPIREDATE IS NULL as nUsersPreregistered
all with one query, and the result should for example be
nUsersActive nUsersExpired nUsersPreregistered
10 2 15
this will later be json_encoded and passed to an ExtJS script for displaying.
Any hint? I tried several times without succeding. I tried with the UNION statement, I get the right numbers, but of course in column, while I need them in row.
Thanks for your support.
Something like the following should work, you may need to adjust for the specific database that you are using.
To get them in columns:
select
count(case when EXPIREDATE > CURRENT_TIMESTAMP then 1 end) AS nUsersActive,
count(case when EXPIREDATE < CURRENT_TIMESTAMP then 1 end) AS nUsersExpired,
count(case when EXPIREDATE IS NULL then 1 end) AS nUserPreregistered
from users_table
And in rows (this is not as efficient!):
select
'nUsersActive' AS Param
count(case when EXPIREDATE > CURRENT_TIMESTAMP then 1 end) AS Value
from users_table
UNION ALL
select 'nUsersExpired',
count(case when EXPIREDATE < CURRENT_TIMESTAMP then 1 end)
from users_table
UNION ALL
select 'nUserPreregistered',
count(case when EXPIREDATE IS NULL then 1 end)
from users_table
I'm assuming you are using SQL Server. You should be able to get what you're looking for by using a CASE statement. Make sure you return something (anything) if the condition is true and NULL if the condition is false. Here is the msdn documentation: http://msdn.microsoft.com/en-us/library/ms181765.aspx
Your query would look something like this:
select COUNT(CASE WHEN #ThingToCheck = 'Value' THEN 1 ELSE NULL END) as Count1, COUNT(CASE WHEN #ThingToCheck = 'Value' THEN 1 ELSE NULL END) FROM ....
SELECT COUNT(CASE WHEN EXPIREDATE > CURRENT_TIMESTAMP THEN 1 END) AS nUsersActive,
COUNT(CASE WHEN EXPIREDATE < CURRENT_TIMESTAMP THEN 1 END) AS nUsersExpired,
COUNT(CASE WHEN EXPIREDATE IS NULL THEN 1 END) AS nUsersPreregistered
FROM Users