SQL Group By and window function - sql

I am struggling a little bit with an SQL Statement and was hoping if someone would be willing to point me in the right direction.
Below is a picture of my table:
As you can see here I have a column called 'State'. Basically I want to group all 'State' associated with a particular BuildID and display them in an extra column on my SQL output.
I am close but not quite there.
In the next picture below is an example of the statement I have used to try and achieve this:
As you can see here, it has done SUM and added the TotalTime and created the extra columns I require. However instead of grouping it all into one record, it has created 2 extra lines per BuildID. One with the value for the 'Running' state, another record for the value State of 'Break' and another record that contains the value 0 on both States.
Now what I want it to do is group it into one record for each BuildID. Like the picture I have added below:
The above image is how I want the records displayed. But the problem is I have added the WHERE [State] = Running, which I know is wrong but was just using this as an example. As you can see the 'Break' column has no value.
I hope this makes sense and was hoping if someone could point me in the right direction?
Here is an example on SQL fiddle http://sqlfiddle.com/#!3/7b6b9/2
Thanks for taking the time to read this :)

Have refined the sql a bit, here you go:
SELECT BuildID,Product, Program,
sum(CASE WHEN State = 'Running' THEN cast(TotalTime as INT) ELSE 0 END) AS Running
, sum(CASE WHEN State = 'Break' THEN cast(TotalTime as INT) ELSE 0 END) AS Breakt
FROM Line1Log
GROUP BY BuildID,Product, Program
Please check SQLFiddle
Not sure if i am missing something :-), but the solution looks pretty straight forward. Let me know.

move your SUM() OVER(PARTITION BY...) out from CASE
SQL fiddle
select BuildID, Product, Program, Sum(Running) Running, Sum([Break]) [Break]
from (
SELECT Distinct BuildID, Product, Program,
Sum(Case when [State]='Running' Then TotalTime Else 0 END) OVER (Partition by [State], [BuildID]) Running,
Sum(Case when [State]='Break' Then TotalTime Else 0 END) OVER (Partition by [State], [BuildID]) [Break]
From Line1Log) T
group by BuildID, Product, Program

Everything else is ok, why are you grouping all columns?, Try this,
Select BuidId,Product,program,Sum(Running),Sum(Break)
(......
.....
......) as T
group by BuidId,Product,program

Related

Why are my SQL subqueries getting syntax errors? Using COUNT()

The question is: are there more reviews with the word "love" or with the word "hate" in them?
Here is the code I am trying to use:
SELECT
(COUNT(SELECT id FROM review WHERE text LIKE '%love%') FROM review) AS NumLove,
(COUNT(SELECT id FROM review WHERE text LIKE '%hate%') FROM review) AS NumHate
FROM
review
Another variation:
SELECT
COUNT(SELECT id FROM review WHERE text LIKE '%love%') AS NumLove,
COUNT(SELECT id FROM review WHERE text LIKE '%hate%') AS NumHate
FROM
review
I am getting an error:
Syntax error near "SELECT"
I have tried to adjust the code a few different times, but I keep getting syntax errors. I can run either of the select statements on their own, and they will execute. I just can't get them to run in a single query.
You need conditional aggregation:
SELECT COUNT(CASE WHEN text LIKE '%love%' THEN 1 END) AS NumLove,
COUNT(CASE WHEN text LIKE '%hate%' THEN 1 END) AS NumHate
FROM review
The important thing to remember is functions are used against columns not result sets. Multiple ways to get there. Aside from the CASE example.
SELECT COUNT(Pro.Love) AS NumLov
FROM
(SELECT id Love FROM review WHERE text LIKE '%love%') as Pro
To write this in one query, you could use a case expression to turn your love and hate evals into 1 and 0 and use Sum instead of count.
SELECT SUM(results.love) AS NumLov
FROM
(
SELECT CASE WHEN text like '%love%' THEN 1 ELSE 0 END AS love
FROM review
) as results
I prefer to use sum instead of count here when using a condition case expression - since you really are adding up (summing) the number of 1s from each case expression
select
Sum(case when text like '%love%' then 1 else 0 end) as NumLove,
Sum(case when text like '%hate%' then 1 else 0 end) as NumHate
from review

Cannot sum sql query into single line

I have a view (using it to link into an Access 2016 Front-End thus the view). I am trying to sum 4 rows where each have a different status of Approved, In Progress, Rejected and Cancelled. The field I want to sum is Total_Cost.
Criteria is [Status] <> 'Rejected' and <> 'Cancelled'. Therefore, I want Approved and In progress to sum into 1.
The view is still showing 2 rows (Field ID is the primary key so want to show by ID). I have unselected the Output box for [Status]. This normally works in Access but I cannot get it to work in SQL. I have tried Group by, Where, Sum etc and nothing is working.
Any help would be so much appreciated.
Smiddy
The following query might help you or solve your question :
SELECT
ID, SUM(CASE
WHEN [Status] <> 'Rejected' AND [Status] <> 'Cancelled'
THEN Total_Cost
ELSE 0 END) AS yourTotal
FROM yourTable
GROUP BY ID

Select Longest String - SQL Server

