Aggregating positive values on multiple columns with SQL - mysql

I am trying to do aggregation functions on a specific database table with multiple columns.
For example:
Sample Table
ID Column1 Column2 Column3
1 3 5 -2
2 -1 4 6
3 2 -1 3
In this example, if I would like to sum the values in the 3 columns, I want to get the following result:
Column1: (3+2)=5, Column2(5+4)=9 and Column3(6+3)=9.
Thus, my question is whether this is possible with a single SQL query or I would have to go through creating temporary tables?
Note: The data set is big.

If I understand correctly, you only want to SUM the positive values, and ignore the negatives? If so try:
SELECT
SUM(CASE WHEN Column1 > 0 THEN Column1 ELSE 0 END) AS 'Column1PosTotal',
SUM(CASE WHEN Column2 > 0 THEN Column2 ELSE 0 END) AS 'Column2PosTotal',
SUM(CASE WHEN Column3 > 0 THEN Column3 ELSE 0 END) AS 'Column3PosTotal'
FROM Table

Related

MySQL replacement of values in the query result

I transpose table rows to columns by the SELECT statement:
`SELECT cdcb_info.CISLO AS "cislo",
max(case when info = 'HBR' then value end) as "HBR",
max(case when info = 'HCD' then value end) as "HCD"
FROM cdcb_info group by cdcb_info.CISLO`
Result looks like this:
cislo
HBR
HCD
111222
0
5
333444
1
3
how should I modify the query to change the values 0 and 1 to "zero" and "one" for the column HBR and
5, 3 to "five" and "three" for column HCD? Thanks for any help. David
Data example:
id CISLO info value
27 111222 HBR 0
28 111222 HCD 5
29 333444 HBR 1
30 333444 HCD 3
I would advise adding another table, where in one column there are numbers (primary index), in the other the designations of these numbers. Connect this table and output string values from this new table instead of max(case when info = 'HBR' then value end) and max(case when info = 'HCD' then value end).

mysql how do I hide lines with specific value

How can I hide lines with value 0 of 'rechamadas'.
I've tried with 'where' and the result is the same with or without it.
'case when' returns almost the same but with nulls instead of 0s.
I need something like this:
Data NumeroCliente Rechamadas
15/07/21 16481218527 2
17/07/21 16910110913 2
17/07/21 16030926362 1
select
date_format(datahora, '%d/%m/%y') as 'Data',
numerocliente as NumeroCliente,
count(numerocliente) - 1 as Rechamadas
from ligacoes
-- where numerocliente > 1
group by numerocliente
order by datahora
Data NumeroCliente Rechamadas
15/07/21 16481218527 0
17/07/21 16910110913 2
17/07/21 16030926362 0
17/07/21 16200904978 0
21/07/21 16030219377 0
21/07/21 16900314989 2
21/07/21 16090625771 0
22/07/21 16790310530 1
22/07/21 16080429611 0
edit1: My goal is to know how many times each 'NumeroCliente' reappears per date. I've manage to done that with 'count(numerocliente) - 1' cuz the first time it appears doesnt count to what I need. The table 'ligacoes' has tree columns which are 'numerocliente' (an id to each customer), 'datahora' (datetime format) and 'codigooperador' (fk).
thank you for your time!
MySQL (and many other SQL implementations) have a HAVING clause which is an result limitation that is applied after the GROUP BY:
So your query becomes:
select
date_format(datahora, '%d/%m/%y') as 'Data',
numerocliente as NumeroCliente,
count(numerocliente) - 1 as Rechamadas
from ligacoes
where numerocliente > 1
group by numerocliente
HAVING Rechamadas > 0
order by datahora
ref: manual

Combining multiple columns into one- SQL Server 2008

