How can I SUM rows that have at least X Boolean 1s? - sql

Example table:
col1 col2 col3 col4
Abe 1 0 1
Bob 0 1 0
Cam 1 1 1
Dan 1 0 0
Eve 1 1 1
How can I query so that I can SUM how many people in col1 have a total of 2 1s? (So, since Abe is the only person with 2 1s, the query outputs the number 1.)
Thanks.

Select count(*) from table_name where col2+col3+col4=2

If Your columns value contains only 0 and 1 then Vlad Călin Buzea and scaisEdge answer will work for you. But if it can have other than 0 and 1, You need this.
SELECT COUNT(*)
FROM Table_Name
WHERE (CASE WHEN col2 = 1 THEN 1 ELSE 0 END) +
(CASE WHEN col3 = 1 THEN 1 ELSE 0 END) +
(CASE WHEN col4 = 1 THEN 1 ELSE 0 END) = 2

;WITH cte AS (
SELECT 'Abe' AS Col1, CAST(1 AS BIT) as Col2, CAST(0 AS BIT) as Col3, CAST(1 AS BIT) AS Col4
UNION ALL
SELECT 'Bob' AS Col1, CAST(0 AS BIT) as Col2, CAST(1 AS BIT) as Col3, CAST(0 AS BIT) AS Col4
UNION ALL
SELECT 'Cam' AS Col1, CAST(1 AS BIT) as Col2, CAST(1 AS BIT) as Col3, CAST(1 AS BIT) AS Col4
UNION ALL
SELECT 'AbeWNull' AS Col1, CAST(1 AS BIT) as Col2, CAST(NULL AS BIT) as Col3, CAST(1 AS BIT) AS Col4
)
SELECT *
FROM
cte
WHERE
ISNULL(CAST(Col2 AS INT),0) + ISNULL(Col3,0) + ISNULL(Col4,0) = 2
The cte gives you some test data. 2 things. 1 if it is a Boolean or bit column you could have to cast/convert to an integer or numeric datatype at least one of the columns or the addition wont work. And yes I tested and needed to. Second, if you don't deal with the potential of a null you may not get the answer you want.
For example.
SELECT 1 + NULL + 1
Will give you NULL
Using SUM on a column isn't the same and it will just ignore the nulls, but not during the addition line.

Use addition of columns in where clause and select count()
select count(*)
from my_table
where CAST(ifnull(col2,false) AS SIGNED INTEGER) +
CAST(ifnull(col3,false) AS SIGNED INTEGER) +
CAST(ifnull(col4,false) AS SIGNED INTEGER) = 2;

Related

SQL query to calculate a value from 3 different rows

col1 col2 cal_val
F 1879 1879
% 25 1409
$ -45 1454
First row basically outputs back the entry in column 2
2nd row would basically calculate 25% of the value in row1, column 3 and then subtract that value from previous value which is 1879-470 = 1409
I need to be able to calculate final value of 1454 (which is basically a subtraction from the 2nd row output value)1409 - (-45) which would equal to 1454
You can use conditional aggregation:
select ( (sum(case when col1 = 'F' then col2 end) *
sum(case when col1 = '%' then 1 - col2 / 100.0 end)
) -
sum(case when col1 = '$' then col2 end)
)
from t;
Here is a db<>fiddle.
create temporary table t_teble
(
col1 text ,
col2 numeric ,
cal_val numeric );
insert into t_teble
select 'F',1879, 1879 union all
select '%',25,1409 union all
select '$',-45,1454;
select ( (sum(case when col1 = 'F' then col2 end) *
sum(case when col1 = '%' then 1 - col2 / 100.0 end)
) -
sum(case when col1 = '$' then col2 end)
),
(sum(case when col1 = 'F' then col2 end) *
sum(case when col1 = '%' then 1 - col2 / 100.0 end)
)
from t_teble;

Concatenate SQL table rows with conditions in single text

