Resue from Mysql unique index duplicate entry - mysql

I am trying to fix a double request problem: when browser spawn two or more identical requests to server and they got processed on different app servers.
In this case one of two requests hits:
Mysql::Error: Duplicate entry '...'
for key 'index_purchases_on_site_id_and_order_number_and_email
There is rescue code afterwards that selects existing record instead that uses the same parameters as insert request:
select * from purchases where site_id = ? and order_number = ? and email = ?
But it doesn't find anything in database.
A fragment from DB query log:
SQL (1.3ms) BEGIN
......
Purchase Create (0.0ms) Mysql::Error: Duplicate entry '1887-100264587-9z1CIIDsH2a21+AEEH2OR9LsndO3oIS4D4Am1U5XJ04=
' for key 'index_purchases_on_site_id_and_order_number_and_email': INSERT INTO `purchases` (`order_date`, `referrer`, `created_at`, `updated_at`, `encrypted_email`, `visitor_id`, `order_number`, `coupon_code`, `subtotal`, `customer_id`, `site_id`, `ip_address`) VALUES('2013-01-14 20:57:47', 'https://www.bonobos.com/b/checkout', '2013-01-14 20:57:47', '2013-01-14 20:57:47', '9z1CIIDsH2a21+AEEH2OR9LsndO3oIS4D4Am1U5XJ04=\n', 15813843, '100264587', '', 218.0, NULL, 1887, '12.106.186.6')
Purchase Load (0.5ms) SELECT * FROM `purchases` WHERE (order_number = '100264587' AND site_id = 1887 AND encrypted_email = '9z1CIIDsH2a21+AEEH2OR9LsndO3oIS4D4Am1U5XJ04=\n') LIMIT 1
SQL (18.0ms) ROLLBACK
How is this possible?

Related

SQL Merge Statement Check Constraint Error

I have the following code table A has a check constraint on column Denial.
CREATE TABLE Table a
(
[ID] int IDENTITY(1,1) NOT NULL ,
[EntityID] int ,
Denial nVarchar(20)
CONSTRAINT Chk_Denial CHECK (Denial IN ('Y', 'N')),
)
Merge statement
MERGE INTO Table a WITH (HOLDLOCK) AS tgt
USING (SELECT DISTINCT
JSON_VALUE(DocumentJSON, '$.EntityID') AS EntityID,
JSON_VALUE(DocumentJSON, '$.Denial') AS Denial
FROM Table1 bd
INNER JOIN table2 bf ON bf.FileUID = bd.FileUID
WHERE bf.Type = 'Payment') AS src ON tgt.[ID] = src.[ID]
WHEN MATCHED
)) THEN
UPDATE SET tgt.ID = src.ID,
tgt.EntityID = src.EntityID,
tgt.Denial = src.Denial,
WHEN NOT MATCHED BY TARGET
THEN INSERT (ID, EntityID, Denial)
VALUES (src.ID, src.EntityID, src.Denial)
THEN DELETE
I get this error when running my MERGE statement:
Error Message Msg 547, Level 16, State 0, Procedure storproctest1, Line 40 [Batch Start Line 0]
The MERGE statement conflicted with the CHECK constraint "Chk_Column". The conflict occurred in the database "Test", table "Table1", and column 'Denial'. The statement has been terminated.
This is due to the source files having "Yes" and "No" instead of 'Y' and 'N'. Hence, I'm getting the above error.
How can I use a Case statement in merge statement to handle the above Check constraints error? or Any alternative solutions.
You can turn Yes to Y and No to N before merging your data. That would belong to the using clause of the merge query:
USING (
SELECT Distinct
JSON_VALUE(DocumentJSON, '$.EntityID') AS EntityID,
CASE JSON_VALUE(DocumentJSON, '$.Denial')
WHEN 'Yes' THEN 'Y'
WHEN 'No' THEN 'N'
ELSE JSON_VALUE(DocumentJSON, '$.Denial')
END AS Denial
FROM Table1 bd
INNER JOIN table2 bf ON bf.FileUID = bd.FileUID
WHERE bf.Type = 'Payment'
) AS src
The case expression translates Y and N values, and leaves other values untouched. Since this applies to the source dataset, the whole rest of the query benefits (ie both the update and insert branches).

Order of INSERT or UPDATE in a transaction in binlog

