MySQL select boolean fields and create 3rd states - mysql

I'm using MySQL and I want to get a boolean with 3 states (-1,0,1) on existing fields.
E.g if I have col1 = null or row doesn't exist col2 = 0 col3 = 1
Then I do :
SELECT col1, col2, col3 FROM customers
I want to get that :
Output
col1 = -1
col2 = 0
col3 = 1
How it's possible ?
note : In my code I'll use LEFT JOIN in my query so when the row doesn't exist so I think I'll get null.

Something like this:
SELECT
a.a,
COALESCE(b.b, -1) as b
FROM
a LEFT JOIN B ON a.id = b.aid
Suppose we have tables:
A.id, A.a
1, 'hello'
2, 'goodbye'
3, 'what'
B.aid, b.b
1, 1
2, null
When we join them with left join we will get:
A.id, a.a, B.aid, b.b
1, 'hello', 1, 1
2, 'goodbye', 2, null --b.b is null because the row value is null
3, 'what', null, null --b.b is null because there is no row, all b columns are null
COALESCE looks at the arguments in order from left to right, returning the first non null one. If the row in b doesn't exist, or it does exist but b.b is NULL in the table, then COALESCE will turn it into -1:
A.id, a.a, B.aid, b.b
1, 'hello', 1, 1
2, 'goodbye', 2, -1 --b.b is -1 because COALESCE found -1 as the first non null value
3, 'what', null, -1 --b.b is -1 because COALESCE found -1 as the first non null value
If however you want to use 0 if b.b is null but -1 if b.b doesn't exist, you need to CASE WHEN using something that is a value:
SELECT
a.a,
CASE WHEN b.aid IS NULL THEN -1 ELSE COALESCE(b.b, 0) END as b
FROM
a LEFT JOIN B ON a.id = b.aid
Here we inspect one of the columns used in the join, b.aid. If it is null we know the join failed and there is no row in B for that row in A, hence we can CASE WHEN test b.aid for being null and if it is, then put -1 as our "-1 means no row was in b", ELSE we can COALESCE to turn b.b into 0 if it is null. This gives a result like:
A.id, a.a, B.aid, b.b
1, 'hello', 1, 1
2, 'goodbye', 2, 0 --b.b is 0 because CASE WHEN's ELSE block was used, and COALESCE found 0 as the first non null value
3, 'what', null, -1 --b.b is -1 because CASE WHEN's WHEN block fired, because b.aid was null, and CASE WHEN provided -1 as the value

Related

Using Case When in SQL to return different values

I would like to join various table and convert some column values from integer to text like below case. Let's say I have Type_ID: 1, 2, 100, 200, 300, .....
If the Type_ID are 1 and 200, then it will print out High and Good respectively. But if the Type_ID are not 1 and 200, I want it to return original integer value. How can I do that? Thanks.
SELECT A.AID,
CASE WHEN B.Type_ID = '1' THEN 'High' WHEN B.Type_ID = '200' THEN 'GOOD' ELSE (Print Original number value) END AS 'Type'
FROM A, B
WHERE A.AID = B.AID
Expected Result:
AID
Type
1
High
2
499
3
Good
4
Good
5
100
6
300
If I understand correctly, the else value should just be the Type_ID:
SELECT A.AID,
CASE B.Type_ID WHEN '1' THEN 'High'
WHEN '200' THEN 'GOOD'
ELSE CAST(B.Type_ID AS CHAR(50)) END AS Type
FROM A
INNER JOIN B ON A.AID = B.AID;

MySQL SELECT following row with a different column value

