Case remove null values in each column - mysql

I am trying to remove null values from my query.
Val_1
Val_2
Condition_1
Condition_2
Condition_3
X
Y
NULL
NULL
0.508850000
X
Y
0.116350000
NULL
NULL
X
Y
0.000000000
NULL
NULL
X
Y
0.000000000
NULL
NULL
X
Y
NULL
0.000000000
NULL
X
Y
NULL
0.046050000
NULL
X
Y
NULL
NULL
7.385500000
X and Y are identical strings. I am trying to create this, removing null values and keeping all the non-null values together:
Var_1
Var_2
Condition_1
Condition_2
Condition_3
X
Y
0.116350000
0.000000000
0.508850000
X
Y
0.000000000
0.046050000
7.385500000
X
Y
0.000000000
NULL
NULL
Currently, I have this
Select Table_1.Var_1,
Table_1.Var_2,
Avg(CASE WHEN Table_2.Conditions = 'Condition_1' Then Table_1.Values END) As Condition_1,
Avg(CASE WHEN Table_2.Conditions = 'Condition_2' Then Table_1.Values END) As Condition_2,
Avg(CASE WHEN Table_2.Conditions = 'Condition_3' Then Table_1.Values END) As Condition_3,
From Table_1
INNER JOIN Table_2 ON Table_1.ID = Table_2.ID
Group BY Table_1.Val_1, Table_2.Val_2, Table_1.ID
Order By Table_1.Val_1, Table_2.Val_2
Table 1 holds the values, Table 2 holds the conditions. These are joined via a common ID number. Each value can have only one of the three conditions. Aggregate functions such as max just returns a single value, but I need all the values that are not null. I was thinking of wrapping this query in a subquery and then modifying it accordingly, but I'm really unsure if that will work.
Table 1 Sample
ID
Another value
Val_1
Val_2
Values
01
15
X
Y
0.29000
01
15
X
Y
1.20000
01
15
X
Y
3.38000
Table 2 Sample
ID
Condition
01
1
01
2
01
3

Related

Delete rows with same columns data

I am having a temp table with the following data:
tbl_t
id name_id date t1 t2 s1 s2
1 25 10/05/20 same same NULL NULL
2 23 11/05/21 same same home NULL
3 25 12/05/20 same NULL NULL NULL
4 25 13/06/20 NULL NULL NULL NULL
Desire output:
tbl_t
id name_id date t1 t2 s1 s2
2 23 11/05/21 same same home NULL
3 25 12/05/20 same NULL NULL NULL
I want to delete all rows where t1=t2 and s1=s1
I tried the following sql but i noticed that it is not working.
DELETE FROM tbl_t WHERE t1=t2 AND s1=s2
The problem are the NULL values. Use the NULL-safe comparison operator:
DELETE FROM tbl_t
WHERE t1 <=> t2 AND s1 <=> s2;
Almost any comparison with NULL results in NULL -- including NULL = NULL. And NULL values are treated as false in a WHERE clause (or equivalently WHERE clauses only keep rows where the condition evaluates unequivocally to true).

SQL : Record Existance Check in another table

