I've written a stored procedure to update and insert records into a MariaDB version 15.1, distrib 10.0.13-MariaDB for Win64 (x86).
My stored procedure:
exitProc:BEGIN
#--
# procCreateUser
# Parameters:
# biPerson_id, the id of the user, NULL if new
# vcFirstName, the christian name of the user
# vcMiddleName, optional, middle name of the user
# vcSurName, the surname of the user
# vcEmail, the email associated with the user
# biDept, the department ID
# biRole, the role ID
# vcUsername, the login name of the user
# vcPassword, the password for the user
# vcIPorHost, the IP address or Host name of the client
# biUID, the user ID of the user performing this procedure
#--
DECLARE txtAuditEntry TEXT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1 #sqlstate = RETURNED_SQLSTATE,
#errno = MYSQL_ERRNO, #text = MESSAGE_TEXT;
CALL procLogError(CONCAT("procCreateUser: "
,#errno, " (", #sqlstate, "): ", #text));
END;
#Prepare the parameters
IF (vcFirstName IS NULL) OR (LENGTH(TRIM(vcFirstName)) = 0) THEN
CALL procLogError("vcFirstName must be valid");
LEAVE exitProc;
ELSEIF (vcSurName IS NULL) OR (LENGTH(TRIM(vcSurName)) = 0) THEN
CALL procLogError("vcSurName must be valid");
LEAVE exitProc;
ELSEIF (vcEmail IS NULL) OR (LENGTH(TRIM(vcEmail)) = 0) THEN
CALL procLogError("vcEmail must be valid");
LEAVE exitProc;
ELSEIF (biDept_id IS NULL) OR (biDept_id = 0) THEN
CALL procLogError("biDept_id must be valid");
LEAVE exitProc;
ELSEIF (biRole_id IS NULL) OR (biRole_id = 0) THEN
CALL procLogError("biRole_id must be valid");
LEAVE exitProc;
ELSEIF (vcUsername IS NULL) OR (LENGTH(TRIM(vcUsername)) = 0) THEN
CALL procLogError("vcUsername must be valid");
LEAVE exitProc;
END IF;
#Report parameters
CALL procAuditEntry(CONCAT("biPerson_id: ", biPerson_id), vcIPorHost, biCreator_id);
CALL procAuditEntry(CONCAT("vcFirstName: ", vcFirstName), vcIPorHost, biCreator_id);
CALL procAuditEntry(CONCAT("vcMiddleName: ", vcMiddleName), vcIPorHost, biCreator_id);
CALL procAuditEntry(CONCAT("vcSurName: ", vcSurName), vcIPorHost, biCreator_id);
CALL procAuditEntry(CONCAT("vcEmail: ", vcEmail), vcIPorHost, biCreator_id);
CALL procAuditEntry(CONCAT("biDept_id: ", biDept_id), vcIPorHost, biCreator_id);
CALL procAuditEntry(CONCAT("biRole_id: ", biRole_id), vcIPorHost, biCreator_id);
CALL procAuditEntry(CONCAT("vcUsername: ", vcUsername), vcIPorHost, biCreator_id);
IF (biPerson_id IS NULL) THEN
CALL procAuditEntry("INSERT", vcIPorHost, biCreator_id);
INSERT INTO `tbl_people` (
`vcFirstName`
,`vcMiddleName`
,`vcSurName`
,`vcEmail`
,`biDept_id`
,`biRole_id`
,`vcUserName`
,`vcPassWord`
) VALUES (
vcFirstName
,vcMiddleName
,vcSurName
,vcEmail
,biDept_id
,biRole_id
,vcUsername
,vcPassword
);
#Create audit log entry
SET txtAuditEntry = CONCAT('user \'', vcUsername, '\' created');
CALL procAuditEntry(txtAuditEntry, vcIPorHost, biCreator_id);
ELSE
CALL procAuditEntry("A.UPDATE", vcIPorHost, biCreator_id);
UPDATE `tbl_people` SET
`vcFirstName`=vcFirstName
,`vcMiddleName`=vcMiddleName
,`vcSurName`=vcSurName
,`vcEmail`=vcEmail
,`biDept_id`=biDept_id
,`biRole_id`=biRole_id
,`vcUserName`=vcUsername
WHERE
`biPerson_id`=biPerson_id;
CALL procAuditEntry("B.UPDATE", vcIPorHost, biCreator_id);
IF NOT vcPassWord IS NULL THEN
UPDATE `tbl_people` SET
`vcPassWord`=vcPassword
WHERE
`biPerson_id`=biPerson_id;
END IF;
#Create audit log entry
SET txtAuditEntry = CONCAT('user \'', vcUsername, '\' updated');
CALL procAuditEntry(txtAuditEntry, vcIPorHost, biCreator_id);
END IF;
END
All the calls to 'procAuditEntry' are really just for debugging, when I call this procedure to create a new record I pass the first parameter as null.
I can see from the audit table that it is going into the UPDATE section of the procedure. The issus is, I'm getting a duplicate key error raised by the procedure and I don't understand by because no new entry is being created, only an existing entry being modified. The table definition is as follows:
CREATE TABLE `tbl_people` (
`biPerson_id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Primary key',
`biCompany_id` BIGINT(20) UNSIGNED NULL DEFAULT NULL COMMENT 'Link to companies table',
`biDept_id` BIGINT(20) UNSIGNED NULL DEFAULT NULL COMMENT 'Link to department table',
`biRole_id` BIGINT(20) UNSIGNED NULL DEFAULT NULL COMMENT 'Link to Job title / description',
`tiActive` TINYINT(4) NOT NULL DEFAULT '1' COMMENT '1=active, 0=not',
`dtLastLogin` DATETIME NULL DEFAULT NULL COMMENT 'Date/Time of last login',
`vcFirstName` VARCHAR(48) NOT NULL COMMENT 'First name',
`vcMiddleName` VARCHAR(48) NULL DEFAULT NULL COMMENT 'Middle name',
`vcSurName` VARCHAR(48) NOT NULL COMMENT 'Surname',
`vcEmail` VARCHAR(256) NOT NULL COMMENT 'Email address',
`vcUserName` VARCHAR(48) NOT NULL COMMENT 'User name',
`vcPassWord` VARCHAR(32) NOT NULL COMMENT 'Password',
PRIMARY KEY (`biPerson_id`),
UNIQUE INDEX `Name` (`vcFirstName`, `vcSurName`),
UNIQUE INDEX `userName` (`vcUserName`),
INDEX `active` (`tiActive`),
INDEX `dept` (`biDept_id`),
INDEX `company` (`biCompany_id`),
INDEX `lastLogin` (`dtLastLogin`),
INDEX `jobrole` (`biRole_id`)
)
COMMENT='All timekeeper users'
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=4;
The error being logged is:
procCreateUser: 1062 (23000): Duplicate entry 'Simon-Platten' for key 'Name'
The really odd thing is if I call the UPDATE outside of the stored procedure it works.
Replacing the UPDATE with a REPLACE statement solves the issue, just not sure why the UPDATE fails.
While I am using a higher version of MariaDB (10.1.x), the problem must also be solved in version 10.0.x.
Try:
> SELECT VERSION();
+---------------------------+
| VERSION() |
+---------------------------+
| 10.1.9-MariaDB-1~wily-log |
+---------------------------+
1 row in set (0.00 sec)
> DROP TABLE IF EXISTS `tbl_people`;
Query OK, 0 rows affected (0.00 sec)
> CREATE TABLE `tbl_people` (
-> `biPerson_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
-> `vcFirstName` VARCHAR(48) NOT NULL,
-> `vcMiddleName` VARCHAR(48) NULL DEFAULT NULL,
-> `vcSurName` VARCHAR(48) NOT NULL,
-> UNIQUE INDEX `Name` (`vcFirstName`, `vcSurName`)
-> );
Query OK, 0 rows affected (0.00 sec)
> INSERT INTO `tbl_people`
-> (`vcFirstName`, `vcMiddleName`, `vcSurName`)
-> VALUES
-> ('Simon', 'R.', 'Platten'),
-> ('Peter', 'F.', 'Lucas');
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
> SELECT
-> `biPerson_id`,
-> `vcFirstName`,
-> `vcMiddleName`,
-> `vcSurName`
-> FROM
-> `tbl_people`;
+-------------+-------------+--------------+-----------+
| biPerson_id | vcFirstName | vcMiddleName | vcSurName |
+-------------+-------------+--------------+-----------+
| 1 | Simon | R. | Platten |
| 2 | Peter | F. | Lucas |
+-------------+-------------+--------------+-----------+
2 rows in set (0.00 sec)
> DELIMITER //
> DROP PROCEDURE IF EXISTS `sp_test`//
Query OK, 0 rows affected (0.00 sec)
> CREATE PROCEDURE `sp_test`(
-> biPerson_id BIGINT UNSIGNED,
-> vcFirstName VARCHAR(48),
-> vcMiddleName VARCHAR(48),
-> vcSurName VARCHAR(48)
-> )
-> BEGIN
-> UPDATE `tbl_people` SET
-> `vcFirstName` = vcFirstName,
-> `vcMiddleName` = vcMiddleName,
-> `vcSurName` = vcSurName
-> WHERE `biPerson_id` = biPerson_id;
-> END//
Query OK, 0 rows affected (0.00 sec)
> DELIMITER ;
> CALL `sp_test`(1, 'Simon', 'A.', 'Platten');
ERROR 1062 (23000): Duplicate entry 'Simon-Platten' for key 'Name'
> DELIMITER //
> DROP PROCEDURE IF EXISTS `sp_test`//
Query OK, 0 rows affected (0.00 sec)
> CREATE PROCEDURE `sp_test`(
-> `_biPerson_id` BIGINT UNSIGNED,
-> `_vcFirstName` VARCHAR(48),
-> `_vcMiddleName` VARCHAR(48),
-> `_vcSurName` VARCHAR(48)
-> )
-> BEGIN
-> UPDATE `tbl_people` SET
-> `vcFirstName` = `_vcFirstName`,
-> `vcMiddleName` = `_vcMiddleName`,
-> `vcSurName` = `_vcSurName`
-> WHERE `biPerson_id` = `_biPerson_id`;
-> END//
Query OK, 0 rows affected (0.00 sec)
> DELIMITER ;
> CALL `sp_test`(1, 'Simon', 'A.', 'Platten');
Query OK, 1 row affected (0.00 sec)
> SELECT
-> `biPerson_id`,
-> `vcFirstName`,
-> `vcMiddleName`,
-> `vcSurName`
-> FROM
-> `tbl_people`;
+-------------+-------------+--------------+-----------+
| biPerson_id | vcFirstName | vcMiddleName | vcSurName |
+-------------+-------------+--------------+-----------+
| 1 | Simon | A. | Platten |
| 2 | Peter | F. | Lucas |
+-------------+-------------+--------------+-----------+
2 rows in set (0.00 sec)
Related
I currently have 2 tables in KSQLDB:
CREATE STREAM "source-mysql-person" (
"_uid" STRING,
"_created" TIMESTAMP,
"_updated" TIMESTAMP,
"_disabled" TIMESTAMP,
"name" STRING,
"age" INT
) WITH (
KAFKA_TOPIC = 'source-mysql-person',
VALUE_FORMAT = 'AVRO'
);
/*
Field | Type
--------------------------------------------
_uid | VARCHAR(STRING) (primary key)
_created | TIMESTAMP
_updated | TIMESTAMP
_disabled | TIMESTAMP
name | VARCHAR(STRING)
age | INTEGER
--------------------------------------------
*/
CREATE TABLE "table-mysql-enriched-person_contact" WITH (
KAFKA_TOPIC = 'table-mysql-enriched-person_contact',
VALUE_FORMAT = 'AVRO'
) AS SELECT
"pc"."_uid" AS "_uid",
"pc"."_created" AS "_created",
"pc"."_updated" AS "_updated",
"pc"."_disabled" AS "_disabled",
"pc"."is_default" AS "is_default",
"pc"."value" AS "value",
"pc"."person_uid" AS "person_uid",
AS_MAP(
ARRAY['_uid', 'value'],
ARRAY["ct"."_uid", "ct"."value"]
) AS "contact_type"
FROM "table-mysql-person_contact" "pc"
INNER JOIN "table-mysql-contact_type" "ct" ON
"ct"."_uid" = "pc"."contact_type_uid"
EMIT CHANGES;
/*
Field | Type
-----------------------------------------------
_uid | VARCHAR(STRING) (primary key)
_created | TIMESTAMP
_updated | TIMESTAMP
_disabled | TIMESTAMP
is_default | INTEGER
value | VARCHAR(STRING)
person_uid | VARCHAR(STRING)
contact_type | MAP<STRING, VARCHAR(STRING)>
-----------------------------------------------
*/
I want to create a table table-mysql-enriched-person that has the data of table-mysql-person and for each "person", a list of "person_contact" related to that "person". For this I am trying to use the following querie:
CREATE TABLE "table-mysql-enriched-person" WITH (
KAFKA_TOPIC = 'table-mysql-enriched-person',
VALUE_FORMAT = 'AVRO'
) AS SELECT
"p"."_uid" AS "_uid",
"p"."_created" AS "_created",
"p"."_updated" AS "_updated",
"p"."_disabled" AS "_disabled",
"p"."name" AS "name",
"p"."age" AS "age",
AS_MAP(
ARRAY[
'_uid',
'_created',
'_updated',
'_disabled',
'is_default',
'value',
'contact_type'
],
ARRAY[
"e"."_uid",
"e"."_created",
"e"."_updated",
"e"."_disabled",
"e"."is_default",
"e"."value",
"e"."contact_type"
]
) AS "list_person_contact"
FROM "table-mysql-enriched-person_contact" "e"
INNER JOIN "table-mysql-person" "p" ON
"p"."_uid" = "e"."person_uid"
GROUP BY
"p"."_uid",
"p"."_created",
"p"."_updated",
"p"."_disabled",
"p"."name",
"p"."age"
EMIT CHANGES;
Theoretically the query is correct because I have primary keys in the 2 queries and, thinking that the table "person_contact" is a child table of "person" and that the field person._uid is represented as person_contact.person_uid, I should manage to create the table but ksqldb is returning me the following message:
Could not determine output schema for query due to error: GROUP BY requires aggregate functions
in either the SELECT or HAVING clause.
I have 2 tables:
tbl1(idM int identity(1,1), Name nvarchar(50));
tbl2(idRow int identity(1,1), idM int, Data nvarchar(50));
They are queried via fdQuery1 and fdQuery2 (master:fdQuery1, masterfield:idM).
CachedUpdates = True on both fdQuery.
FDSchemaAdapter is connected to both also.
Also FDUpdateSQL1 and FDUpdateSQL2 connected to fdQuery1 and fdQuery2.
On inserting (fdQuery1.Insert) new row in fdQuery1 it's idM is shown as -2 by default, f.e.
FDUpdateSQL1 insert text:
INSERT INTO tbl1 (Name)
VALUES (:NEW_Name);
SELECT SCOPE_IDENTITY() AS idM
FDUpdateSQL2 insert text:
INSERT INTO tbl2 (idM, Data)
VALUES (:NEW_idM, :NEW_Data);
SELECT SCOPE_IDENTITY() AS idRow
On saving I execute this code:
FDSchemaAdapter.ApplyUpdates;
fdQuery1.CommitUpdates;
fdQuery2.CommitUpdates;
Target: fill form with DB-aware components connected to tbl1 and tbl2 and set tbl2.idM automatically.
How can I do this?
I tried OnUpdateRecord method but it still doesn't return idM from FDUpdateSQL1 insert.
fdQuery1.OnAfterPost field fdQuery1idM.asInteger also returns -2 value.
Current example result in tables:
tbl1
|idM|Name|
|--------|
|5 |Test|
tbl2
|idRow|idM|Data |
|------------------|
|10 |-2 |DataText|
Target tbl2
|idRow|idM|Data |
|------------------|
|10 |5 |DataText|
Thank you!
TableA
| where GuidId == "123"
| where Desc has_any ("processor")
| join kind=leftouter TableB on
$left.SubId == $right.SubId,
$left.ProductName == $right.Name,
$left.GuidId == $right.GuidId
| distinct SubId, PriceTags, ResourceType, ProductName, Name
ProductName is in lower case and Name is in camel case. How to bring ProductName and Name to same case in Join condition.
Thanks
something like:
| extend Name=tolower(Name)
TableA
| where GuidId == "123"
| where Desc has_any ("processor")
| join kind=leftouter (TableB | extend Name=tolower(Name)) on $left.SubId == $right.SubId, $left.ProductName==$right.Name, $left.GuidId==$right.GuidId
|distinct SubId, PriceTags, ResourceType, ProductName, Name
extend Name=tolower(Name)
You'll need to 'normalize' the values before the join.
Ideally you'll do this before ingestion, or at ingestion time (using an update policy).
Given the current non-normalized values, you can do it at query time (performance would be sub-optimal):
TableA
| where GuidId == "123"
| where Desc has "processor"
| join kind=leftouter (
TableB
| extend Name = tolower(Name)
) on
$left.SubId == $right.SubId,
$left.ProductName == $right.Name,
$left.GuidId == $right.GuidId
| distinct SubId, PriceTags, ResourceType, ProductName, Name
I have created one macro in Teradata, now wish to call that macro through Stored Procedure (in Teradata only). The SQL part belongs to macro.
I wrote this procedure in case if execution of macro is not possible through procedure.
Kindly suggest both the option.
CREATE PROCEDURE MDM_STAGE.match_sqls_proc
(
in fname VARCHAR(30),
in match_frst_name VARCHAR (100),
in lname VARCHAR(30),
in match_last_name VARCHAR (100),
in addr1 VARCHAR(1000),
in zip_cd_base varchar(10),
in email VARCHAR(30),
in phone VARCHAR(30),
out msgs VARCHAR(10)
-- INOUT errstr VARCHAR(30)
)
begin
DECLARE SQLTEXT2 VARCHAR (10) ;
DECLARE TBL_COUNT INT ;
select count (*) into :TBL_COUNT from
(
SELECT
CUST.CUST_ID,
CUST.FRST_NAME,
CUST.MATCH_FRST_NAME,
CUST.LAST_NAME,
CUST.MATCH_LAST_NAME,
CUST.GNDR_TYPE_CD,
STREET_ADDR.ADDR_LN_1_TXT,
STREET_ADDR.ADDR_LN_2_TXT,
STREET_ADDR.ADDR_LN_3_TXT,
cast (coalesce (STREET_ADDR.ADDR_LN_1_TXT,'') || ' ' || coalesce
(STREET_ADDR.ADDR_LN_2_TXT,'' ) as varchar (1000)) as addr,
STREET_ADDR.CITY_NAME,
STREET_ADDR.POSTL_CD,
STREET_ADDR.STREET_ADDR_ID,
STREET_ADDR.ADDR_SBTYPE_CD,
ELCTRNC_ADDR.ELCTRNC_ADDR_ID,
ELCTRNC_ADDR.ELCTRNC_ADDR_SBTYPE_CD,
ELCTRNC_ADDR.ELCTRNC_ADDR_TXT,
TLPHN_NUM.TLPHN_LN_NUM,
TLPHN_NUM.TLPHN_NUM_ID
FROM
MDM_STAGE.REF_CUST_V CUST
LEFT OUTER JOIN
MDM_STAGE.REF_STREET_ADDR_V STREET_ADDR
ON
CUST.CUST_ID = STREET_ADDR.CUST_ID
AND
--RDM_ADDRSIM (STREET_ADDR.ADDR_LN_1_TXT ,'2285Main Street' ) =1
RDM_ADDRSIM ( cast (coalesce (STREET_ADDR.ADDR_LN_1_TXT,'') || ' ' ||
coalesce (STREET_ADDR.ADDR_LN_2_TXT,'' ) as varchar (1000)) ,:addr1) =1
AND
SUBSTR(STREET_ADDR.POSTL_CD,0,6) = (:zip_cd_base)
LEFT OUTER JOIN
MDM_STAGE.REF_ELCTRNC_ADDR_V ELCTRNC_ADDR
ON
CUST.CUST_ID = ELCTRNC_ADDR.CUST_ID
/*AND
STREET_ADDR.ADDR_SBTYPE_CD = ELCTRNC_ADDR.ELCTRNC_ADDR_SBTYPE_CD*/
AND
ELCTRNC_ADDR.ELCTRNC_ADDR_TXT= (:email)
LEFT OUTER JOIN
MDM_STAGE.REF_TLPHN_NUM_V TLPHN_NUM
ON
CUST.CUST_ID = TLPHN_NUM.CUST_ID
/*AND
STREET_ADDR.ADDR_SBTYPE_CD = TLPHN_NUM.ADDR_SBTYPE_CD*/
AND
TLPHN_NUM.TLPHN_LN_NUM = (:phone)
WHERE
(RDM_sndx(COALESCE(CUST.Match_FRST_NAME,CUST.CUST_ID))=RDM_sndx(:match_frst_name)
AND
RDM_sndx(COALESCE(STRTOK(CUST.Match_LAST_NAME,' ',1),CUST.CUST_ID))=RDM_SNDX(:match_last_name)
)
AND
(
TLPHN_NUM.CUST_ID IS NOT NULL
OR
ELCTRNC_ADDR.CUST_ID IS NOT NULL
OR
STREET_ADDR.CUST_ID IS NOT NULL
) A
;
IF ( TBL_COUNT > 0 ) THEN SET SQLTEXT2 = 'Match' ;
ELSE
SET Msgs = 'Non-Match' ;
END IF;
end;
Error message -
SPL1027:E(L88), Missing/Invalid SQL statement'E(3707):Syntax error, expected something like an 'EXCEPT' keyword or an 'UNION' keyword or a 'MINUS' keyword between ')' and the word 'A'.'.
No idea, what to add between the word 'A' and ')'. Tried all the possibility but not successful. Not sure how to pass the value of SQL into the 'count' as later call procedure condition is based on that count only.
I have a table Products and around 58000 records in it. I run two queries are as follows.
Product.where(description: 'swiss').count
It returns 0 products out of 58000 products. But when I run query below.
Product.where.not(description: 'swiss').count
it returns 2932 products out of 58000 products. I think it should return all 58000 products, because it is the reverse of first query.
I did not understand why it returns only 2932 products.
If you have NULL values in your columns, this could happen, because NULL always compares as NULL, even to itself, but WHERE expression must be true to include a result.
'a' = 'a'; True
'a' = 'b'; False
'a' = NULL; Results in NULL (not false!)
NULL = NULL; Results in NULL (not true!)
'a' != 'a'; False
'a' != 'b'; True
'a' != NULL; NULL
e.g. consider the table null_test containing
id | str
----+-----
1 | <NULL>
2 | a
3 | b
When looking for a column equal to some value, the NULL is never equal, so this will just return row 2.
SELECT id FROM null_test WHERE str = 'a';
But the same applies looking for a column not equal to some value, the NULL is never not equal (its NULL), so this will just return row 3.
SELECT id FROM null_test WHERE str != 'a';
Thus the total of your = and != is not all the rows, because you never included the NULL rows. This is where IS NULL and IS NOT NULL come in (they work like you might expect = NULL and != NULL to work).
SELECT id FROM null_test WHERE str != 'a' OR str IS NULL;
Now you get rows 1 and 3, making this the opposite of str = 'a'.
For ActiveRecord, it treats the Ruby nil value like the SQL NULL and creates the IS NULL checks in certain situations.
NullTest.where(str: 'a')
SELECT * FROM "null_test" WHERE "str" = 'a'
NullTest.where.not(str: 'a')
SELECT * FROM "null_test" WHERE "str" != 'a'
NullTest.where(str: nil)
SELECT * FROM "null_test" WHERE "str" IS NULL
NullTest.where.not(str: nil)
SELECT * FROM "null_test" WHERE "str" IS NOT NULL
NullTest.where(str: nil).or(NullTest.where.not(str: 'a'))
SELECT * FROM "null_test" WHERE "str" IS NULL OR "str" != 'a'
You have likely many records where description is nil and those are not included in the not.
A way to include the 'nil' records as well would be...
Product.where('description <> ? OR description IS NULL', 'swiss')
Or alternatively
Product.where.not(description: 'swiss').or(Product.where(description: nil))