I am trying to make one table value function in Sql Server. Here I have 3 columns and i want to merge them into one column lets say "new". This new column should show the name of 3 columns if they have value as 1.For example for row one it should display Isprod, for row 2 it should display IsCompetProd and so on.
IsProd IsCompetProd IsOther
1 0 0
0 1 0
0 0 1
1 0 0
Is there any way to do that?
Try like this
SELECT CASE WHEN IsProd=1 THEN 'IsProd'
WHEN IsCompetProd=1 THEN 'IsCompetProd'
WHEN IsOther=1 THEN 'IsOther'
END [New]
FROM table1
If I am getting what you want. Use a case statement. Try this:
SELECT
tbl.*,
(
CASE
WHEN IsProd=1
THEN 'IsProd'
WHEN IsCompetProd=1
THEN 'IsCompetProd'
WHEN IsOther=1
THEN 'IsOther'
ELSE 'None'
END
)AS newColumn
FROM
tbl

Separating/Sorting single column values into several columns using case function

I have two tables that I want to join and split with a case function depending on the values in one of the columns. (I know, sounds weird so let me explain)
It's a process where I run separate batches. Every batch has several samples that are measured in instances of voltage readings in several locations. My two tables looks like this:
Sample Readings
id id
BatchesID SampleID
... voltage
... location
When a batch is run, it takes one sample at a time and for every location (25 locations) it takes about 20 readings of the voltage before moving on to the next one.
I want to look at one batch at a time, and for every Sample.id, I want to gather the AVG(voltage) for all the locations. My table for Readings turns out like:
SampleID location voltage
1 1 5.23
1 1 4.53
... ... ...
1 25 7.89
2 1 4.96
2 1 5.04
... ... ...
2 25 6.09
...
But I want it to look like:
SampleID avg_v_for_1 avg_v_for_2 ... avg_v_for_25
1 4.73 5.24 ... 6.35
2 3.87 4.76 ... 9.32
... ... ... ... ...
200 6.73 3.87 ... 8.23
Basically, what I want to do is for every separate sample, I want to take the average voltage for all the measurements in every location and put in on a single row. What my current syntax looks like is this:
SELECT Readings.SampleID, Sample.BatchesID
(case when location = '1' then AVG(voltage) else 0 end) avg_v_for_1,
(case when location = '2' then AVG(voltage) else 0 end) avg_v_for_2,
...
(case when location = '25' then AVG(voltage) else 0 end) avg_v_for_25
FROM DB.Readings
INNER JOIN Sample
ON Readings.SampleID = Sample.id
WHERE Sample.BatchesID = 'specific_batch_id'
GROUP BY Readings.location, Sample.id;
The problem is that this generates the following table:
SampleID avg_v_for_1 avg_v_for_2 ... avg_v_for_25
1 4.73 0 ... 0
1 0 4.76 ... 0
1 0 0 ... 6.73
2 3.87 0 ... 0
2 0 4.83 ... 0
...
How can I get MySQL to gather ALL the average values for EVERY location on a SINGLE row? I have tried removing the group by location and only group by sampleID but then I only get the values for the first location and everything else becomes 0.
Any help is appreciated, thank you!
I add another answer with explanation how the the query with AVG(case ..when ... then..end) works, and why the version with case ... when ... then AVG(..) end doesn't give expected results.
The first remark: the ANSI SQL standard for group by queries is the following:
SELECT column1, column2, ... column_n, aggregate_function (expression)
FROM tables
WHERE predicates
GROUP BY column1, column2, ... column_n;
where aggregated_function can be a function such a: SUM, MAX, MIN, COUNT, AVG
There are several rules (restrictions) for the GROUP BY CLASUE, see this link for details: http://etutorials.org/SQL/Mastering+Oracle+SQL/Chapter+4.+Group+Operations/4.2+The+GROUP+BY+Clause/
one of them says that:
GROUP BY clause must include all nonaggregate expressions
It means, that all columns in SELECT clause must be listed in the GROUP BY clause,
for example this query:
SELECT col1, col2, AVG( expression )
FROM table
GROUP BY col2
is wrong, because col1 is not listed in the GROUP BY clause, and this query won't work on all databases (Oracle, Postgresql, MS-SQL etc.) - except MySql (why - I'll tell about it later).
The expression within the aggregated function can refer to all columns of the table, regardless of the column is listed in the GROUP BY clause or not.
Because of the above the query:
SELECT Readings.SampleID,
(case when location = '1' then AVG(voltage) else 0 end) avg_v_for_1
....
GROUP BY sampleId
simply won't work on all databases that are compliant with ANSI SQL, this query will give a syntax error because location is out of AVG function, but is not listed in the GROUP BY clause.
The question - why this query works on MySql ?
Because MySql implemented it's own extension to the GROUP BY query, see this link --> http://dev.mysql.com/doc/refman/5.6/en/group-by-extensions.html
In MySql the select list can refer to nonaggregated columns not listed in the GROUP BY clause. Becaue of this extension our query is syntactically correct and runs on MySql, but gives unexpected (unwanted) results, since an order of expression's evaluation is different:
1. it first runs an aggregated (group by) query and evaluates AVG( price ),
2. then evaluates CASE WHEN ... THEN, but for resultset returned by the aggregated query from point 1
The query with the clause AVG( case when ... then ):
1. first calucates the expression CASE-WHEN-THEN for all table rows
2. then runs an aggregated query for resultset returned by #1 and calculates the AVG.
Try:
SELECT Readings.SampleID, Sample.BatchesID
AVG(case when location = '1' then voltage else null end) avg_v_for_1,
AVG(case when location = '2' then voltage else null end) avg_v_for_2,
...
AVG(case when location = '25' then voltage else null end) avg_v_for_25
FROM DB.Readings
........
GROUP BY sample_id
--- EDIT --> use ifnull function to change nulls into 0
SELECT Readings.SampleID, Sample.BatchesID
ifnull( AVG(case when location = '1' then voltage else null end), 0 ) avg_v_for_1,
ifnull( AVG(case when location = '2' then voltage else null end), 0 ) avg_v_for_2,
...
ifnull( AVG(case when location = '25' then voltage else null end), 0 ) avg_v_for_25
FROM DB.Readings
........
GROUP BY sample_id