My requirement is below .
I have two tables let's call them Table A and Table B :
PARTNER_ID PARTNER_Registration Partner_PANNUMBER
----------
1 11 AB1
2 22 AB2
3 33 AB3
4 44 AB4
5 55 AB5
6 66 AB6
7 77 AB5
8 88 AB8
i Will have another table B which contains PID , Preg, Ppan as follows
PID PREG PPAN
----------
1 11 AB1
2 22 AB2
3 33 AB3
4 44
5 AB5
66 AB6
Now I should create a column Output in table A and have output as follows
PARTNER_ID PARTNER_Registration Partner_PANNUMBER Output
----------
1 11 AB1 All three Found
2 22 AB2 All three Found
3 33 AB3 All three found
4 44 AB4 PPAN NOT FOUND
5 55 AB5 PARTNER_Registration Not Found in TABLE B
6 66 AB6 PARTNER_ID Not found in Table B
7 77 AB5 PARTNER_ID, PARTNER_Registration Not found in Table B
8 88 AB8 None of them Found in Table B
Can some one help me find an easy way to acheive this in SQL,
I would like to populate which values of 3 columns are not present in another and update output column accordingly..
Thanks
I would just add up the number of matches:
select a.*,
( exists (select 1 from b where b.PID = a.PARTNER_ID) +
exists (select 1 from b where b.PREG = a.PARTNER_Registration) +
exists (select 1 from b where b.PPAN = a.Partner_PANNUMBER)
) as num_matches
from a;
You can use multiple LEFT JOIN with table B, and test which ones produce NULL values.
SELECT a.*,
CASE WHEN b1.pid IS NOT NULL AND b2.preg IS NOT NULL AND b3.ppan IS NOT NULL
THEN 'All three found'
WHEN b1.pid IS NULL AND b2.preg IS NULL AND p3.ppan IS NULL
THEN 'None of them found in Table B'
ELSE CONCAT(CONCAT_WS(', '
IF(b1.pid IS NULL, 'Partner_ID', NULL),
IF(b2.preg IS NULL, 'Partner_Registration', NULL),
IF(b3.ppan IS NULL, 'PPAN', NULL)),
' not found in Table B') AS Output
FROM TableA AS a
LEFT JOIN TableB AS b1 ON a.partner_id = b1.pid
LEFT JOIN TableB AS b2 ON a.partner_registration = b2.preg
LEFT JOIN TableB AS b3 ON a.partner_pannumber = b.ppan
CONCAT_WS() will ignore null values, so with the IF statements inverting NULL with the names of the missing values, you get the list of results you want.
I would use multiple LEFT JOIN because of the use case of OP where we can manipulate the null values means missing in table2 to achieve the exact output you want.
The query looks big but it is just manipulating the string using specific string functions to get the final string output.
select a.partner_id
,a.partner_registration
,a.partner_pannumber
,case
when chk = ''
then 'All three found'
else
concat(case (length(chk) - length(replace(chk,',','')))
when 3
then 'None of them found'
when 1
then replace(chk,',',' not found')
else
regexp_replace(chk,'[,]',' not found',1,2)
end
,' in table2'
)
end Remarks
from
(
select a.*
,concat(case when pi.pid is null then 'Partner Id,' else '' end
,case when pr.preg is null then 'Partner Registration,' else '' end
,case when pp.ppan is null then 'PPAN,' else '' end
) chk
from table1 a
left join table2 pi
on a.partner_id = pi.pid
left join table2 pr
on a.partner_registration = pr.preg
left join table2 pp
on a.partner_pannumber = pp.ppan
) a
P.S. I personally like the answer with usage of concat_ws as it has less code but you need a little modification for non of them match in ... case.

Positiv or Negative value depends on relationship - Possible to SELECT SUM(...) in single statement?

Each row in the assets table contains the fields value and type. The type field is a relation ship to the types table where each row has a field is_negative:
// assets
id | value | type
----------------------
1 | 10 | 1
2 | 4 | 2
3 | 1 | NULL
// types
id | is_negative
------------------
1 | 0
2 | 1
I would like to query the sum of all asset values where the type specifies whether the value is negative or positive. Assets with no type should have a negative value.
In the above example the result should be 10 - 4 - 1 = 5
Is this somehow possible within a single SELECT SUM(value)... statement?
A tricky way (avoiding conditions):
select sum( value * (0.5 - coalesce(t.is_negative, 1)) * 2 )
from assets a
left join types t on t.id = a.type
Another way (more readable):
select sum(value * case when not is_negative then 1 else -1 end)
from assets a
left join types t on t.id = a.type;
Yes, quite easily.
SELECT SUM(IF(is_negative = 1 OR is_negative IS NULL, value * -1, value))
FROM assets a
LEFT JOIN types t ON a.type = t.id
...or very similarly...
SELECT SUM(CASE WHEN COALESCE(is_negative,1)= 1 THEN value * -1 ELSE value END) x
FROM assets x
LEFT
JOIN types y
ON y.id = x.type;

GROUP BY not NULL values

I have a Hive table (no primary key) that looks similar to:
X Y
-------------
1 a
2 a
2 a
1 b
1 b
2 c
2 NULL
1 NULL
2 d
Note the X column can be values other than just 1 and 2.
The query if I don't want to do GROUP BY would be:
SELECT X, Y
FROM my_table
I want to do a GROUP BY operation on column Y where the value isn't NULL. Moreover, I want to keep the NULL value for Y. So the resulting table would look like:
X Y
-------------
1 a
1 b
2 c
2 NULL
1 NULL
2 d
Note, I don't care which X gets selected.
Based on this question, my query would be:
SELECT
IFNULL(Y, UUID()) AS unq_Y,
any(X) AS X
FROM my_table
GROUP BY unq_Y
However, unq_Y would be whatever UUID() returns if Y is NULL, the query result would be:
X unq_Y
-------------
1 a
1 b
2 c
2 UUID()_result
1 UUID()_result
2 d
How can I avoid this?
Turns out, I can just put the NULL check in the GROUP BY clause:
SELECT
any(Y) AS Y,
any(X) AS X
FROM my_table
GROUP BY COALESCE(Y, CAST(reflect("java.util.UUID", "randomUUID") AS STRING));
My version of Hive doesn't support IFNULL() so COALESCE() is a good alternative. My version Hive also doesn't support UUID() so I called reflect() to get unique id.
It's quite simple if the order of result set is not important. Just use union all as follows:
SELECT
X AS X,
Y AS unq_Y
FROM my_table
where y is not null
GROUP BY unq_Y
union all
SELECT
X AS X,
Y AS unq_Y
FROM my_table
where y is null
;
DEMO
Hope it helps!