I have a SQL table like this
col1 col2 col3
1 0 1
1 1 1
0 1 1
1 0 0
0 0 0
I am expecting output as like this
col1 col2 col3 NewCol
1 0 1 SL,PL
1 1 1 SL,EL,PL
0 1 1 EL,PL
1 0 0 SL
0 0 0 NULL
The condition for this is if col1>0 then SL else ' ', if col2>0 EL else ' ', if col3>0 PL else ' '
I tried to use Concatenate many rows into a single text string? but didn't able to achieve the desired result properly
I have tried It is working fine with a message
Invalid length parameter passed to the LEFT or SUBSTRING function.
WITH CTE AS (
SELECT col1, col2, col3,
CASE WHEN col1 > 0 THEN 'SL,' ELSE '' END +
CASE WHEN col2 > 0 THEN 'EL,' ELSE '' END +
CASE WHEN col3 > 0 THEN 'PL,' ELSE '' END AS NewCol
FROM Employee
)
SELECT col1, col2, col3,
substring(NewCol, 1, len(NewCol) - 1) AS NewCol
FROM CTE
But again my last condition is not matching if all columns is 0 then I have to show NULL as per desired output.
Find the attach fiddle http://sqlfiddle.com/#!6/2bd6a/1
The issue with your code example is that when all columns are 0 then the length is 0 and the substring function will throw an error.
Use nullif to fix it: substring(NewCol, 1, len(nullif(NewCol,'')) - 1) AS NewCol
You could also change to appending the delimiter on the front and use STUFF.
STUFF('',1,1,'') will return NULL rather than an error.
WITH
Employee(col1, col2, col3) AS (
SELECT 1,1,1 UNION ALL
SELECT 0,0,0
),
CTE AS (
SELECT col1, col2, col3,
CASE WHEN col1 > 0 THEN ',SL' ELSE '' END +
CASE WHEN col2 > 0 THEN ',EL' ELSE '' END +
CASE WHEN col3 > 0 THEN ',PL' ELSE '' END AS NewCol
FROM Employee
)
SELECT col1,
col2,
col3,
STUFF(NewCol, 1, 1, '')
FROM CTE
Returns
+------+------+------+------------------+
| col1 | col2 | col3 | (No column name) |
+------+------+------+------------------+
| 1 | 1 | 1 | SL,EL,PL |
| 0 | 0 | 0 | NULL |
+------+------+------+------------------+
You have to check with NULLIF to do this trick
Two ways
SELECT col1, col2, col3,
nullif(CASE WHEN col1 = 1 THEN 'SL,' ELSE '' END +
CASE WHEN col2 = 1 THEN 'EL,' ELSE '' END +
CASE WHEN col3 = 1 THEN 'PL,' ELSE '' END,'') AS NewCol
FROM Employee
OR
SELECT
col1,
col2,
col3,
substring(nullif(NewCol,''), 1, len(NewCol) - 1) AS NewCol
FROM
CTE

SQL GROUP BY with a SUM CASE statement

I know that there are a lot of question like this:
SQL GROUP BY CASE statement with aggregate function
but I've tried doing:
with T as (select col1 , SUM(CASE WHEN col2 = 1 THEN col3 ELSE 0 END) AS Totale
from tabella
group by col1, col2)
select col1, Totale
from T
group by col1, Totale
but I'm getting
col1 | Totale
---------------
1 0
1 70
2 0
2 90
Instead of:
col1 | Totale
---------------
1 70
2 90
What's wrong with that?
UPDATE:
My bad, I try to keep it simple but I've overdone it.. What I've to do is:
with T as (select col1 , SUM(CASE WHEN col2 = 1 THEN col3 ELSE 0 END) AS TotaleA,
SUM(CASE WHEN col2 = 2 THEN col3 ELSE 0 END) AS TotaleB,
(...)
from tabella
group by col1, col2)
select col1, TotaleA, TotaleB
from T
group by col1, TotaleA, TotaleB
And the solution is to do without col2 in the grouping... I was afraid getting "invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause", but it's not.. Can I mark a comment as the correct answer?
You can also approach this problem by using a subquery:
SELECT
col1,
SUM(A) TotalA,
SUM(B) TotalB
FROM
(
select col1,
CASE WHEN col2 = 1 THEN col3 ELSE 0 END A,
CASE WHEN col2 = 2 THEN col3 ELSE 0 END B
from tabella
) t
GROUP BY Col1
Here is one idea. Not sure why you have this wrapped in a cte but why not make it simpler?
select col1
, SUM(col3) AS Totale
from tabella
where col2 = 1
group by col1

SQL Server Sum rows with string value