Comparing 2 Columns in same table

I need to compare 2 columns in a table and give 3 things:
Count of rows checked (Total Rows that were checked)
Count of rows matching (Rows in which the 2 columns matched)
Count of rows different (Rows in which the 2 columns differed)
I've been able to get just rows matching using a join on itself, but I'm unsure how to get the others all at once. The importance of getting all of the information at the same time is because this is a very active table and the data changes with great frequency.
I cannot post the table schema as there is a lot of data in it that is irrelevant to this issue. The columns in question are both int(11) unsigned NOT NULL DEFAULT '0'. For purposes of this, I'll call them mask and mask_alt.
select
count(*) as rows_checked,
sum(col = col2) as rows_matching,
sum(col != col2) as rows_different
from table
Note the elegant use of sum(condition).
This works because in mysql true is 1 and false is 0. Summing these counts the number of times the condition is true. It's much more elegant than case when condition then 1 else 0 end, which is the SQL equivalent of coding if (condition) return true else return false; instead of simply return condition;.
Assuming you mean you want to count the rows where col1 is or is not equal to col2, you can use an aggregate SUM() coupled with CASE:
SELECT
COUNT(*) AS total,
SUM(CASE WHEN col = col2 THEN 1 ELSE 0 END )AS matching,
SUM(CASE WHEN col <> col2 THEN 1 ELSE 0 END) AS non_matching
FROM table
It may be more efficient to get the total COUNT(*) in a subquery though, and use that value to subtract the matching to get the non-matching, if the above is not performant enough.
SELECT
total,
matching,
total - matching AS non_matching
FROM
(
SELECT
COUNT(*) AS total,
SUM(CASE WHEN col = col2 THEN 1 ELSE 0 END )AS matching
FROM table
) sumtbl