Querying Ratio as a percentage - sql-server

I am trying to first count characters in the columns and than dividing them to create a percentage ratio column. I get errors and not sure what is causing the issue.
[Report_Graded] is boolean
[Test_Status] is text with (4) options. "Accepted, Completed, Declined, Scheduled"
SELECT Name, Report_Graded, Test_Status,
SUM(CASE WHEN Report_Graded= 'Completed' THEN 1 ELSE 0 END) / SUM(CASE WHEN Test_Status= 'Declined'OR 'Scheduled' THEN 0 ELSE 1 END) * 100 AS "Ratio_Graded"
FROM [database]
WHERE Date_Test BETWEEN '01/01/2021' AND '06/30/2021'
GROUP BY Name
ORDER BY "Ratio_Graded" DESC

WHEN Test_Status= 'Declined'OR 'Scheduled'
is not syntactically correct. You must write
WHEN Test_Status= 'Declined'OR Test_Status= 'Scheduled'
To run the query.
Also beware of O divide. Add a COALESCE.
The query rewrited :
SELECT Name,
Report_Graded,
Test_Status,
SUM(CASE
WHEN Report_Graded = 'Completed'
THEN 1
ELSE 0
END) / COALESCE(SUM(CASE
WHEN Test_Status = 'Declined'
OR Test_Status = 'Scheduled'
THEN 0
ELSE 1
END) * 100 AS "Ratio_Graded"
FROM [database]
WHERE Date_Test BETWEEN '01/01/2021' AND '06/30/2021'
GROUP BY Name
ORDER BY "Ratio_Graded" DESC;
Also date/time format can vary from the session culture. It is why it is recommended to use the ISO SQL Standard :
AAAAMMJJ hh:mm:ss.nnn for DATETIME (call ISO short)
AAAA-MM-JJ hh:mm:ss.nnn for DATETIME2, DATETIMEOFFSET (call ISO
long)
AAAA-MM-JJ for DATE (call ISO long)

Related

REPLACE NULL WITH 0 when pivot clause is used [duplicate]

I have developed a query, and in the results for the first three columns I get NULL. How can I replace it with 0?
Select c.rundate,
sum(case when c.runstatus = 'Succeeded' then 1 end) as Succeeded,
sum(case when c.runstatus = 'Failed' then 1 end) as Failed,
sum(case when c.runstatus = 'Cancelled' then 1 end) as Cancelled,
count(*) as Totalrun from
( Select a.name,case when b.run_status=0 Then 'Failed' when b.run_status=1 Then 'Succeeded'
when b.run_status=2 Then 'Retry' Else 'Cancelled' End as Runstatus,
---cast(run_date as datetime)
cast(substring(convert(varchar(8),run_date),1,4)+'/'+substring(convert(varchar(8),run_date),5,2)+'/' +substring(convert(varchar(8),run_date),7,2) as Datetime) as RunDate
from msdb.dbo.sysjobs as a(nolock) inner join msdb.dbo.sysjobhistory as b(nolock)
on a.job_id=b.job_id
where a.name='AI'
and b.step_id=0) as c
group by
c.rundate
When you want to replace a possibly null column with something else, use IsNull.
SELECT ISNULL(myColumn, 0 ) FROM myTable
This will put a 0 in myColumn if it is null in the first place.
You can use both of these methods but there are differences:
SELECT ISNULL(col1, 0 ) FROM table1
SELECT COALESCE(col1, 0 ) FROM table1
Comparing COALESCE() and ISNULL():
The ISNULL function and the COALESCE expression have a similar
purpose but can behave differently.
Because ISNULL is a function, it is evaluated only once. As
described above, the input values for the COALESCE expression can be
evaluated multiple times.
Data type determination of the resulting expression is different.
ISNULL uses the data type of the first parameter, COALESCE follows
the CASE expression rules and returns the data type of value with
the highest precedence.
The NULLability of the result expression is different for ISNULL and
COALESCE. The ISNULL return value is always considered NOT NULLable
(assuming the return value is a non-nullable one) whereas COALESCE
with non-null parameters is considered to be NULL. So the
expressions ISNULL(NULL, 1) and COALESCE(NULL, 1) although
equivalent have different nullability values. This makes a
difference if you are using these expressions in computed columns,
creating key constraints or making the return value of a scalar UDF
deterministic so that it can be indexed as shown in the following
example.
-- This statement fails because the PRIMARY KEY cannot accept NULL values
-- and the nullability of the COALESCE expression for col2
-- evaluates to NULL.
CREATE TABLE #Demo
(
col1 integer NULL,
col2 AS COALESCE(col1, 0) PRIMARY KEY,
col3 AS ISNULL(col1, 0)
);
-- This statement succeeds because the nullability of the
-- ISNULL function evaluates AS NOT NULL.
CREATE TABLE #Demo
(
col1 integer NULL,
col2 AS COALESCE(col1, 0),
col3 AS ISNULL(col1, 0) PRIMARY KEY
);
Validations for ISNULL and COALESCE are also different. For example,
a NULL value for ISNULL is converted to int whereas for COALESCE,
you must provide a data type.
ISNULL takes only 2 parameters whereas COALESCE takes a variable
number of parameters.
if you need to know more here is the full document from msdn.
With coalesce:
coalesce(column_name,0)
Although, where summing when condition then 1, you could just as easily change sum to count - eg:
count(case when c.runstatus = 'Succeeded' then 1 end) as Succeeded,
(Count(null) returns 0, while sum(null) returns null.)
When you say the first three columns, do you mean your SUM columns? If so, add ELSE 0 to your CASE statements. The SUM of a NULL value is NULL.
sum(case when c.runstatus = 'Succeeded' then 1 else 0 end) as Succeeded,
sum(case when c.runstatus = 'Failed' then 1 else 0 end) as Failed,
sum(case when c.runstatus = 'Cancelled' then 1 else 0 end) as Cancelled,
SQL Fiddle Demo
A Simple way is
UPDATE tbl_name SET fild_name = value WHERE fild_name IS NULL
If you are using Presto, AWS Athena etc, there is no ISNULL() function. Instead, use:
SELECT COALESCE(myColumn, 0 ) FROM myTable
Wrap your column in this code.
ISNULL(Yourcolumn, 0)
Maybe check why you are getting nulls
Use COALESCE, which returns the first not-null value e.g.
SELECT COALESCE(sum(case when c.runstatus = 'Succeeded' then 1 end), 0) as Succeeded
Will set Succeeded as 0 if it is returned as NULL.
Add an else to your case statements so that they default to zero if the test condition is not found. At the moment if the test condition isn't found NULL is being passed to the SUM() function.
Select c.rundate,
sum(case when c.runstatus = 'Succeeded' then 1 else 0 end) as Succeeded,
sum(case when c.runstatus = 'Failed' then 1 else 0 end) as Failed,
sum(case when c.runstatus = 'Cancelled' then 1 else 0 end) as Cancelled,
count(*) as Totalrun from
( Select a.name,case when b.run_status=0 Then 'Failed' when b.run_status=1 Then 'Succeeded'
when b.run_status=2 Then 'Retry' Else 'Cancelled' End as Runstatus,
---cast(run_date as datetime)
cast(substring(convert(varchar(8),run_date),1,4)+'/'+substring(convert(varchar(8),run_date),5,2)+'/' +substring(convert(varchar(8),run_date),7,2) as Datetime) as RunDate
from msdb.dbo.sysjobs as a(nolock) inner join msdb.dbo.sysjobhistory as b(nolock)
on a.job_id=b.job_id
where a.name='AI'
and b.step_id=0) as c
group by
c.rundate
sum(case when c.runstatus = 'Succeeded' then 1 else 0 end) as Succeeded,
sum(case when c.runstatus = 'Failed' then 1 else 0 end) as Failed,
sum(case when c.runstatus = 'Cancelled' then 1 else 0 end) as Cancelled,
the issue here is that without the else statement, you are bound to receive a Null when the run status isn't the stated status in the column description. Adding anything to Null will result in Null, and that is the issue with this query.
Good Luck!
by following previous answers I was losing my column name in SQL server db however following this syntax helped me to retain the ColumnName as well
ISNULL(MyColumnName, 0) MyColumnName
For regular SQL, ISNULL(item) can only take one parameter, and thus 90% of these solutions don't work.
I repurposed #Krishna Chavali's answer to make this:
(CASE WHEN (NOT ISNULL(column_name)) THEN column_name ELSE 0 END) AS ColumnName
This will return the value in column_name if it is not null, and 0 if it is null.
UPDATE TableName SET ColumnName= ISNULL(ColumnName, 0 ) WHERE Id = 10

SQL Server : multiple Select queries

I am trying to show sum(grand_total) where is_loyal = 1 and sum(grand_total) where is_loyal = 0 together in the same result screen (grand_total column is in the same table for both). I have tried subqueries, join and case when but no luck so far. Is there a way to calculate and show the results together?
The only result I can find by subqueries is below, no matter how I change where clause gives me the same data. If I change my query a bit it throws error message
Msg 512, Level 16, State 1, Line 155
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Result
With conditional aggregation:
select date,
sum(case when loyal = 1 then grand_total end) [Total Loyalty],
sum(case when loyal = 0 then grand_total end) [Total Spent non-loyalty]
from tablename
group by date
use case when like this:
select
sum(case when loyal = 1 then 1 else 0 end) as grand_total_Loyal,
sum(case when loyal = 0 then 1 else 0 end) as grand_total_noneloyal
A simple method uses arithmetic:
select sum(loyal * grandtotal) as loyal_grandtotal,
sum( (1 - loyal) * grandtotal) as notloyal_grandtotal
from t
where loyal in (1, 0);
The more general solution is using a case expression. However, if you have 0/1 flags they fit very easily into arithmetic calculations -- on reason why they are preferred over, say, string flags.

SQL Server condition case doesnt work as intended

I want my SQL to display the overdue count when the condition is the status name showed closed on the exact due date then the count will be set as 1. For example, on the due date, the status name only became closed.
select
category, COUNT(overdue) as overdue2
from
(select
Category, due,
case when DATEDIFF(day, Due, SYSDATETIME()) = 0 then 1
else 0
end as overdue
from
FeedbackDetail
where
StatusName = 'Closed' and
FeedbackDatetime >= '2018-01-01') a
Group by
Category
My expected result is to display the count where the statusname is closed on the exact due date time.
Any idea on this?
The COUNT aggregate function counts existant (non-null) values, so it will count 0 as well as 1. Since you did not post the whole query and we have no idea what a1 is, the only solution that can be proposed is:
Use SUM instead of COUNT.
You can modify the query like given below for better performance and working.
DECLARE #currentDateTime DATETIME = GETDATE()
select
category, SUM(overdue) as overdue2
from
(select
Category,
case when DATEDIFF(day, Due, #currentDateTime) = 0 then 1
else 0
end as overdue
from
FeedbackDetail
where
StatusName = 'Closed' and
FeedbackDatetime >= '2018-01-01') a
Group by
Category

Aggregate Function Error on an Expression

What could be wrong with this query:
SELECT
SUM(CASE
WHEN (SELECT TOP 1 ISNULL(StartDate,'01-01-1900')
FROM TestingTable
ORDER BY StartDate Asc) <> '01-01-1900' THEN 1 ELSE 0 END) AS Testingvalue.
The get the error:
Cannot perform an aggregate function on an expression containing an aggregate or a subquery.
As koppinjo stated what your current (broken) query is doing is checking if you have a NULL-value (or StartDate = '01-01-1900') in your table, return either a 1 or a 0 depending on which, and then attempting to SUM that single value.
There are 2 different logical things you want.
Either getting the amount of rows that has a StartDate or checking if any row is missing StartDate.
SELECT --Checking if there is a NULL-value in table
(
CASE WHEN
(SELECT TOP 1 ISNULL(StartDate,'01-01-1900')
FROM TestingTable
ORDER BY StartDate Asc) <> '01-01-1900' THEN 1
ELSE 0
END
) AS TestingValue
SELECT SUM(TestingValue) TestingValue --Give the count of how many non-NULLs there is
FROM
(
SELECT
CASE WHEN
ISNULL(StartDate,'01-01-1900') <> '01-01-1900' THEN 1
ELSE 0
END AS TestingValue
FROM TestingTable
) T
Here is a SQL Fiddle showing both outputs side by side.
Hard to say, but you probably want something like this:
SELECT
SUM(TestingValue)
FROM
(SELECT
CASE
WHEN ISNULL(StartDate,'01-01-1900') <> '01-01-1900'
THEN 1
ELSE 0
END AS TestingValue
FROM TestingTable) t
As your original query is written now, your subquery will return 1 value overall, so your sum would be 1 or 0 always, not to mention it is illegal. To get around that, this SQL will apply the case statement to every row in the TestingTable and insert the result into a derived table (t), then the 'outer' select will sum the results. Hope this helps!

SQL Server result column in WHERE clause

SELECT
MyColumn = 'something'
FROM table
WHERE MyColumn == 'something'
Possible to use MyColumn in WHERE clause?
EDIT:
Here's full query:
select TOP 10
PremiumYTDCurrent=Sum(CASE WHEN
AASI.Inv_Acctcur>='201101'
and AASI.Inv_Acctcur<='201102'
THEN (AASI.Inv_Premium)*R.[Percent]
ELSE 0 END),
PremiumYTDPrevious=Sum(CASE WHEN
AASI.Inv_Acctcur>='201001'
and AASI.Inv_Acctcur<='201002'
THEN (AASI.Inv_Premium)*R.[Percent]
ELSE 0 END),
R.STAFF, L.Description, L.LINE_OF_BUSINESS
from AAS_Invoice AASI,Invoice I,Revenue_Tracking R, Policy P, Line_Of_Business L
where I.Invoice_No=convert(Char,Convert(int,AASI.Inv_Entry_Num))
and I.Invoice=R.Invoice
and I.POLICY=P.POLICY
and L.LINE_OF_BUSINESS=P.LINE_OF_BUSINESS
and R.Organization IN (SELECT ST.ORGANIZATION FROM Staff ST WHERE ST.STAFF=14407)
and R.Staff=14407
and R.Activity_type='Broker'
and R.[Percent]>0
and PremiumYTDCurrent != 0
group by R.STAFF, L.Description, L.LINE_OF_BUSINESS
order by PremiumYTDCurrent DESC, PremiumYTDPrevious DESC, average_policy DESC
You can not use the column in the where clause. Use the expression instead.
and Sum(CASE WHEN
AASI.Inv_Acctcur>='201101'
and AASI.Inv_Acctcur<='201102'
THEN (AASI.Inv_Premium)*R.[Percent]
ELSE 0 END) <> 0
Edit 1
Did not notice the SUM clause.
Try add it as a HAVING clause instead after order by.
having Sum(CASE WHEN
AASI.Inv_Acctcur>='201101'
and AASI.Inv_Acctcur<='201102'
THEN (AASI.Inv_Premium)*R.[Percent]
ELSE 0 END) != 0
You could wrap the SQL up in a nested statement, a horrendously simple example being, e.g.:
SELECT MyMadeUpColumnName, col2, AnotherMadeUpColumn FROM (
SELECT SUM(sillycolumn) AS 'MyMadeUpColumnName', col2 FROM table GROUP BY col2
) AS t
WHERE t.AnotherMadeUpColumn <> 0
Any column names that you (re)define in the derived table become the actual column names for the parent select.

Resources