SQL SUM only when each value within a group is greater than 0 - sql

Here is a sample data set:
ID Value
1 421
1 532
1 642
2 3413
2 0
2 5323
I want a query that, in this case, only sums ID=1 because all of its values are greater than 0. I cannot use a WHERE statement that says WHERE Value > 0 because then ID=2 would still return a value. I feel like this may be an instance where I could possibly use a OVER(PARTITION BY...) statement, but I am not familiar enough to use it creatively.
As an aside, I don't simply add a WHERE ID = 1 statement because this needs to cover a much larger data set.

Just use having:
select id, sum(value)
from t
group by id
having min(value) > 0;

Related

Order grouped table by id user sql

I want to order a grouped statement using as reference the number choosen by an specific user.
SELECT *
FROM likes
WHERE /**/
GROUP BY type
TABLE
id_user type
1420 1
1421 3
1422 3
1424 7
1425 4
1426 2
1427 1
expected result (at the end what user 1425 choosed)
1
2
3
7
4 //choosen by id_user 1425
I want to put the last row with the number choosed by the user. i just cant figure that out
You can aggregate and use a conditional max for ordering, like so:
select type
from likes
group by likes
order by max(case when id_user = 1425 then 1 else 0 end), type
If any row for the given type has an id_user that matches the chosen value, the conditional max returns 1, wich puts it last in the resultset. The second ordering criteria break the ties for groups that do not fulfill the condition.
If you are running MySQL, you can simplify the order by clause a little:
order by max(id_user = 1425), type

SQL - select surrounding records of the one fulfil a condition

I have the following table:
epochTime,id,counter1,value
123,Alpha,2,2
124,Beta,0,3
135,Alpha,0,1
112,Alpha,0,5
150,Alpha,0,-1
225,Beta,1,2
228,Beta,1,0
300,Beta,0,2
I want to select all records with counter1 > 0 and the record after that, partitioning by id and order by epochTime (the requirement similar to Unix "grep -A 1" command)
So the expected result from the data above would be
epochTime id counter1 value
123 Alpha 2 2
135 Alpha 0 1
225 Beta 1 2
228 Beta 1 0
300 Beta 0 2
I am using AWS Athena, and got the following query, which works as expected.
SELECT * FROM (
SELECT id,
epochTime,
counter1,
value,
first_value(counter1) OVER (
PARTITION BY id
ORDER BY epochTime
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
) AS preCounter
FROM testsql
) WHERE counter1 > 0 OR preCounter > 0
However, I see two problems with the query:
It is a nested query
I needed to create a dummy column (preCounter). If the requirements on the WHERE condition become more complex (i.e: conditions on multiple columns), I would need to create multiple dummy columns
Are there better solutions (better performance, simpler query, ...) for me?
What if counter1 is the number of following records I need to select?
You can use lag():
select t.*
from (select t.*,
lag(counter) over (partition by id order by epochtime) as prev_counter
from testseql t
) t
where counter > 0 or prev_counter > 0;

Give first duplicate a 1 and the rest 0

I have data which contains 1000+ lines and in this it contains errors people make. I have added a extra column and would like to find all duplicate Rev Names and give the first one a 1 and all remaining duplicates a 0. When there is no duplicate, it should be a 1. The outcome should look like this:
RevName ErrorCount Duplicate
Rev5588 23 1
Rev5588 67 0
Rev5588 7 0
Rev5588 45 0
Rev7895 6 1
Rev9065 4 1
Rev5588 1 1
I have tried CASE WHEN but its not giving the first one a 1, its giving them all zero's.
Thanks guys, I am pulling out my hair here trying to get this done.
You could use a case expression over the row_number window function:
SELECT RevName,
Duplicate,
CASE ROW_NUMER() OVER (PARTITION BY RevName
ORDER BY (SELECT 1)) WHEN 1 THEN 1 ELSE 0 END AS Duplicate
FROM mytable
SQL tables represent unordered sets. There is no "first" of anything, unless a column specifies the ordering.
Your logic suggests lag():
select t.*,
(case when lag(revname) over (order by ??) = revname then 0
else 1
end) as is_duplicate
from t;
The ?? is for the column that specifies the ordering.

