SQL Merge Statement Check Constraint Error - json

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).

Related

How to use SQL alias within query

I have a sql query (below) to insert records into a database. The goal is to insert only new / unique entries in the database. So it will insert the row if the row doesn't already exist in the entire database. I would like to have it evaluate that row against ONLY the rows that have the symbol in the instrumentSymbol, rather than evaluating against every row in the entire database.
I am running into this syntax error which I have pinpointed to be due to the use of an alias in line SELECT 1 FROM instrumentsHistory WHERE instrumentSymbol = 'ZYME' AS f
This query works fine if removing the WHERE instrumentSymbol = {SYMBOL} conditional, but I need to this to refine the set of records the query compares itself to (thus reducing time to complete task.
I have looked through the documentation which leads me to believe there is nothing wrong with this query. Can someone pls point me in the right direction?
The Error:
(sqlite3.OperationalError) near "AS": syntax error
[SQL: INSERT INTO instrumentsHistory (datetime, instrumentSymbol, observation, observationColName)
SELECT t.datetime, t.instrumentSymbol, t.observation, t.observationColName
FROM tempTable t
WHERE NOT EXISTS
(SELECT 1 FROM instrumentsHistory WHERE instrumentSymbol = 'ZYME' AS f
WHERE t.datetime = f.datetime
AND t.instrumentSymbol = f.instrumentSymbol
AND t.observation = f.observation
AND t.observationColName = f.observationColName)]
EDIT 1:
Adding complete query...
sql = f"""INSERT INTO instrumentsHistory (datetime, instrumentSymbol, observation, observationColName)
SELECT t.datetime, t.instrumentSymbol, t.observation, t.observationColName
FROM tempTable t
WHERE NOT EXISTS
(SELECT 1 FROM instrumentsHistory WHERE instrumentSymbol = '{symbol}' AS f
WHERE t.datetime = f.datetime
AND t.instrumentSymbol = f.instrumentSymbol
AND t.observation = f.observation
AND t.observationColName = f.observationColName)"""
This code:
WHERE NOT EXISTS (SELECT 1 FROM instrumentsHistory WHERE instrumentSymbol = 'ZYME' AS f
WHERE t.datetime = f.datetime
has multiple errors. There are two WHERE clauses in a row. And as is being used in a WHERE clause. I am guessing this is a copy-and-past error, but it is unclear what you intend.

MySQL Error Code: 1060

so for this, the goal is to add a column to a table called ENROLLMENT called FullFeePaid and to populate the column (assuming its null) but the only two possible answers can be Yes or No comparing data from another table called Course.
So I type the following command using alter however I keep getting a message where there's a duplicate, even i've never made a column called FullFeePaid.
But before that I kept getting an error saying there's a syntax error where it says
"set e.FullPaid = if(c.fee - e.amount <= 0 'yes', 'no')".
SET SQL_SAFE_UPDATES = 0;
ALTER TABLE enrollment
add fullfeepaid varchar(45) NULL;
UPDATE ENROLLMENT as e
JOIN COURSE as c on e.CourseNumber = c.CourseNumber
set e.FullFeePaid = if(c.fee - e.amountpaid <= 0 'yes', 'no')
where e.CourseNumber = c.CourseNumber;
select *
from enrollment;
You're missing a comma between the condition and the result your want to return if it evaluates as true:
UPDATE ENROLLMENT as e
JOIN COURSE as c on e.CourseNumber = c.CourseNumber
SET e.FullFeePaid = if(c.fee - e.amountpaid <= 0, 'yes', 'no')
-- Missing comma in the OP ---------------------^
WHERE e.CourseNumber = c.CourseNumber;

UPDATE multiple rows with different values in one query in MySQL

I am trying to understand how to UPDATE multiple rows with different values and I just don't get it. The solution is everywhere but to me it looks difficult to understand.
For instance, three updates into 1 query:
UPDATE table_users
SET cod_user = '622057'
, date = '12082014'
WHERE user_rol = 'student'
AND cod_office = '17389551';
UPDATE table_users
SET cod_user = '2913659'
, date = '12082014'
WHERE user_rol = 'assistant'
AND cod_office = '17389551';
UPDATE table_users
SET cod_user = '6160230'
, date = '12082014'
WHERE user_rol = 'admin'
AND cod_office = '17389551';
I read an example, but I really don't understand how to make the query. i.e:
UPDATE table_to_update
SET cod_user= IF(cod_office = '17389551','622057','2913659','6160230')
,date = IF(cod_office = '17389551','12082014')
WHERE ?? IN (??) ;
I'm not entirely clear how to do the query if there are multiple condition in the WHERE and in the IF condition..any ideas?
You can do it this way:
UPDATE table_users
SET cod_user = (case when user_role = 'student' then '622057'
when user_role = 'assistant' then '2913659'
when user_role = 'admin' then '6160230'
end),
date = '12082014'
WHERE user_role in ('student', 'assistant', 'admin') AND
cod_office = '17389551';
I don't understand your date format. Dates should be stored in the database using native date and time types.
MySQL allows a more readable way to combine multiple updates into a single query. This seems to better fit the scenario you describe, is much easier to read, and avoids those difficult-to-untangle multiple conditions.
INSERT INTO table_users (cod_user, date, user_rol, cod_office)
VALUES
('622057', '12082014', 'student', '17389551'),
('2913659', '12082014', 'assistant','17389551'),
('6160230', '12082014', 'admin', '17389551')
ON DUPLICATE KEY UPDATE
cod_user=VALUES(cod_user), date=VALUES(date)
This assumes that the user_rol, cod_office combination is a primary key. If only one of these is the primary key, then add the other field to the UPDATE list.
If neither of them is a primary key (that seems unlikely) then this approach will always create new records - probably not what is wanted.
However, this approach makes prepared statements easier to build and more concise.
UPDATE table_name
SET cod_user =
CASE
WHEN user_rol = 'student' THEN '622057'
WHEN user_rol = 'assistant' THEN '2913659'
WHEN user_rol = 'admin' THEN '6160230'
END, date = '12082014'
WHERE user_rol IN ('student','assistant','admin')
AND cod_office = '17389551';
You can use a CASE statement to handle multiple if/then scenarios:
UPDATE table_to_update
SET cod_user= CASE WHEN user_rol = 'student' THEN '622057'
WHEN user_rol = 'assistant' THEN '2913659'
WHEN user_rol = 'admin' THEN '6160230'
END
,date = '12082014'
WHERE user_rol IN ('student','assistant','admin')
AND cod_office = '17389551';
To Extend on #Trevedhek answer,
In case the update has to be done with non-unique keys, 4 queries will be need
NOTE: This is not transaction-safe
This can be done using a temp table.
Step 1: Create a temp table keys and the columns you want to update
CREATE TEMPORARY TABLE temp_table_users
(
cod_user varchar(50)
, date varchar(50)
, user_rol varchar(50)
, cod_office varchar(50)
) ENGINE=MEMORY
Step 2: Insert the values into the temp table
Step 3: Update the original table
UPDATE table_users t1
JOIN temp_table_users tt1 using(user_rol,cod_office)
SET
t1.cod_office = tt1.cod_office
t1.date = tt1.date
Step 4: Drop the temp table
In php, you use multi_query method of mysqli instance.
$sql = "SELECT COUNT(*) AS _num FROM test;
INSERT INTO test(id) VALUES (1);
SELECT COUNT(*) AS _num FROM test; ";
$mysqli->multi_query($sql);
comparing result to transaction, insert, case methods in update 30,000 raw.
Transaction: 5.5194580554962
Insert: 0.20669293403625
Case: 16.474853992462
Multi: 0.0412278175354
As you can see, multiple statements query is more efficient than the highest answer.
Just in case if you get error message like this:
PHP Warning: Error while sending SET_OPTION packet
You may need to increase the max_allowed_packet in mysql config file.
UPDATE Table1 SET col1= col2 FROM (SELECT col2, col3 FROM Table2) as newTbl WHERE col4= col3
Here col4 & col1 are in Table1. col2 & col3 are in Table2 I Am trying to update each col1 where col4 = col3 different value for each row
I did it this way:
<update id="updateSettings" parameterType="PushSettings">
<foreach collection="settings" item="setting">
UPDATE push_setting SET status = #{setting.status}
WHERE type = #{setting.type} AND user_id = #{userId};
</foreach>
</update>
where PushSettings is
public class PushSettings {
private List<PushSetting> settings;
private String userId;
}
it works fine

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 ;

Merge not inserting. No error

Can someone tell me why this insert is failing but not giving me an error either? How do I fix this?
merge table1 as T1
using(select p.1,p.2,p.3,p.4,p.5 from #parameters p
inner join table1 t2
on p.1 = t2.1
and p.2 = t2.2
and p.3 = t2.3
and p.4 = t2.4) as SRC on SRC.2 = T1.2
when not matched then insert (p.1,p.2,p.3,p.4,p.5)
values (SRC.1,SRC.2,SRC.3,SRC.4,SRC.5)
when matched then update set t1.5 = SRC.5;
The T1 table is currently empty so nothing can match. The parameters table does have data in it. I simply need to modify this merge so that it checks all 4 fields before deciding what to do.
You can't select from a variable: from #parameters
See the following post: Using a variable for table name in 'From' clause in SQL Server 2008
Actually, you can use a variable table. Check it out:
MERGE Target_table AS [Target]
USING #parameters AS [Source]
ON (
[Target].col1 = [Source].col1
AND [Target].col2 = [Source].col2
AND [Target].col3 = [Source].col3
AND [Target].col4 = [Source].col4
)
WHEN NOT MATCHED BY TARGET
THEN INSERT (col1,col2,col3,col4,col5)
VALUES (
[Source].col1
,[Source].col2
,[Source].col3
,[Source].col4
,[Source].col5
)
WHEN MATCHED
THEN UPDATE SET [Target].col5 = [Source].col5;