How to identify null values using json_extract mysql 8.0 - mysql

What would be the right way to identify null value when using JSON_EXTRACT,
I want to use a case statement to identify null values in a json field and if the value is null replace it with another value in this case 1.
CREATE TABLE `Log` (
`change` json DEFAULT NULL
) ENGINE=InnoDB AUTO_INCREMENT=345 DEFAULT CHARSET=utf32 COLLATE=utf32_unicode_ci;
insert into `Log` (`change`) values (JSON_OBJECT('documentNumber', 2));
insert into `Log` (`change`) values (JSON_OBJECT('documentNumber', null));
select case
when isnull(JSON_EXTRACT(`change`, '$.documentNumber')) = 1 then '1'
else JSON_EXTRACT(`change`, '$.documentNumber')
end as 'result'
from `Log`;
For this query i am getting result,
result
2
null
but i am expecting,
result
2
1
dbfiddle

JSON 'null' literal is not NULL value.
See this demo:
CREATE TABLE `Log` (
`change` json DEFAULT NULL
) ENGINE=InnoDB AUTO_INCREMENT=345 DEFAULT CHARSET=utf32 COLLATE=utf32_unicode_ci;
insert into `Log` (`change`) values (JSON_OBJECT('documentNumber', 2));
-- JSON 'null'
insert into `Log` (`change`) values (JSON_OBJECT('documentNumber', null));
-- no key, this will produce regular NULL
insert into `Log` (`change`) values (JSON_OBJECT('documentNumberX', null));
select `change`,
case
when isnull(JSON_EXTRACT(`change`, '$.documentNumber')) = 1 then '1'
else JSON_EXTRACT(`change`, '$.documentNumber')
end as 'result',
JSON_EXTRACT(`change`, '$.documentNumber') IS NULL test1,
JSON_EXTRACT(`change`, '$.documentNumber') = CAST('null' AS JSON) test2,
case when JSON_EXTRACT(`change`, '$.documentNumber') = CAST('null' AS JSON)
then '1'
else JSON_EXTRACT(`change`, '$.documentNumber')
end as 'result2'
from `Log`;
fiddle

Related

MySQL update if exists else insert throws syntax error

Trying to update existing records based not on ID but specific usernames with no luck. I wrote the following query but I got a syntax error I can't find.
IF EXISTS (SELECT 1 FROM users WHERE username = 'REMOTEUSER1')
THEN
BEGIN
UPDATE users
SET username = 'REMOTEUSER1', password = 'BJxp98YkVbt4', exp_date = '1650991560', member_id = 1, is_mag = '0', play_token = '', reseller_notes = ''
WHERE username = 'REMOTEUSER1'
END;
ELSE
BEGIN
INSERT INTO users (
username,
password,
exp_date,
member_id,
is_new,
play_token,
reseller_notes
) VALUES (
'REMOTEUSER1',
'BJxp98YkVbt4',
'1650991560',
1,
0,
'',
''
)
END;
END IF;
The IF-ELSE conditional statement construct is supported to be used through FUNCTIONS or STORED PROCEDURES that can't use it like a normal query.
If your username column is UNIQUE index or PRIMARY KEY I would use INSERT ... ON DUPLICATE KEY UPDATE Statemen
INSERT INTO users (
username,
password,
exp_date,
member_id,
is_new,
play_token,
reseller_notes
) VALUES (
'REMOTEUSER1',
'BJxp98YkVbt4',
'1650991560',
1,
0,
'',
''
) ON DUPLICATE KEY UPDATE
password = 'BJxp98YkVbt4',
exp_date = '1650991560',
member_id = 1,
is_mag = '0',
play_token = '',
reseller_notes = '';
sqlfiddle
If is_mag is a bit(1) (boolean), then it's likely the update portion where you set it to '0'
either set the boolean to an integer value of 0, or prefix it with b
i.e.
my_bool = b'0'

MySQL: detecting a text "NULL" or 0 field and changing it to proper NULL