I have a dynamic SQL query which returns rows like below with string values & numeric values.
EMP col1 col2 col3 col4 col5
----------------------------
A1 4 4 3 3 3
A2 4 2 5 3 3
A3 sd 3 3 1 sd
A4 3 4 3 3 3
Now I need a new column which sums col1 to col5 and creates a total sum column where it should ignore the string values as in row 3. There are no NULL values
How could I achieve this? Using ISNUMERIC might be the solution, but I'm not sure how to use it in such a scenario.
You can use a CASE Expression to determine whether the value is a number. If it is a number then either cast the value to an INT or DECIMAL data type, otherwise use 0 so it doesn't effect the sum.
SELECT
CASE WHEN ISNUMERIC(col1) = 1 THEN CAST(col1 as INT) ELSE 0 END
+ CASE WHEN ISNUMERIC(col2) = 1 THEN CAST(col2 as INT) ELSE 0 END
+ CASE WHEN ISNUMERIC(col3) = 1 THEN CAST(col3 as INT) ELSE 0 END
+ CASE WHEN ISNUMERIC(col4) = 1 THEN CAST(col4 as INT) ELSE 0 END
+ CASE WHEN ISNUMERIC(col5) = 1 THEN CAST(col5 as INT) ELSE 0 END as SumValue
FROM MyTable
If you're on SQL Server 2012, TRY_CONVERT avoids pitfalls commonly encountered with ISNUMERIC:
SELECT col1, col2, col3, col4, col5,
ISNULL(TRY_CONVERT(int, col1), 0) +
ISNULL(TRY_CONVERT(int, col2), 0) +
ISNULL(TRY_CONVERT(int, col3), 0) +
ISNULL(TRY_CONVERT(int, col4), 0) +
ISNULL(TRY_CONVERT(int, col5), 0) AS total
FROM Employee
SQLFiddle
You can do this with a big case statement:
select q.*,
((case when isnumeric(col1) = 1 then cast(col1 as int) else 0 end) +
(case when isnumeric(col2) = 1 then cast(col2 as int) else 0 end) +
(case when isnumeric(col3) = 1 then cast(col3 as int) else 0 end) +
(case when isnumeric(col4) = 1 then cast(col4 as int) else 0 end) +
(case when isnumeric(col5) = 1 then cast(col5 as int) else 0 end)
) as newcol
from q;
isnumeric() should be sufficient for your purposes. You might need fancier logic if you only want positive integers or want to exclude exponential notations or the like.
You're on the right track with isnumeric:
select
emp,
(case when isnumeric(col1) = 1 then cast(col1 as int) else 0 end) +
col2...
from table1

Case when to find the difference in the number of counts of particular kind of rows.

I have a table which looks like this
col1, col2
a,C
a,D
a,C
a,D
I want to find out that for a in col1, what is the (Number of rows with C - Number of rows with D).
If I were to find the two numbers it will simply be
SELECT COUNT(1) FROM mytable where COL1='a' and COL2='C'
SELECT COUNT(1) FROM mytable where COL1='a' and COL2='D'
And then I could just find the difference.
However, I wanted to do it with a single query. So I went for this
SELECT COUNT(CASEWHEN(COL2)='D', 1, -1)
FROM mytable
But that does not seem to work. Any suggestions?
Here is one way:
SELECT SUM(CASE WHEN col2 = 'C' THEN 1 ELSE 0 END) Col2C,
SUM(CASE WHEN col2 = 'D' THEN 1 ELSE 0 END) Col2D,
SUM(CASE WHEN col2 = 'C' THEN 1 WHEN col2 = 'D' THEN -1 ELSE 0 END) [Col2C-Col2D]
FROM myTable
WHERE col1 = 'a'
select SUM(CASE WHEN col2 = 'C' THEN 1 WHEN col2 = 'D' THEN -1 ELSE 0 END) as Diff
from mytable
where col1 = 'a'
SELECT sum(CASE WHEN COL2='D' THEN 1 ELSE -1 END) as balance
FROM mytable
You were on the right track, this should work:
SELECT col1, SUM(CASE WHEN COL2 ='C' THEN 1 ELSE 0 END) - SUM(CASE WHEN COL2 ='D' THEN 1 ELSE 0 END)
FROM mytable
GROUP BY col1
Thanks folks for the quick responses. For me, the following code snippet worked.
SUM( CASEWHEN (COL2='D', 1, -1))
And a slightly fuller version of this is
SUM( CASE WHEN COL2='C' THEN -1 WHEN COL2='D' THEN 1 ELSE 0 END)
I would recommend the fuller version.