mysql when I join same table twice aggregate is wrong

I basically have a table that holds counts for every date. I want to create a query that gives me the total # of counts over the entire table, as well as the total for yesterday. But when I try to join the table twice, the aggregates are off. Below is how you can replicate the results.
CREATE TABLE a (id int primary key);
CREATE TABLE b (a_id int, b_id int, date date, count int, primary key (a_id,b_id,date));
INSERT INTO a VALUES (1);
INSERT INTO b VALUES (1, 1, UTC_DATE(), 5);
INSERT INTO b VALUES (1, 2, UTC_DATE(), 10);
INSERT INTO b VALUES (1, 1, UTC_DATE()-1, 7);
INSERT INTO b VALUES (1, 2, UTC_DATE()-1, 12);
SELECT A.id,SUM(B.count) AS total_count,SUM(Y.count) AS y FROM a AS A
LEFT JOIN b AS B ON (B.a_id=A.id)
LEFT JOIN b AS Y ON (Y.a_id=A.id AND Y.date=UTC_DATE()-1)
GROUP BY A.id;
Results in:
+----+-------------+------+
| id | total_count | y |
+----+-------------+------+
| 1 | 68 | 76 |
+----+-------------+------+
The correct result should be:
+----+-------------+------+
| id | total_count | y |
+----+-------------+------+
| 1 | 34 | 22 |
+----+-------------+------+
What's going on here? Is this a bug in mysql or am I not understanding how the joins are working.
No, it's not a bug in MySQL.
Your JOIN conditions are generating "duplicate" rows. (Remove the aggregate functions and the GROUP BY, and you'll see what's happening.
That row from table "a" is matching four rows from table "b". That's all fine and good. But when you add the join to the third table ("y"), each row returned from that third "y" table (two rows) is being "matched" to every row from the "b" table... so you wind up with a total of eight rows in your result set. (That's why the "total_count" is getting doubled.)
To get the result set you specify, you don't need to join that table "b" second time. Instead, just use a conditional test to determine whether that "count" should be included in the "y" total or not.
e.g.
SELECT a.id
, SUM(b.count) AS total_count
, SUM(IF(b.date=UTC_DATE()-1 ,b.count,0)) AS y
FROM a a
LEFT
JOIN b b ON (b.a_id=a.id)
GROUP BY a.id;
Note that the MySQL IF expression can be replaced with an equivalent ANSI CASE expression for improved portability:
, SUM(CASE WHEN b.date=UTC_DATE()-1 THEN b.count ELSE 0 END) AS y
If you did want to do JOIN to that "b" table a second time, you would want the JOIN condition to be such that a row from "y" would match, at most, ONE row from "b", so as not to introduce any duplicates. So you'd basically need the join condition to include all of the columns in the primary key.
(Note that the predicates in the join condition for table "y" guarantee that each from from "y" will match no more than ONE row from "b"):
SELECT a.id
, SUM(b.count) AS total_count
, SUM(y.count) AS y
FROM a a
LEFT
JOIN b b
ON b.a_id=a.id
LEFT
JOIN b y
ON y.a_id = b.a_id
AND y.b_id = b.b_id
AND y.date = b.date
AND y.date = UTC_DATE()-1
GROUP BY a.id;
(To get the first statement to return an identical resultset, with a potential NULL in place of a zero, you'd need to replace the '0' constant in the IF expression with 'NULL'.
, SUM(IF(b.date=UTC_DATE()-1 ,b.count,NULL)) AS y
SELECT A.id,b_count AS total_count,y_count as y
FROM a AS A
LEFT JOIN (select a_id,SUM(B.Count) b_count from b
group by B.A_id) AS B1 ON (B1.a_id=A.id)
LEFT JOIN (select a_id,SUM(Count) y_count from b
where date=UTC_DATE()-1
group by B.A_id) AS Y ON (Y.a_id=A.id)
SQLFiddle Demo