SQLServer Creating a Case in a query based on top 100 results - sql

I'm trying to create a SQL Server query based on the following criteria:
The query focuses on three columns: Report_Status, Error_Message, and Create_Date. The purpose of the query is to filter the top 100 most recent results based on the Create_Date. Once that's done, it needs to see if EVERY row in Report_Status in that top 100 says 'Failed' AND that Error_Message does not contain 'Placement is missing%'.
If it meets those conditions, then it needs to output the message "Potential service failure." If it doesn't meet those conditions, then it either needs to do nothing or output something normal, like "No problems found."
I figured a Case might be the best way to do this, so I tried it out. I'm having trouble getting it to work, though:
select Report_Status, Error_Message, Create_Date,
case
when Report_Status = 'Failed' and Error_Message not like 'Placement is missing%' then 'Potential service failure.'
ELSE 'No problems found.'
end
from [AUDIT_TABLE] limit 100
Is this the best way to approach this problem? If so, what do I need to change so this works? If it's not a good way, what's a better way to tackle the problem?

You would appear to want something like this:
select (case when count(*) = 100 then 'Potential service failure.'
else 'No problems found.'
end) as summary
from (select a.*
from [AUDIT_TABLE]
order by date desc
fetch first 100 rows only
) t100
where Report_Status = 'Failed' and
Error_Message not like 'Placement is missing%'

I ended up working with a coworker to solve this. Gordon Linoff's CASE section was great, but we changed how we searched for the most recent 100 records by also using the Report_ID field.
select
(case when count(*) = 100 then 'Potential failure.'
else 'No problems found.'
end) as Result
from Audit_Table
where Report_Status = 'fail'
and Error_Message not like 'Placement is missing%'
and Report_ID >= (select min(Report_ID) from (select top 100 * from Audit_Table order by Report_ID desc ) t100)

Related

CASE WHEN Statement referencing two different Columns

As you can see in the screenshot below, there are multiple account numbers that have either a "successful" or "fail" outcome. Some account numbers have multiple entries like account_number "413655". For accounts like "413655", where one outcome is Success, and the other outcome is fail, I want to create a new column that shows "success" for both entries. Only accounts that have all fail outcomes should display "fail" in this new column "Distinct_count". The rest should display "success".
SCREENSHOT: https://i.stack.imgur.com/NQZmY.jpg
Please find my query below.(I have bolded the part that needs to be edited)
-- #WbResult v_tcci_collection_activity_fact
SELECT date_dim_id,
B.user_key,
B.product_type,
B.dealer_nbr,
(CASE B.make
WHEN 'TOYOTA' THEN 'TOYOTA'
WHEN 'SUBARU' THEN 'SUBARU'
WHEN 'LEXUS' THEN 'LEXUS'
ELSE 'OTHER'
END),
C.dealer_name,
C.zone,
activity_date,
activity_time,
activity_code,
(CASE WHEN len(b.loan_nbr) > 3
THEN b.loan_nbr
ELSE b.lease_nbr END)
AS account_number,
(CASE WHEN activity_code IN ('SHPS','SBPS','SOPS','SHCS','SBCS') THEN 'Successful'
ELSE 'Fail' END)
AS outcome,
**(CASE WHEN outcome = 'Successful' AND outcome = 'Fail' OR outcome = 'Successful' THEN 'Successful'
ELSE 'Fail' END)
AS distinct_count**
FROM dm_business_ops_tcci.v_tcci_collection_activity_fact A
left join dm_business_ops_tcci.v_tcci_collection_account_dim B
on A.collection_account_dim_id = B.collection_account_dim_id
left join dm_business_ops_tcci.v_tcci_dealer_dim C
on A.dealer_dim_id = C.dealer_dim_id
where activity_code IN ('SBCS','SOPF','SBPS','SOPS','SHPF','SHPS','SBCF','SBPF','SHCF','SHCS')
It's difficult to parse through the whole query in your example, but in your scenario a Windowing Function is a good way to achieve this scenario.
Your query won't work as it's only doing things row-by-row, so you need to be able to take in the details from the other row to make it happen.
In your case you want to use a Windowing Function like the following (simplified from your specific example):
MAX(outcome) OVER (PARTITION BY account_number) AS outcome_overall
Here I am being a little cheap and nothing that Successful comes after Fail in the dictionary to utilize MAX. But with this, outcome_overall is calculated by:
Partitioning the dataset into separate chunks based on account_number.
Within each partition, it finds the MAX(outcome).
outcome_overall is that value from #2, repeated for each row in that partition.
Example data and what outcome_overall would be:
account_number
outcome
outcome_overall
A1
Successful
Successful
A1
Fail
Successful
A2
Fail
Fail
A2
Fail
Fail
A3
Successful
Successful
A4
Fail
Fail