I have a tabe like this:
sn(char) ts(int) data(char) flag(tinyint)
'a' 1494825611 'a0' 1
'a' 1494825613 'a1' 0
'a' 1494825617 'a2' 0
'a' 1494825623 'a3' 1
'a' 1494825634 'a4' 1
'b' 1494825644 'b1' 1
'b' 1494825643 'b0' 0
'a' 1494825645 'a5' 1
'a' 1494825648 'a6' 0
'b' 1494825658 'b2' 1
Rows may be in a wrong order (like b1 and b0), so they should be sorted by ts first.
I am trying to make an efficient query for sn to get rows where the current and the next flag differs.
As a result, I'd want something like this for sn 'a':
old_ts ts old_data data flag
1494825611 1494825613 'a0' 'a1' 0
1494825617 1494825623 'a2' 'a3' 1
1494825645 1494825648 'a5' 'a6' 0
and for sn 'b':
old_ts ts old_data data flag
1494825643 1494825644 'b0', 'b1' 1
It's not a problem to create additional columns or tables.
You can use #rowFlag variable. Each row check whether it's equals to flag. If yes set the filter field to 0 to skip it later
select old_ts, ts, old_data, data, new_flag as flag
from
(select
t.ts,
t.data,
case when #rowFlag=flag then 0 else 1 end as filter,
flag as new_flag,
#rowFlag:=flag as old_flag,
#old as old_data,
#old:=data,
#old_ts as old_ts,
#old_ts:=ts
from test t, (select #rowFlag:=-1, #old:=null, #old_ts:=null) as def
where sn='a'
order by ts) as sub
where filter=1 and old_ts is not null;
SQL Fiddle
You can check this, as this contains old value and new values as well. Change new_table with your actual table name.
select a.sn, a.ts as oldts, b.ts as newts,
a.data as old_data, b.data as data, a.flag as old_flag , b.flag as flag
from (
select sn, ts, data, flag ,
if(#oldSn = sn,#rowNumber := #rowNumber + 1,#rowNumber := 1) as row_number,
#oldSn := sn as curentsn
from new_table
order by sn, ts ) a
join (
select sn, ts, data, flag ,
if(#oldSn1 = sn,#rowNumber := #rowNumber + 1,#rowNumber := 1) as row_number,
#oldSn1 := sn as curentsn
from new_table
order by sn, ts ) b on a.sn = b.sn
and a.row_number + 1 = b.row_number
where a.flag != b.flag
Output of above query
sn, oldts, newts, old_data, data, old_flag, flag
a, 1494825611, 1494825613, a0, a1, 1, 0
a, 1494825617, 1494825623, a2, a3, 0, 1
a, 1494825645, 1494825648, a5, a6, 1, 0
b, 1494825643, 1494825644, b0, b1, 0, 1

To check the condition from multiple rows in sql and return true or false

Table X
ColA ColB ColC
------------------------
A 10 Not NULL
B 20 Not NULL
C 10 Not NULL
D 50 Not NULL
E 20 Not Null
I want a statement where columnB in (10,20) then return '1' else '0'
Ignore the rest values in ColB
Example output for above table :
1
It should be similar to-
Select
case
when ColB is in (10,20) the '1' else '0'
from Table X
where
ColC is NOT NULL;
If I'm understanding your question correctly, perhaps you're looking for conditional aggregation:
select max(case when colb in (10,20) then 1 else 0 end) result
from yourtable
SQL Fiddle Demo
Could you specify better your question?
If I've understand it, all you need is an nested IF statement.
SELECT
IF(COLB = 10, 1, IF(COLB = 20, 1, 0)) AS MYRES
FROM
CFGMML_CTARNC01;

How to select for observations that are null for one variable and not null for another?

I need to select observations from a dataset in a way that excludes rows missing certain values, but having others. For example, I have the following variables:
A, dateA, B, dateB, C, dateC
I need to exclude rows that are not null for A, but are missing a dateA value OR are not null for B, but are missing a dateB value OR are not null for C but are missing a dateC value. Also, because my variables are structured so that they can be empty values, I have been using the following to code to identify "null" observations:
WHERE dateA > '';
I'm not sure what to put in my select statement to accomplish this. Any help would be much appreciated! Thanks!
EDIT here would be some example data: (sorry for the awkward formatting)
Obs----A-----dateA
1--------3-----2002-02-13 00:00:00
2--------8-----2009-12-19 00:00:00
3--------0
4--------7
The result I would want would be to select observations 1, 2, and 3, but not 4 because it is missing a value for dateA, but has a value for A. 3 should be included because although it is missing a value for dateA, it has a 0 value for A. I also have other variables, B, dateB, C and dateC that need to be selected for in the same way.
To include these rows we would do:
WHERE (A IS NOT NULL AND A != 0 AND dateA > '')
OR (B IS NOT NULL AND B != 0 AND dateB > '')
OR (C IS NOT NULL AND C != 0 AND dateC > '');
To exclude these we can simply use NOT:
WHERE NOT(
(A IS NOT NULL AND A != 0 AND dateA > '')
OR (B IS NOT NULL AND B != 0 AND dateB > '')
OR (C IS NOT NULL AND C != 0 AND dateC > '')
);
Edit: Update following question clarification.
Is this the badger?
SELECT *
FROM table1 t1
WHERE (a>0 AND dateA > '')
OR (b>0 AND dateB > '')
OR (c>0 AND dateC > '');
or this?
SELECT *
FROM table1 t1
WHERE (a=0 OR (a>0 AND dateA>''))
AND (b=0 OR (b>0 AND dateB>''))
AND (c=0 OR (c>0 AND dateC>''));

MySQL conditionally counting results

I have a query which returns the counts of several different types of records but I now need to further qualify the result set. I am curious if there is an elegant way to combine these statements into a single statement. Basically if column 2 is true increment ND_true and if column 2 is false increment ND_false instead.
sum(if(c.1 = 'ND' and c.2 is true, if(c.2 = 'P', 1, 0), 0)) as 'ND_true'
sum(if(c.1 = 'ND' and c.2 is false, if(c.2 = 'P', 1, 0), 0)) as 'ND_false'
Erm...
select count(*) from `tablename` where [something something something]
Seems like a much better alternative to what you're doing. Either that or you're not explaining very clearly what you are doing and what led you to the solution you have.
One alternative:
Select ...
, C.ND_True As ND_True
, C.ND_False As ND_False
From ...
Cross Join (
Select Sum( Case When C1.P = 1 Then 1 Else 0 End ) As ND_True
, Sum( Case When C1.P = 0 Then 1 Else 0 End ) As ND_False
From SomeTable As C1
Where C1.1 = 'ND'
And C1.P = 'P'
Union All
Select Z.Val, Z.Val
From ( Select 0 As Val ) As Z
Where Not Exists (
Select 1
From SomeTable As C2
Where C2.1 = 'ND'
And C2.P = 'P'
)
) As C
Your query sample although brief is unclear... you are first testing of c1 = 'ND' (string comparison) ANDed with c.2 (implying c.2 is logical), then another if( c.2 = 'P'... ) I'm sure you are abbreviating column names, but this isn't making sense. Is c.2 a logical field or a string field... one or the other.
sum(if(c.1 = 'ND' and c.2 is true, if(c.2 = 'P', 1, 0), 0)) as 'ND_true'
sum(if(c.1 = 'ND' and c.2 is false, if(c.2 = 'P', 1, 0), 0)) as 'ND_false'
Here is a simplified version of what I think you are looking for.. In this case, you are concerned with c.1 being "ND", so put that as your WHERE clause to limit what is retrieved from the table. Then you don't have to re-duplicate it as part of the IF() clause test. Then, just put in the "other" criteria where I have the c.2 expression... Since the clause is identical for what is being tested, the 2nd and 3rd columns trigger which column they will be counted in...
select
sum( if( c.2, 1, 0 )) as ND_True,
sum( if( c.2, 0, 1 )) as ND_False
from
yourTable c
where
c.1 = 'ND'
Ex: Data
col1 col2
AX true
BC true
ND true <-- this row
XY false
ND true <-- this row
ND false <-- this row
AX false
ND true <-- this row
would result in only the 4 marked rows being queried with a final count of
ND_True = 3
ND_False = 1