I'm using debezium connector to stream my Mysql binlog change records to Kafka Topic. My transaction is like so:
Tx begin
Insert INTO Project(Name, InProgress) VALUES ('New Project', 0);
-- We get the created id (say PID)
Insert INTO Tasks(TaskName, ProjectID) VALUES ('Task A', PID);
-- We get the taskID (say TID1)
Insert INTO Tasks(TaskName, ProjectID) VALUES ('Task B', PID);
-- We get the taskID (say TID2)
UPDATE Tasks SET TaskName = 'Task C' where ID = TID2;
Update Project SET InProgress = 1 where ID = PID;
Tx end
My question is in what order will I get the bin log records? Will I get the records in the order in which the records are inserted? So like this?
NEW Project with ID = PID
NEW Task with ID = TID1
NEW Task with ID = TID2
Is this documented anyplace?

ActiveRecord::Rollback doesn't seems to do a transaction rollback

One day I noticed my transactions dont accept a ActiveRecord::Rollback. I have such an example:
example
ActiveRecord::Base.transaction do
puts #shipment_list.status
#shipment_list.update(shipment_list_params)
raise ActiveRecord::Rollback
end
puts #shipment_list.status
result
CACHE (0.0ms) SELECT `shipment_lists`.* FROM `shipment_lists` WHERE `shipment_lists`.`id` = 24121 ORDER BY created_at DESC LIMIT 1 [["id", "24121"]]
(0.2ms) BEGIN
reserve
(1.3ms) SELECT MAX(`audits`.`version`) AS max_id FROM `audits` WHERE `audits`.`auditable_id` = 24121 AND `audits`.`auditable_type` = 'ShipmentList'
SQL (160.5ms) INSERT INTO `audits` (`action`, `auditable_id`, `auditable_type`, `audited_changes`, `created_at`, `remote_address`, `request_uuid`, `user_id`, `user_type`, `version`) VALUES ('update', 24121, 'ShipmentList', '---\nstatus:\n- reserve\n- 2\n', '2016-07-10 12:01:55', '127.0.0.1', 'efc5b6e7-c3f9-4b4a-a0fd-67651b2eeb20', 18, 'User', 19)
SQL (0.3ms) UPDATE `shipment_lists` SET `status` = 2, `updated_at` = '2016-07-10 12:01:55' WHERE `shipment_lists`.`id` = 24121
(0.2ms) ROLLBACK
bill
Where is the mistake? I really in a trouble.
Actually the problem was caused by myISAM mysql schema. Transactions rollback is not allowed.

Mysql - How can I select rows based on two criterias

I'm trying to run this query, to select all the rows that have status = 1:
SELECT
acc.id,
acc.user_id,
acc.type,
acc.account,
acc.`status`,
acc.paid,
acc.`password`, CAST(AES_DECRYPT( BASE64_DECODE( `password` ), 'encryption-key') AS CHAR)
FROM acc
WHERE status = status = '1'
However, it returns all the tables, it does't select only the rows that have status = 1
It's probably a syntax error. I do need this
`acc.`password`, CAST(AES_DECRYPT( BASE64_DECODE( `password` ), 'encryption-key') AS CHAR)`
part so I can decrypt the passwords.
What did I do wrong?
You don't need to append acc. to all the fields given you're only retrieving data from one table.
You had and extra status attached to your condition
Should be:
SELECT `id`,
`user_id`,
`type`,
`account`,
`status`,
`paid`,
`password`,
CAST(AES_DECRYPT(BASE64_DECODE(`password`),'encryption-key') AS CHAR)
FROM acc
WHERE status = '1'

Cancel Insert if inner query find nothing

I got the following query :
INSERT INTO contracts_settings (contract_id, setting_id, setting_value)
VALUES (:contract_id, (
SELECT setting_id
FROM settings
WHERE setting_type = :setting_type
AND setting_name = :setting_name
LIMIT 1
), :setting_value)
ON DUPLICATE KEY UPDATE setting_value = :setting_value
The value with the prefix : is replaced with data using PHP PDO::bindBalue.
If the inner query find nothing (it return NULL) but also INSERT a NULL statement. How to avoid that ?
Thanks.
Convert the INSERT ... VALUES syntax to INSERT ... SELECT:
INSERT INTO contracts_settings
(contract_id, setting_id, setting_value)
SELECT
:contract_id,
setting_id,
:setting_value
FROM settings
WHERE setting_type = :setting_type
AND setting_name = :setting_name
LIMIT 1
ON DUPLICATE KEY UPDATE
setting_value = :setting_value ;