Unable to enter null value in bigint or double datatype in mariadb table using python - mysql

I am inserting records in maria db table from a file using python. Input file has header. Population and Avg_Height columns in the file are partial empty. I want it to go as null value in table as well. Population column in table is set as bigint(20) and can accept null value. I am trying the below code -
Table Definition -
CREATE TABLE `local_db`.`table_x` (
`Unique_code` varchar(50) NOT NULL,
`city` varchar(200) DEFAULT NULL,
`state` varchar(50) DEFAULT NULL,
`population` bigint(20) DEFAULT NULL,
`Avg_Height` double DEFAULT NULL,
`Govt` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
try:
connection = mysql.connector.connect(host='localhost',
database='local_db',
user='root',
password='root',
port = '3306')
input_file = "input_file"
csv_data = csv.reader(open(input_file))
next(csv_data)
cursor = connection.cursor()
for row in csv_data:
cursor.execute("""
INSERT INTO table_x(Unique_code,city,state,population,Avg_Height,Govt)
VALUES(%s,%s,%s,%s,%s,%s)
ON DUPLICATE KEY UPDATE city = VALUES(city),state = VALUES(state), \
population = VALUES(population),Avg_Height = VALUES(Avg_Height),Govt = VALUES(Govt)""")
connection.commit()
print(cursor.rowcount, "Record inserted successfully into table_x")
cursor.close()
except mysql.connector.Error as error:
print("Failed to insert record into table_x table {}".format(error))
finally:
if (connection.is_connected()):
connection.close()
print("MySQL connection is closed")
But I am getting below error -
Failed to insert record into table_x table 1366 (22007): Incorrect integer value: '' for column `local_db`.`table_x`.`population` at row 1
MySQL connection is closed
Please suggest what code changes I can do here to handle this situation.

You need to insert null instead of '' empty string. here is the demo.
CREATE TABLE `table_x` (
`Unique_code` varchar(50) NOT NULL,
`city` varchar(200) DEFAULT NULL,
`state` varchar(50) DEFAULT NULL,
`population` bigint(20) DEFAULT NULL,
`Avg_Height` double DEFAULT NULL,
`Govt` varchar(50) DEFAULT NULL
) ;
INSERT INTO table_x(Unique_code,city,state,population,Avg_Height,Govt)
values
('xyz','abc','dd',null ,3, 'fd');

You need to insert NULL in that situation instead of an empty string. You can pre-process the row list to convert empty strings into None, which will have the same effect:
for row in csv_data:
row = [None if v == '' else v for v in row]
# write to table

Related

MariaDb vs MySQL JSON_ARRAYAGG JSON_OBJECT Without Escaping

I have a select query, which works just fine in my localhost MySQL database environment. It should return json object.
When I run the same query on my hosted public server with MariaDB 10.5.15 installed, the returned json includes several backslashes, escaping characters.
Here is the code:
SELECT
json_object(
'id', C1.Category1ID,
'text', C1.Category1Name,
'nodes', JSON_ARRAYAGG(
JSON_OBJECT(
'id', C2.Category2ID,
'text', C2.Category2Name,
'nodes', C2.nodes,
'class', 'nav-level-2',
'href', 'admin-categories-2.php'
)
),
'class', 'nav-level-1',
'href', 'admin-categories-1.php'
) AS JSON
FROM categories_1 C1
LEFT JOIN (
SELECT
C2.Category1ID,
C2.Category2ID,
C2.Category2Name,
JSON_ARRAYAGG(
JSON_OBJECT(
'id', C3.Category3ID,
'text', C3.Category3Name,
'class', 'nav-level-3',
'href', 'admin-categories-3.php'
)
) as nodes
FROM categories_2 C2
LEFT JOIN categories_3 C3 ON C3.Category2ID = C2.Category2ID AND C3.Category3Status = 1
WHERE C2.Category2Status = 1
GROUP BY C2.Category2ID
ORDER BY C2.Category2Order, C3.Category3Order
) C2 ON C2.Category1ID = C1.Category1ID
WHERE C1.Category1Status = 1
GROUP BY C1.Category1ID
ORDER BY C1.Category1Order
;
My question is how to write this query correctly for MariaDB.
I am attaching result from MySQL (img1) and MariaDB (img2).
I am attaching create and insert statements for db here:
CREATE TABLE `categories_1` (
`Category1ID` int(11) NOT NULL AUTO_INCREMENT,
`Category1Name` varchar(45) DEFAULT NULL,
`Category1Name_FR` varchar(45) DEFAULT NULL,
`Category1Photo` varchar(45) DEFAULT NULL,
`Category1Order` int(3) DEFAULT NULL,
`Category1Status` int(1) DEFAULT 1,
PRIMARY KEY (`Category1ID`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COMMENT='Top level category'
CREATE TABLE `categories_2` (
`Category2ID` int(11) NOT NULL AUTO_INCREMENT,
`Category2Name` varchar(45) DEFAULT NULL,
`Category2Name_FR` varchar(45) DEFAULT NULL,
`Category2Order` int(3) DEFAULT NULL,
`Category2Status` int(1) DEFAULT 1,
`Category1ID` int(11) DEFAULT NULL COMMENT 'To which parent level category it fits',
PRIMARY KEY (`Category2ID`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='Mid level category'
CREATE TABLE `categories_3` (
`Category3ID` int(11) NOT NULL AUTO_INCREMENT,
`Category3Name` varchar(45) DEFAULT NULL,
`Category3Name_FR` varchar(45) DEFAULT NULL,
`Category3Order` int(3) DEFAULT NULL,
`Category3Status` int(1) DEFAULT 1,
`Category2ID` int(11) DEFAULT NULL COMMENT 'To which parent level category it fits',
PRIMARY KEY (`Category3ID`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COMMENT='Bottom level category'
INSERT INTO `categories_1` VALUES (1,'Meat','Meat-fr','meat.jpg',1,1),(2,'Fish & Sea Food',NULL,'fish.jpg',2,1),(3,'Fruit & Vegetables',NULL,'fruit-veg.jpg',3,1),(4,'Test L1',NULL,'categories-default.jpg',4,0);
INSERT INTO `categories_2` VALUES (1,'Beef','Feef-fr',1,1,1),(2,'Lamb',NULL,2,1,1),(3,'Pork',NULL,3,1,1),(4,'Veal',NULL,4,1,1),(5,'Poultry-Fowl',NULL,6,1,1),(6,'Sausages and Bacon',NULL,5,1,1),(7,'Salmon',NULL,8,1,2),(8,'Flat Fish',NULL,9,1,2),(9,'Common Fish',NULL,10,1,2),(10,'Squid family',NULL,11,1,2),(11,'Shellfish',NULL,12,1,2),(12,'Tuna',NULL,13,1,2),(13,'Other Fish',NULL,14,1,2),(14,'TEST L2',NULL,7,0,1);
INSERT INTO `categories_3` VALUES (1,'Specialist Beef','Specialist Beef-fr',1,1,1),(2,'Wagyu',NULL,2,1,1),(3,'Japanese Wagyu',NULL,3,1,1),(4,'Other Beef',NULL,4,1,1),(5,'All Lamb',NULL,6,1,2),(6,'All Pork',NULL,5,1,3),(7,'All Veal',NULL,7,1,4),(8,'All Poultry-Fowl',NULL,11,1,5),(9,'Pork Sausages',NULL,8,1,6),(10,'Other meats',NULL,9,1,6),(11,'Bacon',NULL,10,1,6),(12,'All Salmon',NULL,12,1,7),(13,'All Flat Fish',NULL,13,1,8),(14,'All Common Fish',NULL,14,1,9),(15,'All Squid family',NULL,15,1,10),(16,'All Shellfish',NULL,16,1,11),(17,'All Tuna',NULL,17,1,12),(18,'All Other Fish',NULL,18,1,13),(19,'TEST L3',NULL,999,0,14);
MariaDB have no JSON datatype (JSON keyword is an alias for LONGTEXT keyword only), it may treate string type value as JSON only.
You use construction JSON_ARRAYAGG( JSON_OBJECT( .... In MariaDB the value produced by JSON_OBJECT is string ! It is one solid string, not complex value of JSON datatype. Hence during JSON_ARRAYAGG this solid string value which contains the chars needed in quoting is processed, and all doublequote chars are quoted.
See FIDDLE, especially last and pre-last code blocks. In pre-last block pay special attention to the doubequote chars which wraps the whole value (not inner doublequotes which are quoted by the slashes).
I do not see the way to fix this in MariaDB. There is no method to tell the function that the value provided as an argument is not string but JSON - there is no such datatype.
Wait until MariaDB implements JSON datatype (if) and upgrade.

'Table doesn't exist' with creation using execute() function with 'multi=True' parameter

MySQL 5.6.
I don't understand why if I use multi=True parameter table is not created. I don't find any information about it in documentation. If I separate all queries it works, but I don't want to separate them.
from mysql import connector as connector
conn = connector.connect(
user='root',
password='root',
host='127.0.0.1',
database='ra'
)
conn.autocommit = True
cursor = conn.cursor(dictionary=True, buffered=True)
sql = """
DROP TABLE IF EXISTS tab01;
CREATE TABLE tab01 (nzu DECIMAL(5,0) PRIMARY KEY,
nbr DECIMAL(3,0) DEFAULT NULL,
nland DECIMAL(5,0) DEFAULT NULL,
nlandtype DECIMAL(5,0) DEFAULT NULL,
nzuarea DECIMAL(12,1) DEFAULT NULL,
nzuareaos DECIMAL(12,1) DEFAULT NULL) ENGINE = MyISAM;
INSERT INTO tab01 (SELECT zu.nzu, zu.nbr, zu.nland,
IF(ISNULL(lands.nlandtype),0,lands.nlandtype) AS nlandtype,
0.0 AS nzuarea, 0.0 AS nzuareaos
FROM (SELECT * FROM zu WHERE nhoz = '6204000001') AS zu
LEFT JOIN lands AS lands ON zu.nland=lands.nland
ORDER BY nzu);
"""
cursor.execute(sql, multi=True)
cursor.execute('SELECT * FROM tab01')
# mysql.connector.errors.ProgrammingError: 1146 (42S02): Table 'ra.tab01' doesn't exist
result = cursor.fetchone()
Are you sure your CREATE works? I believe ENGINE option has to be at the end of CREATE statement:
CREATE TABLE tab01 (
nzu DECIMAL(5,0) PRIMARY KEY,
nbr DECIMAL(3,0) DEFAULT NULL,
nland DECIMAL(5,0) DEFAULT NULL,
nlandtype DECIMAL(5,0) DEFAULT NULL,
nzuarea DECIMAL(12,1) DEFAULT NULL,
nzuareaos DECIMAL(12,1) DEFAULT NULL
) ENGINE = MyISAM;
Also this statement:
cursor.execute(sql, multi=True)
creates an iterator over the results. It looks like it's lazy (i.e., it executes SQL statements only as needed). You're never asking for the results for the second statement, so it is only executing the first one. Try:
for _ in cursor.execute(sql, multi=True): pass

MySQL NULL field asking for value while INSERT

Mysql Version: 5.7.x
Query:
INSERT INTO `products_manufacturer`
SET `website_id` = 27,
`name` = 'YAZAKI CORP',
`url` = 'http://www.speclocator.com/mfg_category.php?manufacturename=YAZAKI+CORP',
`enabled` = true,
`rectified_manufacturer_id` = NULL,
`logo` = NULL;
Error Code: 1364. Field 'facebook' doesn't have a default value 0.000 sec
Table Structure attached as screenshot.
Try below query then after inserting data
ALTER TABLE products_manufacturer MODIFY COLUMN facebook VARCHAR(255) NULL DEFAULT '0.000';

comparing a varchar field to the number zero returns as if its a true match

i am looking for some work around on this problem and/or i need it to reply with an empty result or the boolean false.
using the sql statement on MySQL
`SELECT * FROM users WHERE verify = 0 LIMIT 1`
the code above returns the second row in the table.
Here is the table i used:
CREATE TABLE IF NOT EXISTS `users` (
`user_id` bigint(20) unsigned NOT NULL,
`username` varchar(30) NOT NULL,
`password` varchar(60) NOT NULL,
`email` varchar(30) NOT NULL,
`firstname` varchar(30) DEFAULT NULL,
`lastname` varchar(30) DEFAULT NULL,
`status` tinyint(1) NOT NULL DEFAULT '1',
`verify` varchar(32) NOT NULL,
`verified` bit(1) NOT NULL DEFAULT b'0'
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=latin1;
INSERT INTO `users` VALUES(1, 'admin', '$2y$10$id6rHN6Zy8XHmCkWlAMvGO8pr3K4OD1zfFAZMaVgoGXbezY8SXcT2', 'admin#admin.com', 'Firstname', 'Lastname', 1, '21232f297a57a5a743894a0e4a801fc3', b'1');
INSERT INTO `users` VALUES(36, 'client', '$2y$10$gdtPImQhYoCIiTpTs/veW.BXsWUz6Zcxb.TY6XXQNO6uf5Q7kx99.', 'client#client.com', 'client', 'client', 1, 'cf3873cdefaefa2cc2c4f1efbba23202', b'0');
--edit, sorry did not specify want i wanted
i don't want it to return anything or maybe how do i make it that it would return false or empty result.
right now, i am using a nasty workaround by modifying the zero result and making it a text "zero" before passing it to the sql query. works but, if there is something better way that you can suggest it would be much appreciated.
I'm not sure what you expect to happen. When you write:
where verify = 0
MySQL has a conundrum. verify is a character string and 0 is an integer. They are not comparable, so MySQL converts one to the other. In this case, it will convert verify to an integer value, getting 0, and they match.
If you want a string comparison, then use:
where verify = '0'
However, that returns the same result.
If you want it to compare to the character value of 0, then perhaps you want:
where verify = '\0'

Error Delphi / MySQL / Parameters

Well, the situation is: I have 1 TComboBox called cboTipDocIden and 1 TEdit called txtDocIdenSolic.
The values of cboTipDocIden are: "1.DNI","2.RUC".
The component TUniQuery is called q_DetSolicitante.
The SQL Sentence target is:
SELECT oper_solicitante.id_solicitante, oper_solicitante.ape_pat, oper_solicitante.ape_mat,
oper_solicitante.nombre, oper_solicitante.direcc_idtipcalle, oper_solicitante.direcc_nombrecalle,
oper_solicitante.direcc_nro, oper_solicitante.idvinculo_fk
FROM oper_solicitante
WHERE oper_solicitante.tipDocIden = :TipDocIden AND
oper_solicitante.nroDocIden = :NroDocIden
The SQL is executed on OnExit event of txtDocIdenSolic, here the code:
procedure TForm1.txtDocIdenSolicExit(Sender: TObject);
var
TipDocIden, NroDocIden:string;
begin
if(length(txtDocIdenSolic.Text)>0) then
begin
TipDocIden:=chr(39)+copy(cboTipDocIden.Text,1,1)+chr(39);
NroDocIden:=chr(39)+trim(txtDocIdenSolic.Text)+chr(39);
q_DetSolicitante.Close;
q_DetSolicitante.Params[0].AsString:=TipDocIden;
q_DetSolicitante.Params[1].AsString:=NroDocIden;
q_DetSolicitante.Open;
if(length(q_DetSolicitante.FieldByName('id_solicitante').AsString)=0) then
begin
stbar.Panels[0].text:='Nuevo Solicitante...';
txtApePat.SetFocus;
end
else
begin
stbar.Panels[0].Text:='Solicitante Reiterativo...';
txtApePat.Text:=q_DetSolicitante.FieldByName('ape_pat').AsString;
txtApeMat.Text:=q_DetSolicitante.FieldByName('ape_mat').AsString;
txtNombre.Text:=q_DetSolicitante.FieldByName('nombre').AsString;
end;
end
else
msg1.Execute;
end;
Finally, the table structure is:
CREATE TABLE `oper_solicitante` (
`id_solicitante` int(11) NOT NULL,
`tipDocIden` char(1) NOT NULL,
`nroDocIden` varchar(11) NOT NULL,
`ape_pat` varchar(50) NOT NULL,
`ape_mat` varchar(50) NOT NULL,
`nombre` varchar(50) NOT NULL,
`direcc_idtipcalle` int(11) NOT NULL,
`direcc_nombrecalle` varchar(80) NOT NULL,
`direcc_nro` varchar(15) NOT NULL,
`idvinculo_fk` int(11) NOT NULL,
PRIMARY KEY (`id_solicitante`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Well, the SQL returns zero rows inside Delphi but when i change the parameters for literal values the SQL works.
Thanks for your useful help.
Remove the chr(39) characters around your parameter values. Using Params[].AsString allows the database driver to properly quote them, and you're adding (doubling) them and thus causing the query to fail.
TipDocIden:= copy(cboTipDocIden.Text,1,1);
NroDocIden:= trim(txtDocIdenSolic.Text);
q_DetSolicitante.Close;
q_DetSolicitante.Params[0].AsString := TipDocIden;
q_DetSolicitante.Params[1].AsString := NroDocIden;
q_DetSolicitante.Open;