What is the correct syntax to write "merge statement" in PostgreSQL 9.6.2 - postgresql

code :It is merge query which is running on Postgres 9.6.2 and giving syntax error.
<<!--It is giving syntax error--->
MERGE INTO timesheets.timesheet_report AS tgt USING timesheets.tmp_timesheet_report AS src ON src.FMNo = tgt.FMNo
AND src.ts_start_dt = tgt.ts_start_dt
AND src.charge_code = tgt.charge_code WHEN NOT MATCHED
INSERT (tgt.FIRST_NAME,
tgt.LAST_NAME)
VALUES(src.FIRST_NAME,
src.LAST_NAME) WHEN MATCHED
UPDATE
SET tgt.FIRST_NAME = src.FIRST_NAME,
tgt.LAST_NAME = src.LAST_NAME;

It is ON CONFLICT
INSERT INTO table_name [your usual insert syntax here]
ON CONFLICT [some conflict definition]
DO UPDATE SET column1 = EXCLUDED.value1
So I guess your query would look like this:
INSERT INTO timesheets.timesheet_report (FMNo, ts_start_dt, charge_code, FIRST_NAME, LAST_NAME)
SELECT src.FMNo, src.ts_start_dt, src.charge_code, src.FIRST_NAME, src.LAST_NAME FROM timesheets.tmp_timesheet_report AS src
ON CONFLICT (FMNo, ts_start_dt, charge_code)
DO UPDATE
SET FIRST_NAME = EXCLUDED.FIRST_NAME,
LAST_NAME = EXCLUDED.LAST_NAME;
If you don't have primary key or unique index, then you need to create unique index on timesheets.timesheet_report using btree (FMNo, ts_start_dt, charge_code);

Related

Merge join not able to join properly on varchar column

I've created below code to implement SCD type 2 using merge, when i run the code i'm getting primary key violations on csname field. I have the below values as part of primary key, not sure whether merge SQL does support for varchar or not.
if I run the normal inner join SQL on the same key then i'm getting the matching records as well.
Any help much appreciated
csname
ER - Building Complaints
TR - Building Applications
CREATE PROCEDURE dbo.load_target
AS
BEGIN
INSERT INTO [TR_DW].[enum].[Rt]([csname],[enddatetime],[EffectiveToDate],[EffectiveFromDate],[CurrentRecord])
SELECT[csname],[enddatetime],[EffectiveToDate],[EffectiveFromDate],[CurrentRecord]
FROM
(
MERGE [TR_DW].[enum].[Rt] RtCSQSuTT
USING [TR].[enum].[Rt] RtCSQSuST
ON (RtCSQSuTT.csname = RtCSQSuST.csname)
WHEN NOT MATCHED THEN
INSERT ([csname],[enddatetime],[EffectiveToDate],[EffectiveFromDate],[CurrentRecord])
VALUES ([csname],[enddatetime],'12/31/9999', getdate(), 'Y')
WHEN MATCHED AND RtCSQSuTT.[CurrentRecord] = 'Y' AND
(ISNULL(RtCSQSuTT.[enddatetime], '') != ISNULL(RtCSQSuST.[enddatetime], ''))THEN
UPDATE SET
RtCSQSuTT.[CurrentRecord] = 'N',
RtCSQSuTT.[EffectiveFromDate] = GETDATE() - 1,
RtCSQSuTT.[EffectiveToDate] = GETDATE()
OUTPUT $Action Action_Taken,RtCSQSuST.[csqname],RtCSQSuST.[enddatetime],'12/31/9999' AS[EffectiveToDate],GETDATE() AS[EffectiveFromDate],'Y' AS[CurrentRecord]
)AS MERGE_OUT21
WHERE MERGE_OUT21.Action_Taken = 'UPDATE';
END
GO

sqlalchemy to create temporary table

I created a temporary table with sqlalchemy (with an underlying postgres database) that is going to be joined with a database table. However, in some cases when a value is empty '' then postgres throws the error:
failed to find conversion function from unknown to text
SqlAlchemy assembles everything to the following context
[SQL: 'WITH temp_table AS \n(SELECT %(param_1)s AS id, %(param_2)s AS email, %(param_3)s AS phone)\n SELECT campaigns_contact.id, campaigns_contact.email, campaigns_contact.phone \nFROM campaigns_contact JOIN temp_table ON temp_table.id = campaigns_contact.id AND temp_table.email = campaigns_contact.email AND temp_table.phone = campaigns_contact.phone'] [parameters: {'param_1': 83, 'param_2': '', 'param_3': '+1234567890'}]
I assemble the temporary table as follows
stmts = []
for row in import_data:
row_values = [literal(row[value]).label(value) for value in values]
stmts.append(select(row_values))
subquery = union_all(*stmts)
subquery = subquery.cte(name="temp_table")
The problem seems to be the part here
...%(param_2)s AS email...
which after replacing the param_2 results in
...'' AS email...
which will cause the error mentioned above.
One way to solve the issue is to perform a cast
...''::text AS email...
However, I don't know how to perform ::text cast with sqlalchemy!?