I have a need to select the longest string in a SQL Server Query.
I need, the longest description from LongDescription_c when there is something in it or the longest from PartDescription.
At the moment, we have the following query created by a colleague a long time ago:
SELECT PartNum,
MAX(CASE WHEN LongDescription_c = '' THEN PartDescription ELSE LongDescription_c END) AS PartDesc
FROM
Part
GROUP BY
PartNum
This works in a lot of circumstances but not all and I believe the reason for this is the MAX(). As i believe this returns in alphabetical order rather then MAX(LEN()) which is what I believe he wanted. However, I cannot work out how to use MAX(LEN()) as this will purely return the maximum length as an integer.
Thanks for any help in advance as Im a bit stuck at this point.
Thanks :)
Along the lines of what #jarlh was saying, one option would be to use a TOP trick:
SELECT TOP 1 *
FROM Part
ORDER BY
LEN(CASE WHEN LongDescription_c = ''
THEN PartDescription ELSE LongDescription_c END) DESC,
CASE WHEN LongDescription_c = ''
THEN PartDescription ELSE LongDescription_c END
In the case of a tie, it would report the alphabetically lowest description first.
If performance be an issue, then adding an index is the typical thing to do. But in this case, because we are ordering using a function, the index cannot be used. If you really need performance, then consider adding a computed column to store the length.
Following query will give you row with longest LongDescription_c
SELECT TOP 1 * FROM [Part]
ORDER BY LEN(LongDescription_c) DESC
You would requited to use len() function in order to check length of string
select top(1) with ties PartNum, *
from table t
order by row_number() over (partition by PartNum order by
len(CASE WHEN LongDescription_c = ''
THEN PartDescription ELSE LongDescription_c END) desc)
I think your colleagues query is wrong.
If your LongDescription_c is always longer than PartDescription column, and only need to display PartDescription when LongDescription is not available, you can use a much simpler query
SELECT PartNum, IIF(LEN(LongDescription_c)>=LEN(PartDescription),LongDescription_c,PartDescription)
FROM Part

Nested CASE statement to exclude certain rows

Sample Data: Oracle 10g
Number Activity
1 x Activity
1 no activity
2 x activity
3 no activity
What I need to do is produce the rows where there is either no activity or x activity, then comes the problem: If there is an ID with both x activity and no activity, I only want to produce the x activity rows. Can it be done? Here is the CASE statement that produces the above data:
CASE WHEN DSKMTB_ACTIVITY_TYPE.ACTIVITY_TYPE_LABEL IS NULL
THEN 'No Activity'
ELSE DSKMTB_ACTIVITY_TYPE.ACTIVITY_TYPE_LABEL
END AS "Activity Type"
I am thinking I need to nest a CASE statement, but I can't quite gather the logic in my head. Please let me know if there is anything that I can do to help. Per the usual, I have not included the entire query here, as it is quite large, but will edit if anyone feels it is necessary. Thanks in advance.
By grouping by ID and filtering you might get through it:
SELECT
CASE
WHEN MAX(NVL(a.ACTIVITY_TYPE_LABEL, 'aaaa')) = 'aaaa'
THEN 'No Activity'
ELSE a.ACTIVITY_TYPE_LABEL
END AS "Activity Type"
FROM DSKMTB_ACTIVITY_TYPE a
GROUP BY a.id
The problem is if you actually select other fields, it will probably break the GROUP BY and we'll have to make a subquery.
You can put a MAX() around the case statement and than a GROUP BY on the ID field.
MAX(CASE WHEN DSKMTB_ACTIVITY_TYPE.ACTIVITY_TYPE_LABEL IS NULL
THEN 'No Activity'
ELSE DSKMTB_ACTIVITY_TYPE.ACTIVITY_TYPE_LABEL
END) AS "Activity Type"
GROUP BY ID

How to get aggregates without using a nested sql query

I am writing a custom report from an Avamar (Postgresql) database which contains backup job history. My task is to display jobs that failed last night (based on status_code), and include that client's success ratio (jobs succeeded/total jobs run) over the past 30 days on the same line.
So the overall select just picks up clients that failed (status_code doesn't equal 30000, which is the success code). However, for each failed client from last night, I need to also know how many jobs have succeeded, and how many jobs total were started/scheduled in the past 30 days. (The time period part is simple, so I haven't included it in the code below, to keep it simple.)
I tried to do this without using a nested query, based on Hobodave's feedback on this similar question but I'm not quite able to nail it.
In the query below, I get the following error:
column "v_activities_2.client_name" must appear in the GROUP BY clause or be used in an aggregate function
Here's my (broken) query. I know the logic is flawed, but I'm coming up empty with how best to accomplish this. Thanks in advance for any guidance!
select
split_part(client_name,'.',1) as client_name,
bunchofothercolumnns,
round(
100.0 * (
((sum(CASE WHEN status_code=30000 THEN 1 ELSE 0 END))) /
((sum(CASE WHEN type='Scheduled Backup' THEN 1 ELSE 0 END))))
as percent_total
from v_activities_2
where
status_code<>30000
order by client_name
You need to define a GROUP BY if you have columns in the SELECT that do not have aggregate functions performed on them:
SELECT SPLIT_PART(t.client_name, '.', 1) AS client_name,
SUM(CASE WHEN status_code = 30000 THEN 1 ELSE 0 END) as successes
FROM v_activities_2
GROUP BY SPLIT_PART(t.client_name, '.', 1)
ORDER BY client_name
How do you expect the following to work:
SUM(CASE WHEN status_code = 30000 THEN 1 ELSE 0 END) as successes
FROM v_activities_2
WHERE status_code <> 30000
You can't expect to count rows you're excluding.
Why avoid nested query?
It seems most logical / efficient solution here.
If you do this in one pass with no sobqueries (only group by's), you will end with scanning the whole table (or joined tables) - which is not efficient, because only SOME clients failed last night.
Subqueries are not that bad, in general.