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.
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
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'
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;