changing positions of sql query results

The title is not claryifying my problem but this is how i could describe it.
I have a query which returns the following result :
and i was wondering if there is a way to reduce the number of lines from three to one having all the three no null values ( 400, 1000 and 21820 in one line ) with banquet as description.
Thank you for reading.
PS: this is just a capture of a part of the query results and there are a lot of duplicated lines. i can post my query if it would be helpful. i'm using some select case there..
EDIT:
THANK YOU guys but i solved that by copying the results of the main query to input of another one and adding distinct and sum clauses
SELECT description, MAX(number1) AS number1, MAX(number2) AS number2)
FROM myTable
GROUP BY description
At last in Oracle, you can use "When"
Eg:
SELECT
DESCRIPTION,
CASE WHEN SUMPRICE1 IS NULL THEN
CASE WHEN SUMPRICE2 IS NULL THEN
CASE WHEN SUMPRICE3 IS NULL THEN
0
ELSE SUMPRICE3 END
ELSE SUMPRICE2 END
ELSE SUMPRICE1 END AS SUMPRICE
FROM MY_TABLE
GROUP BY DESCRIPTION, SUMPRICE
Off course this is useble just if you have a static number of columns.
EDIT: I think I don't get the problem, but, if you don't want to merge the columns, you can use:
SELECT DESCRIPTION,
MAX(SUMPRICE1) AS SUMPRICE1,
MAX(SUMPRICE2) AS SUMPRICE2,
MAX(SUMPRICEN) AS SUMPRICEN
FROM MY_TABLE
GROUP BY DESCRIPTION
Or you can use the case to avoid the null, in the case of any of rows don't have a value:
SELECT DESCRIPTION,
CASE WHEN MAX(SUMPRICE1) IS NULL THEN 0 ELSE WHEN MAX(SUMPRICE1) END AS SUMPRICE1,
CASE WHEN MAX(SUMPRICE2) IS NULL THEN 0 ELSE WHEN MAX(SUMPRICE2) END AS SUMPRICE2,
CASE WHEN MAX(SUMPRICEN) IS NULL THEN 0 ELSE WHEN MAX(SUMPRICEN) END AS SUMPRICEN
FROM MY_TABLE
GROUP BY DESCRIPTION

Doing two COUNT on a single column without using views in one sql statement or in pl/sql block

I have a table attendance having columns
date1 ,status(either PRESENT or ABSENT),student_idstudent and student_subject_subjectid
I want make a query for student_idstudent and percentage attendance they have ie(count of present/total count) for each student for a particular subject.
Essentially I just want the values of two counts. Is there any easy way to do so without using views and preferably using pl/sql?
Below is my try using cursor.
Please tell me whether using the below code is it guaranteed to give corresponding answers(ie present count and total count) for each student_idstudent
Also tell me if this can fail in any other case?
DECLARE
s_id attendance.student_idstudent%type;
s_present number(3);
CURSOR student_present is select student_idstudent, count(student_idstudent) from attendance
where status like 'Present' and student_subject_subjectid like 102
group by student_idstudent;
s1_id attendence.student_idstudent%type;
s1_total number(3);
CURSOR student_total is select student_idstudent, count(student_idstudent) from attendance
where student_subject_subjectid like 102
group by student_idstudent;
BEGIN
OPEN student_present;
OPEN student_total;
LOOP
FETCH student_present into s_id, s_present;
FETCH student_total into s1_id, s1_total;
EXIT WHEN student_present%notfound;
dbms_output.put_line('student '|| s_id || ' has ' ||S_present/s1_total*100 || '% record' );
END LOOP;
CLOSE student_present;
CLOSE student_total;
END;
/
I'm not sure if this is a homework question or not, so Im giving you a partial answer, and you should be able to complete the query on your own.
select student_idstudent
,count(case when status like 'Absent' then 1 end) as absent_count
,count(case when status like 'Present' then 1 end) as present_count
,count(*) as tot_count
from attendance
where student_subject_subjectid = 102
group
by student_idstudent;
Also, using LIKE without any wild card characters is equal to using =. For clarity, the conditions should really be written status = 'Absent' and status = 'Present'. This is also more clear.
The same goes for like <number>. Do you mean student_subject_subjectid = 102, or do you have something else in mind?
With #ronnis help.
I came up with this answer.
SELECT student_idstudent,
count(CASE WHEN status = 'Present' then 1 END)/count(*)*100 as percentage
FROM attendence
where student_subject_subjectid = 102
group by student_idstudent;