Need to result of column based on available column in SQL

I am having one view which is returning the following result:
I need to put identifier just like below image
Required output:
Explanation of Output: If you can see the image 1 and in that image release 1 has 3 dates. From that I need to get 1 as an identifier for the MAX(IMPL_DATE).In RELEASE_ID = 1, We are having 08/20/2016, 08/09/2016 and 10/31/2016. From This 10/31/2016 is the largest date. So, Need Identifier as 1 and other 2 are going to be 0. Same thing with the RELEASE_ID 2 we have 2 dates and from them 01/13/2017 is the largest date so, need 1 in that row and other's going to be 0.
Thanks In advance...
You can do this with window functions:
select t.*,
(case when rank() over (partition by portfolio_id, release_id
order by impl_date desc
) = 1
then 1 else 0
end) as indentifier
from t;
The above will assign "1" to all rows with the maximum date. If you want to ensure that only one row is assigned a value (even when there are ties), then use row_number() instead of rank().

How to get three count values from same column using SQL in Access?

I have a table that has an integer column from which I am trying to get a few counts from. Basically I need four separate counts from the same column. The first value I need returned is the count of how many records have an integer value stored in this column between two values such as 213 and 9999, including the min and max values. The other three count values I need returned are just the count of records between different values of this column. I've tried doing queries like...
SELECT (SELECT Count(ID) FROM view1 WHERE ((MyIntColumn BETWEEN 213 AND 9999));)
AS Value1, (SELECT Count(ID) FROM FROM view1 WHERE ((MyIntColumn BETWEEN 500 AND 600));) AS Value2 FROM view1;
So there are for example, ten records with this column value between 213 and 9999. The result returned from this query gives me 10, but it gives me the same value of 10, 618 times which is the number of total records in the table. How would it be possible for me to only have it return one record of 10 instead?
Use the Iif() function instead of CASE WHEN
select Condition1: iif( ), condition2: iif( ), etc
P.S. : What I used to do when working with Access was have the iif() resolve to 1 or 0 and then do a SUM() to get the counts. Roundabout but it worked better with aggregation since it avoided nulls.
SELECT
COUNT(CASE
WHEN MyIntColumn >= 213 AND MyIntColumn <= 9999
THEN MyIntColumn
ELSE NULL
END) AS FirstValue
, ??? AS SecondValue
, ??? AS ThirdValue
, ??? AS FourthValue
FROM Table
This doesn't need nesting or CTE or anything. Just define via CASE your condition within COUNTs argument.
I dont really understand what You want in the second, third an fourth column. Sounds to me, its very similar to the first one.
Reformatted, your query looks like:
SELECT (
SELECT Count(ID)
FROM view1
WHERE MyIntColumn BETWEEN 213 AND 9999
) AS Value1
FROM view1;
So you are selecting a subquery expression that is not related to the outer query. For each row in view1, you calculate the number of rows in view1.
Instead, try to do the calculation once. You just have to remove your outer query:
SELECT Count(ID)
FROM view1
WHERE MyIntColumn BETWEEN 213 AND 9999;
OLEDB Connection in MS Access does not support key words CASE and WHEN .
You can only use iif() function to count two, three.. values in same columns
SELECT Attendance.StudentName, Count(IIf([Attendance]![Yes_No]='Yes',1,Null)) AS Yes, Count(IIf([Attendance]![Yes_No]='No',1,Null)) AS [No], Count(IIf([Attendance]![Yes_No]='Not',1,Null)) AS [Not], Count(IIf([Attendance]![Yes_No],1,Null)) AS Total
FROM Attendance
GROUP BY Attendance.StudentName;