I have the following bit of code
UPDATE
table_one
SET
field_one = CASE
WHEN field_one = 'NULL' OR field_one = 0
THEN NULL
ELSE field_one
END
So I want to see if the field has a string "NULL" or a zero (0) value. if it does then it should be set to a NULL within the database.
The issue I'm having is that it's setting everything to NULL in some fields while other fields are okay.
Is there anything wrong with the code?
UPDATE table_one
SET field_one = NULL
WHERE field_one = 'NULL'
OR field_one = '0'
UPDATE table_one SET field_one = NULL WHERE field_one IN ( 0 , 'NULL');

Using CAST with an insert into ... select

I am trying to cast some bad data into proper data using CAST(column AS DECIMAL(7,2)), which works when just SELECTing, but once combined with an INSERT statement, the statement fails:
/* setup */
drop table if exists dst;
create table dst (
id int not null auto_increment
, columnA decimal(7,2)
, primary key (id)
);
drop table if exists src;
create table src (
id int not null auto_increment
, columnA varchar(255)
, primary key (id)
);
insert into src (columnA) values ('');
/* test */
/* This works as I would like it to*/
select CAST(columnA AS decimal(7,2)) from src; /* returns 0.00 */
/* This fails */
insert into dst (columnA)
select CAST(columnA AS decimal(7,2)) from src;
/*0 19 21:01:56 insert into dst (columnA)
select cast(columnA as decimal(7,2)) from src Error Code: 1366. Incorrect decimal value: '' for column '' at row -1 0.000 sec*/
Edit: this is a pared down reproduction example - the data I am
working with is much more varied than just an empty string - it might
also be a non-numeric string value or a numeric value that is outside
of the bounds of decimal(7,2) - in which the CAST statement works
the way I would like it to when only in a SELECT but fails when
trying to use them as part of the INSERT.
Am I doing something wrong, or is there another way to achieve what I am looking for?
I am using MYSQL 5.6.11 on WIN 7 x64
Set explicitly the value for the empty string with CASE or IF:
SELECT CASE WHEN columnA = '' THEN 0 ELSE CAST(columnA AS decimal(7,2)) END
FROM src;
SELECT IF(columnA <> '', CAST(columnA AS decimal(7,2)), 0)
FROM src;
Or use 2 SELECTs with UNION ALL :
SELECT CAST(columnA AS decimal(7,2))
FROM src
WHERE columnA <> ''
UNION ALL
SELECT 0
FROM src
WHERE columnA = '';
You can try using REGEXP to filter out any irregularities in source data:
INSERT INTO dst (columnA)
SELECT CAST(CASE
WHEN columnA REGEXP '^[0-9]{0,7}(\.[0-9]{0,2})$' THEN columnA
ELSE 0
END AS decimal(7,2))
FROM src;
SQL Fiddle Demo here

MySQL Trigger checking for existing rows with possible NULL values

I have an InnoDB table with a unique index on performance_id, ticket_rank_id and ticket_type_id.
All of these id's have relations to other tables, but their values can also be NULL.
MySQL allows duplicate rows if one of the column values is NULL so I decided to build a trigger for this problem.
CREATE TRIGGER `before_insert_performance_tickets`
BEFORE INSERT ON `performance_tickets` FOR EACH ROW BEGIN
DECLARE num_rows INTEGER;
SELECT COUNT(*) INTO num_rows FROM performance_tickets
WHERE performance_id = NEW.performance_id
AND ticket_rank_id = NEW.ticket_rank_id
AND ticket_type_id = NEW.ticket_type_id;
IF num_rows > 0 THEN
// Cancel insert action
ELSE
// Perform insert action
END IF;
END
The problem is AND ticket_rank_id = NEW.ticket_rank_id where I have to check if ticket_rank_id is NULL or has a value.
AND ticket_rank_id = NULL does not work, it only works if i do AND ticket_rank_id IS NULL.
Is there any slick solution for this or do I have to write separate queries depending on NEW.ticket_rank_id and NEW.ticket_type_id being NULL or not?
You need to add extra OR condition for NULL values (ticket_rank_id IS NULL OR ticket_rank_id = NEW.ticket_rank_id) because NULL compared with anything return FALSE. Try this query:
SELECT COUNT(*)
INTO num_rows
FROM performance_tickets
WHERE performance_id = NEW.performance_id
AND (ticket_rank_id IS NULL OR ticket_rank_id = NEW.ticket_rank_id)
AND (ticket_type_id IS NULL OR ticket_type_id = NEW.ticket_type_id);
I think I figured it out:
SELECT COUNT(*) INTO num_rows FROM performance_tickets
WHERE performance_id = NEW.performance_id
AND IF(NEW.ticket_rank_id IS NULL, ticket_rank_id IS NULL, ticket_rank_id = NEW.ticket_rank_id)
AND IF(NEW.ticket_type_id IS NULL, ticket_type_id IS NULL, ticket_type_id = NEW.ticket_type_id)
Seems to work, now I have to figure out how to abort the insert if num_rows == 1. But that's a different problem.
Thanks anyways ;)

