Country
ID
Period
Type
America
null
20
expired
null
1234
30
expired
null
null
40
expired
Suppose i have a table with this data,
if country is existing eg: America then i fetch associated period i.e 20 from db.
Else i need to check whether particular id is existing then taken 30.
If both are not existing we take the default both null column that is 3rd row which is 40.
So the precedence of fetching period is Country>ID>Default.
select period from table where type = 'expired and ((cntry_nam = 'America' and id is null) or (cntry_nam is null and id = '1234')) and cntry_nam is not null and serv_id is null
Instead of making 3 db calls one for checking if country is present else second db call if id is present then fetch that period. third if both are not present the default in which both cases are null. How can we optimise it into a single db call. I have tried using case statement too it didnot work.
SELECT
(case
when cntry_nam = 'America' and id is null
THEN rr.prd_mnth
else
(case
when cntry_nam is null and id = '1234'
THEN rr.prd_mnth
else
(case
when cntry_nam is null and id is null THEN rr.prd_mnth
end)
end)
end)
FROM table rr where type = 'expired'
You don't need all the nested cases because the cases are tested in order, so that implements the priority you want.
SELECT CASE
WHEN country IS NOT NULL THEN period
WHEN id IS NOT NULL THEN 30
ELSE 40
END AS Period
FROM yourTable
WHERE type = 'expired'
Related
This question already has answers here:
MySQL AVG() return 0 if NULL
(3 answers)
Closed last month.
I have the following structre
id val
1 ...
.
.
2 ...
.
.
3 null
3 null
3 null
4 ...
.
.
Basically each id has multiple no. of values. And an id has either all values as integers or all values as null
What I want is to perform an aggregate (like AVG) on val group by id. If that id has null values, I want to put 5 there.
#1
SELECT id, (CASE SUM(val) WHEN null THEN 5 ELSE AVG(val) END) AS ac FROM tt GROUP BY id
> executes ELSE even for id = 3
In CASE, there should be an aggregate function that when done on null values give null.
I checked SUM and MAX like
SELECT SUM(val) FROM tt WHERE id = 3
> null
and it gives null here but doesn't work in main statement. I guess it is related to the type of equality and hence tried WHEN IS NULL but its a syntax error.
Also, is there some more standard way of indicating group of values as all null rather than using SUM or MAX.
You can use if condition :
select id, If(sum(val) is null, 5, AVG(val)) as average
FROM tt
group by id
check here : https://dbfiddle.uk/Uso9nNTM
The exact problem with your CASE expression is that to check for null in MySQL we have to use IS NULL rather than equality. So use this version:
CASE WHEN SUM(val) IS NULL THEN 5 ELSE AVG(val) END
But we might as well just use COALESCE() to assign an average of 5 for those id groups having all null values.
SELECT id, COALESCE(AVG(val), 5) AS avg_val
FROM tt
GROUP BY id;
Note that the AVG() function by default ignores nulls. Therefore, the expression AVG(val) would only be null if every record in an id group were having null for val.
I have a table where a column is mostly NULL except for one row.
ID STATUS VALUE POS
1 'BAD' 200 0
2 NULL 200 0
3 NULL 300 1
4 'OK' 0 2
if I do
Select * from table where STATUS != 'OK'
I expect
ID STATUS VALUE POS
1 'BAD' 200 0
2 NULL 200 0
3 NULL 300 1
But I get
ID STATUS VALUE POS
1 'BAD' 200 0
I want to know why, I know I can do something else like Where ID = 4, but why the query above returns an empty result for NULL values?
Thanks
Comparing with NULL is always NULL. Think about NULL like it is "unknown value". Does some unknown value is not equal to 'OK'? this is unknown... so the result is NULL.
In logical expressions NULL is treated as FALSE. So you do not receive the rows which you want to receive.
You must either apply additional check for NULL value (WHERE status != 'OK' OR status IS NULL) or convert NULL value to some definite constant value before compare (WHERE COALESCE(status, '') != 'OK').
Pay attention - this interpretation differs from one used in CHECK constraint (including FOREIGN KEY constraint) in which NULL value is treated as "matched".
It isn't possible to use "equal" or "not equal" for NULL values
You MUST use IS NULL or IS NOT NULL e.g:
Select * from table where STATUS != 'OK' OR Status IS NULL
Well, the values aren't null per say, they are in VARCHAR(30) but in decimal form. However some of the records have "NA" in some fields. I would like mysql to skip those rows in SUM calculation when "NA" is present in the fields used for the SUM. Mysql is treating all incalculable fields as 0. The 0 from fields containing "NA" is misleading. I am doing a GROUP BY TABLE.ID.
Edit:
SELECT
SUM(
CASE
WHEN X >1 THEN 1
WHEN X<-1 THEN 2
ELSE 3
END
CASE
WHEN Y >1 THEN 1
WHEN Y <-1 THEN 2
ELSE 3
END)
AS "Col X+Y";
FROM TableA
GROUP BY TableA_ID;
Sometimes X and/or Y = "NA" on certain fields. I get 6 if both X and Y on TableA_ID = 17 or other numbers when one of them is "NA".
Edit (quoting my comment on VARCHAR):
"I tried storing my values as DEC(5,2), but some of the data from Excel have NA's in the fields. I did set X DEC(5,2) NULL and tried inserting NA into it but kept getting an error (cannot be null). I also tried making the default value "NA" but still get an error (cannot be null). I'll add in a sample query as edit."
I got it. I added in another WHERE clause using
WHERE ..... AND(Colx IS NOT NULL OR Coly IS NOT NULL OR ......);
I switched back the values to DEC(3,1) and made the fields NULLable with defaults null if the field value is NULL. I had to understand how to use NULL. I took out the 'NA's in Excel and left those field values blank.
if foo1 is null or NA just sum it as zero (the neutrum value in the addition), otherwise sum the value.
select sum( case when foo1 is null or foo1 = 'NA' then 0 else foo1 end) as sum, foo2
from FooTable group by foo2
or
select sum(foo1) from FooTable
where (foo2 <> 'NA' and foo2 is null) and (foo3 <> 'NA' or foo3 is null )
group by foo4
Bit of a newbie and probably a very basic question to you, but is driving me mad.
I have a mysql table. I have a record which has a record id, and six other fields which contain names of photographs.
So,
Record_id, photo1, photo2, photo3, photo4, photo5, photo6
I want have have the end result where I have a column called 'TOTAL' which shows the number of how many records have photographs in them as a TOTAL. So, Record 1 may have a total of 5 photographs, record 2 may have 3 photographs, and record 3 may have a total of NO records for that record etc?
Now some of the photographs names which are uploaded to the field may contain numbers, ie, photo244.jpg, or pic3993.jpg etc - so I don't want these numbers added together, I am just looking for whether the field has a name in it etc, and this would be counted as 1 to add to the total. So the end result in on the page is that record 13 (for example) has a total of 4 photographs etc - sorry if not a good explanation!
It may have something to do with SUM or COUNT, but have spent ages trying to get combination or correct key/syntax! Can anyone help please by giving an example of the mysql select statement - would be grateful!
I presume that if there is no photo, then the field photoX is null or is empty.
So use CASE for output 0 if the field is null or empty, 1 else.
SELECT Record_id
,
CASE WHEN (photo1 IS NULL OR photo1 = '') THEN 0 ELSE 1 END
+ CASE WHEN (photo2 IS NULL OR photo2 = '') THEN 0 ELSE 1 END
+ CASE WHEN (photo3 IS NULL OR photo3 = '') THEN 0 ELSE 1 END
+ CASE WHEN (photo4 IS NULL OR photo4 = '') THEN 0 ELSE 1 END
+ CASE WHEN (photo5 IS NULL OR photo5 = '') THEN 0 ELSE 1 END
+ CASE WHEN (photo6 IS NULL OR photo6 = '') THEN 0 ELSE 1 END
AS Total
FROM myTable
It will the best query:
SELECT
Record_id,
(6 - IFNULL(photo1,1) - IFNULL(photo2,1) - IFNULL(photo3,1) - IFNULL(photo4,1) - IFNULL(photo5,1) - IFNULL(photo6,1)) AS TOTAL
FROM
table
Something like this will give you a count by Photo1, Photo2, etc.:
SELECT
SUM(CASE WHEN photo1 IS NOT NULL THEN 1 END) AS Photo1Count,
SUM(CASE WHEN photo2 IS NOT NULL THEN 1 END) AS Photo2Count,
SUM(CASE WHEN photo3 IS NOT NULL THEN 1 END) AS Photo3Count,
SUM(CASE WHEN photo4 IS NOT NULL THEN 1 END) AS Photo4Count,
SUM(CASE WHEN photo5 IS NOT NULL THEN 1 END) AS Photo5Count
FROM MyTable
Something like this will count how many rows have at least one photograph:
SELECT SUM (
CASE WHEN
photo1 IS NOT NULL OR
photo2 IS NOT NULL OR
photo3 IS NOT NULL OR
photo4 IS NOT NULL OR
photo5 IS NOT NULL THEN 1 END)
FROM MyTable
Note that these queries are for grand totals. They don't show activity by row. If activity by row is needed, try the answers from Scorpi0 or Michael Sivolobov.
I am getting an inconsistent result from below two SQL queries.
Query1 : select (case when 'Abc' = null then 1 else 0 end) from dual
Query2 : select (case when ('Abc' <> null) then 1 else 0 end) from dual
Result for both queries same i.e
0
What's wrong am I missing some thing ?
NOTE : : I know I can use IS NULL and IS NOT NULL but my question is why result from above queries is inconsistent.
EDIT : Added from answer of #ppeterka.
select (case when null = null then 1 else 0 end) from dual
This returns 0 too. Null is not even equal to itself.
But then what does this return?
select (case when null <> null then 1 else 0 end) from dual
0 again
SQLFiddle link
Because NULL is unknown that is why the result is 0. When you want to compare a column or a value if it is null or not, use IS NULL or IS NOT NULL.
select (case when 'Abc' IS null then 1 else 0 end) from dual -- 0
select (case when ('Abc' IS NOT null) then 1 else 0 end) from dual -- 1
SQLFiddle Demo
The result of comparing anything to NULL, even itself, is always NULL(not TRUE or FALSE).
Searched CASE expression:
If no Boolean_expression evaluates to TRUE, the Database Engine returns the else_result_expression if an ELSE clause is specified, or a NULL value if no ELSE clause is specified.
In your case the result always will be 0, because 0 in ELSE clause
To add a bit of twist to this, try this out:
select (case when null = null then 1 else 0 end) from dual
This returns 0 too. Null is not even equal to itself.
But then what does this return?
select (case when null <> null then 1 else 0 end) from dual
This returns 0 again! Oh holy... It is not even not equal to itself, while it is not equal to itself... Quite a situation to grasp without getting insane...
Why to keep this all in mind? - one might ask
One example is indexing: in Oracle, indexes don't work the way one would expect them to work on NULL values where a column permits the use of that value. This means that given an index, if all the values (fields, functions on fields, etc) of a row that are included in the index are all NULL, that row won't be indexed in that given index. So this means that an index, that has only one value indexed (for example, a field directly), a null value would mean that row not to be included in the index.
To overcome this
it might be advisable to add an index with a distinct, exact value semantically representing the NULL meaning, like NVL(mynullcol,-1) on a column only containing positive integers to be able to query them quickly.
or you could add a constant value to form a "semi-multivalue" index, that indexes all rows, where one can be null, as the other is a constant. (create index idx_myindex on table(column_with_nulls,1); )
(This question and this article detail this subject in a bit more depth)
Another example is ordering...
select (case when null < null then 1 else 0 end) from dual;
select (case when null > null then 1 else 0 end) from dual;
Both 0. This is OK... We expected this by now... And what about this?
select (case when 'Abc' > null then 1 else 0 end) from dual;
select (case when null > 'Abc' then 1 else 0 end) from dual;
Uh-oh... Both 0 again. This might be an issue - how is ordering going to work?
select col_1 from
(select null as col_1 from dual)
union all (select 'Abc' as col_1 from dual)
union all (select null as col_1 from dual)
union all (select null as col_1 from dual)
order by col_1
This however consistently returns:
Abc
null
null
null
Using ... order by col_1 DESC returns:
null
null
null
Abc
So from this, on an empirical basis, it does seem that 'Abc' < null... However, as per the valuable comment of #ypercube:
the sort order can be set with the NULLS LAST and NULLS FIRST modifiers (at least in Oracle).
What you observe is the default sort order when the ORDER BY has no modifier
NULL is a twisted business, it is wise to steer away from it if it is possible... (And this is not only true for SQL, but for certain situations in OOP languages too.)
You can't use <> or = with nulls. You need to say
select (case when 'Abc' is null then 1 else 0 end) from dual
and
select (case when 'Abc' is not null then 1 else 0 ) from dual
It is not inconsistent.
if you have 2 objects A,B then it's one of the following three:
A equals B
A not equals B
you cannot compare A and B
It's like examining if (0/0 > 0) or (0/0 < 0) or (0/0 = 0). You just cannot compare them. every option is false
For your example: case checks if your argument is true
argument ('abc'=null) is not true, it's null
argument ('abc'<>null) is not true, it's null
The value NULL means the data value for the column is Unknown. A NULL is not synonymous with Zero, or zero length string or blank.
Anything you compare with NULL will result in Unknown (NULL).
Please check this to clear your doubts. To have the correct result, use IS NULL or IS Not NULL as you already know.