SQL Server Update via Select Statement

I have the following sql statement and I want to update a field on the rows returned from the select statement. Is this possible with my select? The things I have tried are not giving me the desired results:
SELECT
Flows_Flows.FlowID,
Flows_Flows.Active,
Flows_Flows.BeatID,
Flows_Flows.FlowTitle,
Flows_Flows.FlowFileName,
Flows_Flows.FlowFilePath,
Flows_Users.UserName,
Flows_Users.DisplayName,
Flows_Users.ImageName,
Flows_Flows.Created,
SUM(CASE WHEN [Like] = 1 THEN 1 ELSE 0 END) AS Likes,
SUM(CASE WHEN [Dislike] = 1 THEN 1 ELSE 0 END) AS Dislikes
FROM Flows_Flows
INNER JOIN Flows_Users ON Flows_Users.UserID = Flows_Flows.UserID
LEFT JOIN Flows_Flows_Likes_Dislikes ON
Flows_Flows.FlowID=Flows_Flows_Likes_Dislikes.FlowID
WHERE Flows_Flows.Active = '1' AND Flows_Flows.Created < DATEADD(day, -60, GETDATE())
Group By Flows_Flows.FlowID, Flows_Flows.Active, Flows_Flows.BeatID,
Flows_Flows.FlowTitle, Flows_Flows.FlowFileName, Flows_Flows.FlowFilePath,
Flows_Users.UserName, Flows_Users.DisplayName, Flows_Users.ImageName,
Flows_Flows.Created
Having SUM(CASE WHEN [Like] = 1 THEN 1 ELSE 0 END) = '0' AND SUM(CASE WHEN [Dislike] = 1
THEN 1 ELSE 0 END) >= '0'
This select statement returns exactly what I need but I want to change the Active field from 1 to 0.
yes - the general structure might be like this: (note you don't declare your primary key)
UPDATE mytable
set myCol = 1
where myPrimaryKey in (
select myPrimaryKey from mytable where interesting bits happen here )
Because you haven't made your question more clear in what result you want to achieve, I'll provide an answer with my own assumptions.
Assumption
You have a select statement that gives you stuffs, and it works as desired. What you want it to do is to make it return results and update those selected rows on the fly - basically like saying "find X, tell me about X and make it Y".
Anwser
If my assumption is correct, unfortunately I don't think there is any way you can do that. A select does not alter the table, it can only fetch information. Similarly, an update does not provide more detail than the number of rows updated.
But don't give up yet, depending on the result you want to achieve, you have alternatives.
Alternatives
If you just want to update the rows that you have selected, you can
simply write an UPDATE statement to do that, and #Randy has provided
a good example of how it will be written.
If you want to reduce calls to server, meaning you want to make just
one call to the server and get result, as well as to update the
rows, you can write store procedures to do that.
Store procedures are like functions you wrote in programming languages. It essentially defines a set of sql operations and gives them a name. Each time you call that store procedure, the set of operations gets executed with supplied inputs, if any.
So if you want to learn more about store procedures you can take a look at:
http://www.mysqltutorial.org/introduction-to-sql-stored-procedures.aspx
If I understand correctly you are looking for a syntax to be able to select the value of Active to be 0 if it is 1. The syntax for something like that is
SELECT
Active= CASE WHEN Active=1 THEN 0 ELSE Active END
FROM
<Tables>
WHERE
<JOIN Conditions>

Distinct in SQL Server

I am executing the following query,
Select distinct
a.cr_id,
Case
When ca.ca_vote = 'Approve' and ca.ca_title='MANAGER' Then ca.ca_email
When ca.ca_vote = 'Reject' Then ''
When ca.ca_vote = 'Pending' Then ''
When ca.ca_vote = 'IN PROCESS' Then ''
End as ca_email
from
credit a
inner join credit_approvals ca on ca.c_id=a.cr_id
where
a.cr_cs_date between Convert(varchar(20),'11/16/2011',101) and dateadd(day,1,convert (varchar(20),'11/16/2011',101))
order by
a.cr_id
Despite distinct for cr_id, it is still displaying the duplicate values. Please let me know how to handle this, so that I could able to display only distinct records.
Distinct is applied to all columns, not the one which is immediately after Distinct.
If you have several different ca_email for a cr_id, you will see them all.
If you don't want that, you have to come up with a rule to decide what record among the duplicates must stay.