Get the other field value in case of NULL

CREATE TABLE itemmast (
cid INTEGER,
description varchar(30),
defaultprice DOUBLE);
INSERT INTO itemmast VALUES (1, 'Item 1', '0');
INSERT INTO itemmast VALUES (2, 'Item 2', '8');
INSERT INTO itemmast VALUES (3, 'Item 3', '5.5');
INSERT INTO itemmast VALUES (4, 'Item 4', '0');
INSERT INTO itemmast VALUES (5, 'Item 5', '59');
CREATE TABLE specialprice (
cid INTEGER,
username varchar(30),
newprice DOUBLE);
INSERT INTO specialprice VALUES (4, 'UserS', '10');
INSERT INTO specialprice VALUES (2, 'UserX', '115');
I want to get the value of [newprice] for specific user just in case its in the [specialprice] table, otherwise get the [defaultprice] from the [itemmast] table
So far I have this but not working as expected.
SELECT itemmast.*,newprice,
CASE specialprice.newprice
WHEN NULL
THEN itemmast.defaultprice
ELSE
specialprice.newprice
END AS itemprice
FROM itemmast
LEFT JOIN specialprice ON specialprice.cid = itemmast.cid
where itemmast.cid = '1' and username= 'UserS'
Change your CASE statement into
CASE WHEN specialprice.cid IS NULL
THEN itemmast.defaultprice
ELSE specialprice.newprice
END as RealPrice
SQLFiddle Demo
Or alternatively use COALESCE
COALESCE(specialprice.newprice, itemmast.defaultprice)
SQLFiddle Demo
Why not rather us IFNULL
•IFNULL(expr1,expr2)
If expr1 is not NULL, IFNULL() returns expr1; otherwise it returns
expr2. IFNULL() returns a numeric or string value, depending on the
context in which it is used.
mysql> SELECT IFNULL(1,0);
-> 1
mysql> SELECT IFNULL(NULL,10);
-> 10
mysql> SELECT IFNULL(1/0,10);
-> 10
mysql> SELECT IFNULL(1/0,'yes');
-> 'yes'
So in your example, something like
SELECT itemmast.*,
newprice,
IFNULL(specialprice.newprice, itemmast.defaultprice) itemprice
FROM itemmast LEFT JOIN
specialprice ON specialprice.cid = itemmast.cid
For a more generic approach, use IF(,,):
IF (specialprice.newprice IS NULL, specialprice.defaultprice, specialprice.newprice)
reference: http://dev.mysql.com/doc/refman/5.1/en/control-flow-functions.html#function_if
The other answers are OK, but the reason your SQL is not working is that null is never equal to anything, not even null, and your case statement is comparing the value of specialprice.newprice with null which will never be true.
The only test that is true for null is the special is null test, so you must use that:
case when specialprice.newprice is null ... else ... end
or use a built-in funciton:
select ifnull(specialprice.newprice, itemmast.defaultprice) ...