How to refer OLD.X at ON CONFLICT DO UPDATE SET X = OLD.X + EXCLUDED.X

There are an alias for "old value" in the ON CONFLICT DO UPDATE?
My real life problem is
INSERT INTO art.validterm (namespace,term,X,info)
SELECT namespace,term,array_agg(Xi), 'etc'
FROM term_raw_Xs
GROUP BY namespace,term
ON CONFLICT (term) DO
UPDATE SET aliases=OLD.X||EXCLUDED.X
WHERE term=EXCLUDED.term
PS: no "OLD" exists, is the question. The parser say that only X is ambigous.
Simply replacing OLD with the name of the table, in your case: validterm, worked for me.
My test:
DROP TABLE IF EXISTS work.term_raw;
CREATE TABLE work.term_raw
(
unique_field INT UNIQUE,
x_field TEXT
);
INSERT INTO work.term_raw VALUES (1, 'A');
INSERT INTO work.term_raw VALUES (1, 'B')
ON CONFLICT (unique_field) DO UPDATE SET x_field = term_raw.x_field || EXCLUDED.x_field;
SELECT * FROM work.term_raw;
My result:

Update Rule on View - PostgreSQL

My rule to update a view "fva_gpi_sbcpcba_voapcba" isn't properly updating the "product_serial_number" column in both "general_product_info" and "fva_3800" tables.
It only updates the "product_serial_number" in the first table written in the update rule and not both. That is, in this case it will update the fva_3800 table's product_serial_number, but not the general_product_info table's. If I put the UPDATE on general_product_info table first, vice versa.
Update rule: (removed overly long and unimportant code and replaced with ...)
CREATE RULE update_fva_fullview
AS ON UPDATE TO fva_gpi_sbcpcba_voapcba
DO INSTEAD
(UPDATE voa_pcba
SET (voa_pcba_serial_number, ..., ch4_voa_cqr_link)
= (NEW.voa_pcba_serial_number, ..., NEW.ch4_voa_cqr_link)
WHERE voa_pcba_serial_number = OLD.voa_pcba_serial_number;
UPDATE sbc_pcba
SET (sbc_pcba_serial_number, sbc_fw_revision, sbc_mac_address, sbc_test_result_link)
= (NEW.sbc_pcba_serial_number, NEW.sbc_fw_revision, NEW.sbc_mac_address, NEW.sbc_test_result_link)
WHERE sbc_pcba_serial_number = OLD.sbc_pcba_serial_number;
UPDATE fva_3800
SET (product_serial_number, status_pcba_serial_number, sbc_pcba_serial_number, voa_pcba_serial_number)
= (NEW.product_serial_number, NEW.status_pcba_serial_number, NEW.sbc_pcba_serial_number, NEW.voa_pcba_serial_number)
WHERE product_serial_number = OLD.product_serial_number;
UPDATE general_product_info
SET (product_serial_number, part_number, innovator_product_bom, calibration_certificate, manual,
application_sw_name, application_sw_rev, test_report_link, production_exceptions, notes)
= (NEW.product_serial_number, NEW.part_number, NEW.innovator_product_bom, NEW.calibration_certificate, NEW.manual,
NEW.application_sw_name, NEW.application_sw_rev, NEW.test_report_link, NEW.production_exceptions, NEW.notes)
WHERE product_serial_number = OLD.product_serial_number;);
View: (in full... sorry, it is long, but I'd rather not cause confusion)
CREATE OR REPLACE VIEW fva_gpi_sbcpcba_voapcba AS
SELECT product_serial_numbers.product_serial_number, general_product_info.part_number, general_product_info.innovator_product_bom,
general_product_info.calibration_certificate, general_product_info.manual, general_product_info.application_sw_name,
general_product_info.application_sw_rev, general_product_info.test_report_link, fva_3800.status_pcba_serial_number,
sbc_pcba.sbc_pcba_serial_number, sbc_pcba.sbc_fw_revision, sbc_pcba.sbc_mac_address, sbc_pcba.sbc_test_result_link,
voa_pcba.voa_pcba_serial_number, voa_pcba.voa_fw_revision, voa_pcba.voa_test_result_link, voa_pcba.ch1_tap_part_number,
voa_pcba.ch1_tap_serial_number, voa_pcba.ch1_tap_cqr_link, voa_pcba.ch1_voa_part_number, voa_pcba.ch1_voa_serial_number,
voa_pcba.ch1_voa_cqr_link, voa_pcba.ch2_tap_part_number, voa_pcba.ch2_tap_serial_number, voa_pcba.ch2_tap_cqr_link,
voa_pcba.ch2_voa_part_number, voa_pcba.ch2_voa_serial_number, voa_pcba.ch2_voa_cqr_link, voa_pcba.ch3_tap_part_number,
voa_pcba.ch3_tap_serial_number, voa_pcba.ch3_tap_cqr_link, voa_pcba.ch3_voa_part_number, voa_pcba.ch3_voa_serial_number,
voa_pcba.ch3_voa_cqr_link, voa_pcba.ch4_tap_part_number, voa_pcba.ch4_tap_serial_number, voa_pcba.ch4_tap_cqr_link,
voa_pcba.ch4_voa_part_number, voa_pcba.ch4_voa_serial_number, voa_pcba.ch4_voa_cqr_link, general_product_info.production_exceptions,
general_product_info.notes, general_product_info.gpi_id
FROM product_serial_numbers
INNER JOIN general_product_info ON product_serial_numbers.product_serial_number = general_product_info.product_serial_number
INNER JOIN fva_3800 ON product_serial_numbers.product_serial_number = fva_3800.product_serial_number
INNER JOIN sbc_pcba ON fva_3800.sbc_pcba_serial_number = sbc_pcba.sbc_pcba_serial_number
INNER JOIN voa_pcba ON fva_3800.voa_pcba_serial_number = voa_pcba.voa_pcba_serial_number;
product_serial_number is a pkey in product_serial_numbers table, and a unique fkey in general_product_info and fva_3800 tables.
edit:
fva_3800_product_serial_number_fkey FOREIGN KEY (product_serial_number) REFERENCES product_serial_numbers(product_serial_number) ON UPDATE CASCADE ON DELETE SET NULL
All of the constraints for fkeys are like this. They all have CASCADE and SET NULL.
Here is the definition of fva_3800 table:
CREATE TABLE FVA_3800 (
id serial CONSTRAINT fva_3800_id_pkey PRIMARY KEY,
product_serial_number varchar(32) UNIQUE REFERENCES Product_Serial_Numbers(product_serial_number) ON UPDATE CASCADE ON DELETE SET NULL,
status_PCBA_serial_number varchar(32),
SBC_PCBA_serial_number varchar(32) REFERENCES SBC_PCBA(SBC_PCBA_serial_number) ON UPDATE CASCADE ON DELETE SET NULL,
VOA_PCBA_serial_number varchar(32) REFERENCES VOA_PCBA(VOA_PCBA_serial_number) ON UPDATE CASCADE ON DELETE SET NULL
);
Instead of using Rules, I used Functions and Triggers.
Rules just don't work properly in this situation for UPDATEs nor DELETEs
CREATE FUNCTION update_fva_full() RETURNS TRIGGER AS $_$
BEGIN
UPDATE voa_pcba
SET (voa_pcba_serial_number, voa_fw_revision, voa_test_result_link, ch1_tap_part_number, ch1_tap_serial_number, ch1_tap_cqr_link,
ch1_voa_part_number, ch1_voa_serial_number, ch1_voa_cqr_link, ch2_tap_part_number, ch2_tap_serial_number, ch2_tap_cqr_link,
ch2_voa_part_number, ch2_voa_serial_number, ch2_voa_cqr_link, ch3_tap_part_number, ch3_tap_serial_number, ch3_tap_cqr_link,
ch3_voa_part_number, ch3_voa_serial_number, ch3_voa_cqr_link, ch4_tap_part_number, ch4_tap_serial_number, ch4_tap_cqr_link,
ch4_voa_part_number, ch4_voa_serial_number, ch4_voa_cqr_link)
= (NEW.voa_pcba_serial_number, NEW.voa_fw_revision, NEW.voa_test_result_link, NEW.ch1_tap_part_number, NEW.ch1_tap_serial_number, NEW.ch1_tap_cqr_link,
NEW.ch1_voa_part_number, NEW.ch1_voa_serial_number, NEW.ch1_voa_cqr_link, NEW.ch2_tap_part_number, NEW.ch2_tap_serial_number, NEW.ch2_tap_cqr_link,
NEW.ch2_voa_part_number, NEW.ch2_voa_serial_number, NEW.ch2_voa_cqr_link, NEW.ch3_tap_part_number, NEW.ch3_tap_serial_number, NEW.ch3_tap_cqr_link,
NEW.ch3_voa_part_number, NEW.ch3_voa_serial_number, NEW.ch3_voa_cqr_link, NEW.ch4_tap_part_number, NEW.ch4_tap_serial_number, NEW.ch4_tap_cqr_link,
NEW.ch4_voa_part_number, NEW.ch4_voa_serial_number, NEW.ch4_voa_cqr_link)
WHERE voa_pcba_serial_number = OLD.voa_pcba_serial_number;
UPDATE sbc_pcba
SET (sbc_pcba_serial_number, sbc_fw_revision, sbc_mac_address, sbc_test_result_link)
= (NEW.sbc_pcba_serial_number, NEW.sbc_fw_revision, NEW.sbc_mac_address, NEW.sbc_test_result_link)
WHERE sbc_pcba_serial_number = OLD.sbc_pcba_serial_number;
UPDATE fva_3800
SET (product_serial_number, status_pcba_serial_number, sbc_pcba_serial_number, voa_pcba_serial_number)
= (NEW.product_serial_number, NEW.status_pcba_serial_number, NEW.sbc_pcba_serial_number, NEW.voa_pcba_serial_number)
WHERE product_serial_number = OLD.product_serial_number;
UPDATE general_product_info
SET (product_serial_number, part_number, innovator_product_bom, calibration_certificate, manual,
application_sw_name, application_sw_rev, test_report_link, production_exceptions, notes)
= (NEW.product_serial_number, NEW.part_number, NEW.innovator_product_bom, NEW.calibration_certificate, NEW.manual,
NEW.application_sw_name, NEW.application_sw_rev, NEW.test_report_link, NEW.production_exceptions, NEW.notes)
WHERE product_serial_number = OLD.product_serial_number;
RETURN OLD;
END $_$ LANGUAGE 'plpgsql';
CREATE TRIGGER update_from_fva_view
INSTEAD OF UPDATE ON fva_gpi_sbcpcba_voapcba
FOR EACH ROW EXECUTE PROCEDURE update_fva_full();

Cannot insert NULL value into column error

I have a issue where I want to update a column in a table and with a trigger to update same column but in another table. It says I cannot insert NULL but I can't seem to understand from where it gets that NULL value. This is the trigger:
CREATE TRIGGER Custom_WF_Update_WF_DefinitionSteps_DefinitionId ON WF.Definition
AFTER UPDATE AS BEGIN
IF UPDATE(DefinitionId)
IF TRIGGER_NESTLEVEL() < 2
BEGIN
ALTER TABLE WF.DefinitionSteps NOCHECK CONSTRAINT ALL
UPDATE WF.DefinitionSteps
SET DefinitionId =
(SELECT i.DefinitionId
FROM inserted i,
deleted d
WHERE WF.DefinitionSteps.DefinitionId = d.DefinitionId
AND i.oldPkCol = d.DefinitionId)
WHERE WF.DefinitionSteps.DefinitionId IN
(SELECT DefinitionId FROM deleted)
ALTER TABLE WF.DefinitionSteps CHECK CONSTRAINT ALL
END
END
This update statement works just fine:
UPDATE [CCHMergeIntermediate].[WF].[Definition]
SET DefinitionId = source.DefinitionId + 445
FROM [CCHMergeIntermediate].[WF].[Definition] source
But this one fails:
UPDATE [CCHMergeIntermediate].[WF].[Definition]
SET DefinitionId = target.DefinitionId
FROM [CCHMergeIntermediate].[WF].[Definition] source
INNER JOIN [centralq3].[WF].[Definition] target
ON (((source.Name = target.Name) OR (source.Name IS NULL AND target.Name IS NULL)))
I get the following error:
Msg 515, Level 16, State 2, Procedure Custom_WF_Update_WF_DefinitionSteps_DefinitionId, Line 7
Cannot insert the value NULL into column 'DefinitionId', table 'CCHMergeIntermediate.WF.DefinitionSteps'; column does not allow nulls. UPDATE fails.
If I do a select instead of the update statement, like this:
SELECT source.DefinitionId, target.DefinitionId
FROM [CCHMergeIntermediate].[WF].[Definition] source
INNER JOIN [centralq3].[WF].[Definition] target
ON (((source.Name = target.Name) OR (source.Name IS NULL AND target.Name IS NULL)))
I get this result:
http://i.stack.imgur.com/3cZsM.png (sorry for external link, I don't have enaugh reputation to post image here )
What am I doing wrong? What I don't see? What am I missing..?
The problem was in the trigger at the condition. I modified the second where from i.oldPkCol = d.DefinitionId to i.oldPkCol = **d.oldPkCol** and it worked.
UPDATE WF.DefinitionSteps
SET DefinitionId =
(SELECT i.DefinitionId
FROM inserted i,
deleted d
WHERE WF.DefinitionSteps.DefinitionId = d.DefinitionId
AND i.oldPkCol = **d.oldPkCol**)
WHERE WF.DefinitionSteps.DefinitionId IN
(SELECT DefinitionId FROM deleted)