How can I add some text after some sequence of text if this sequence matches certain criteria using Shell...












0














I want to add a statement just after the text matching the conditions mentioned in a shell script,



Below is my sample File(SQL File) :



begin
AFFECTED_ROWS := 0;

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;

DELETE FROM table_name
WHERE condition;

INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
end;


I will take this file and perform below transformation,
Once I see any of below Text in sequence



1: "UPDATE ... SET ...;"
2: "DELETE ... FROM ...;"
3: "INSERT ... INTO ...;"
4: "MERGE ... INTO ... [WHEN MATCHED THEN | WHEN NOT MATCHED] ... [UPDATE|INSERT|DELETE] ... ;"


I need to add 1 extra row just after the semicolon



AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;


So My new file will look like something below



begin
AFFECTED_ROWS := 0;

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

DELETE FROM table_name
WHERE condition;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

end;


I tried finding and implementing the approach in the scope of PLSQL but didn't find any generic way possible to get no of rows affected, so I thought
of text parsing but I don't know much about awk or sed.



For now what I was trying to do something like below:



sed '/Patterns Go Here/a AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;' temp.sql



So pattern may have conditions mentioned above










share|improve this question






















  • Welcome to Unix & Linux. ;-) You might be better off on our sister site Database Administrators...
    – Fabby
    Oct 24 at 23:00


















0














I want to add a statement just after the text matching the conditions mentioned in a shell script,



Below is my sample File(SQL File) :



begin
AFFECTED_ROWS := 0;

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;

DELETE FROM table_name
WHERE condition;

INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
end;


I will take this file and perform below transformation,
Once I see any of below Text in sequence



1: "UPDATE ... SET ...;"
2: "DELETE ... FROM ...;"
3: "INSERT ... INTO ...;"
4: "MERGE ... INTO ... [WHEN MATCHED THEN | WHEN NOT MATCHED] ... [UPDATE|INSERT|DELETE] ... ;"


I need to add 1 extra row just after the semicolon



AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;


So My new file will look like something below



begin
AFFECTED_ROWS := 0;

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

DELETE FROM table_name
WHERE condition;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

end;


I tried finding and implementing the approach in the scope of PLSQL but didn't find any generic way possible to get no of rows affected, so I thought
of text parsing but I don't know much about awk or sed.



For now what I was trying to do something like below:



sed '/Patterns Go Here/a AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;' temp.sql



So pattern may have conditions mentioned above










share|improve this question






















  • Welcome to Unix & Linux. ;-) You might be better off on our sister site Database Administrators...
    – Fabby
    Oct 24 at 23:00
















0












0








0







I want to add a statement just after the text matching the conditions mentioned in a shell script,



Below is my sample File(SQL File) :



begin
AFFECTED_ROWS := 0;

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;

DELETE FROM table_name
WHERE condition;

INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
end;


I will take this file and perform below transformation,
Once I see any of below Text in sequence



1: "UPDATE ... SET ...;"
2: "DELETE ... FROM ...;"
3: "INSERT ... INTO ...;"
4: "MERGE ... INTO ... [WHEN MATCHED THEN | WHEN NOT MATCHED] ... [UPDATE|INSERT|DELETE] ... ;"


I need to add 1 extra row just after the semicolon



AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;


So My new file will look like something below



begin
AFFECTED_ROWS := 0;

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

DELETE FROM table_name
WHERE condition;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

end;


I tried finding and implementing the approach in the scope of PLSQL but didn't find any generic way possible to get no of rows affected, so I thought
of text parsing but I don't know much about awk or sed.



For now what I was trying to do something like below:



sed '/Patterns Go Here/a AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;' temp.sql



So pattern may have conditions mentioned above










share|improve this question













I want to add a statement just after the text matching the conditions mentioned in a shell script,



Below is my sample File(SQL File) :



begin
AFFECTED_ROWS := 0;

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;

DELETE FROM table_name
WHERE condition;

INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
end;


I will take this file and perform below transformation,
Once I see any of below Text in sequence



1: "UPDATE ... SET ...;"
2: "DELETE ... FROM ...;"
3: "INSERT ... INTO ...;"
4: "MERGE ... INTO ... [WHEN MATCHED THEN | WHEN NOT MATCHED] ... [UPDATE|INSERT|DELETE] ... ;"


I need to add 1 extra row just after the semicolon



AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;


So My new file will look like something below



begin
AFFECTED_ROWS := 0;

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

DELETE FROM table_name
WHERE condition;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

end;


I tried finding and implementing the approach in the scope of PLSQL but didn't find any generic way possible to get no of rows affected, so I thought
of text parsing but I don't know much about awk or sed.



For now what I was trying to do something like below:



sed '/Patterns Go Here/a AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;' temp.sql



So pattern may have conditions mentioned above







shell-script shell awk grep






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Oct 24 at 22:39









Hargun Suri

6




6












  • Welcome to Unix & Linux. ;-) You might be better off on our sister site Database Administrators...
    – Fabby
    Oct 24 at 23:00




















  • Welcome to Unix & Linux. ;-) You might be better off on our sister site Database Administrators...
    – Fabby
    Oct 24 at 23:00


















Welcome to Unix & Linux. ;-) You might be better off on our sister site Database Administrators...
– Fabby
Oct 24 at 23:00






Welcome to Unix & Linux. ;-) You might be better off on our sister site Database Administrators...
– Fabby
Oct 24 at 23:00












1 Answer
1






active

oldest

votes


















1














I have solved it by using perl instead of sed and using the IRS (Input Record Separator - $/) special variable to process lines by semi-colon, rather than by newline.



Any language that supports changing the IRS should work (probably possible with pure bash using IFS=';', but I haven't explored this).



In this example, perl will load it's buffer until the input record separator, then process all that content as a line - by changing what that separator is, you can process the file a statement at a time, rather than a line at a time. I can then match the pattern of the statement(s) I'm interested in, and append the affected rows logic to the line before it gets printed.



$ cat test.sql
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);

SELECT another-non-matching-statement FROM table;

end;

$ cat test.sql | perl -pe 'BEGIN{$/=";"} m/MERGE INTO .*/ && ($_ .= "nAFFECTED_ROWS := AFFECTED_ROWS + SQL %ROWCOUNT;")'
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

SELECT another-non-matching-statement FROM table;

end;

$


Using less perl shorthand, you might do this:



perl -e '$/=";"; foreach $statement (<>){ print $statement; $statement =~ m/(MERGE INTO .*)|(DELETE FROM)/i && print "nAFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;" }'


e.g.:



cat test.sql | perl -e '$/=";"; foreach $statement (<>){ print $statement; $statement =~ m/(MERGE INTO .*)|(DELETE FROM)/i && print "nAFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;" }'
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

SELECT another-non-matching-statement FROM table;

DELETE FROM truncate_me;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

end;
$





share|improve this answer























  • perl $/ is the input record separator, not field. awk can do the same (portably) with -vRS=';' and bash can do read -d';' but that's nonstandard and less efficient. Note all such approaches fail if any of your statements has a char/string literal containing semicolon like SET recipe = 'mix this; stir that'
    – dave_thompson_085
    Oct 25 at 1:30












  • Good points, thanks dave_thompson. Embedded separators will be many grief, so issues - and handling them will require a lot more sophistication than can be encapsulated in a one-liner. Re field/separator, yeah, I had IFS on the brain from some other work, just typed it without thinking. Thanks for the catch, will edit.
    – GarethHumphriesAcc
    Oct 25 at 2:28











Your Answer








StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f477631%2fhow-can-i-add-some-text-after-some-sequence-of-text-if-this-sequence-matches-cer%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














I have solved it by using perl instead of sed and using the IRS (Input Record Separator - $/) special variable to process lines by semi-colon, rather than by newline.



Any language that supports changing the IRS should work (probably possible with pure bash using IFS=';', but I haven't explored this).



In this example, perl will load it's buffer until the input record separator, then process all that content as a line - by changing what that separator is, you can process the file a statement at a time, rather than a line at a time. I can then match the pattern of the statement(s) I'm interested in, and append the affected rows logic to the line before it gets printed.



$ cat test.sql
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);

SELECT another-non-matching-statement FROM table;

end;

$ cat test.sql | perl -pe 'BEGIN{$/=";"} m/MERGE INTO .*/ && ($_ .= "nAFFECTED_ROWS := AFFECTED_ROWS + SQL %ROWCOUNT;")'
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

SELECT another-non-matching-statement FROM table;

end;

$


Using less perl shorthand, you might do this:



perl -e '$/=";"; foreach $statement (<>){ print $statement; $statement =~ m/(MERGE INTO .*)|(DELETE FROM)/i && print "nAFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;" }'


e.g.:



cat test.sql | perl -e '$/=";"; foreach $statement (<>){ print $statement; $statement =~ m/(MERGE INTO .*)|(DELETE FROM)/i && print "nAFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;" }'
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

SELECT another-non-matching-statement FROM table;

DELETE FROM truncate_me;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

end;
$





share|improve this answer























  • perl $/ is the input record separator, not field. awk can do the same (portably) with -vRS=';' and bash can do read -d';' but that's nonstandard and less efficient. Note all such approaches fail if any of your statements has a char/string literal containing semicolon like SET recipe = 'mix this; stir that'
    – dave_thompson_085
    Oct 25 at 1:30












  • Good points, thanks dave_thompson. Embedded separators will be many grief, so issues - and handling them will require a lot more sophistication than can be encapsulated in a one-liner. Re field/separator, yeah, I had IFS on the brain from some other work, just typed it without thinking. Thanks for the catch, will edit.
    – GarethHumphriesAcc
    Oct 25 at 2:28
















1














I have solved it by using perl instead of sed and using the IRS (Input Record Separator - $/) special variable to process lines by semi-colon, rather than by newline.



Any language that supports changing the IRS should work (probably possible with pure bash using IFS=';', but I haven't explored this).



In this example, perl will load it's buffer until the input record separator, then process all that content as a line - by changing what that separator is, you can process the file a statement at a time, rather than a line at a time. I can then match the pattern of the statement(s) I'm interested in, and append the affected rows logic to the line before it gets printed.



$ cat test.sql
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);

SELECT another-non-matching-statement FROM table;

end;

$ cat test.sql | perl -pe 'BEGIN{$/=";"} m/MERGE INTO .*/ && ($_ .= "nAFFECTED_ROWS := AFFECTED_ROWS + SQL %ROWCOUNT;")'
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

SELECT another-non-matching-statement FROM table;

end;

$


Using less perl shorthand, you might do this:



perl -e '$/=";"; foreach $statement (<>){ print $statement; $statement =~ m/(MERGE INTO .*)|(DELETE FROM)/i && print "nAFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;" }'


e.g.:



cat test.sql | perl -e '$/=";"; foreach $statement (<>){ print $statement; $statement =~ m/(MERGE INTO .*)|(DELETE FROM)/i && print "nAFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;" }'
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

SELECT another-non-matching-statement FROM table;

DELETE FROM truncate_me;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

end;
$





share|improve this answer























  • perl $/ is the input record separator, not field. awk can do the same (portably) with -vRS=';' and bash can do read -d';' but that's nonstandard and less efficient. Note all such approaches fail if any of your statements has a char/string literal containing semicolon like SET recipe = 'mix this; stir that'
    – dave_thompson_085
    Oct 25 at 1:30












  • Good points, thanks dave_thompson. Embedded separators will be many grief, so issues - and handling them will require a lot more sophistication than can be encapsulated in a one-liner. Re field/separator, yeah, I had IFS on the brain from some other work, just typed it without thinking. Thanks for the catch, will edit.
    – GarethHumphriesAcc
    Oct 25 at 2:28














1












1








1






I have solved it by using perl instead of sed and using the IRS (Input Record Separator - $/) special variable to process lines by semi-colon, rather than by newline.



Any language that supports changing the IRS should work (probably possible with pure bash using IFS=';', but I haven't explored this).



In this example, perl will load it's buffer until the input record separator, then process all that content as a line - by changing what that separator is, you can process the file a statement at a time, rather than a line at a time. I can then match the pattern of the statement(s) I'm interested in, and append the affected rows logic to the line before it gets printed.



$ cat test.sql
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);

SELECT another-non-matching-statement FROM table;

end;

$ cat test.sql | perl -pe 'BEGIN{$/=";"} m/MERGE INTO .*/ && ($_ .= "nAFFECTED_ROWS := AFFECTED_ROWS + SQL %ROWCOUNT;")'
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

SELECT another-non-matching-statement FROM table;

end;

$


Using less perl shorthand, you might do this:



perl -e '$/=";"; foreach $statement (<>){ print $statement; $statement =~ m/(MERGE INTO .*)|(DELETE FROM)/i && print "nAFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;" }'


e.g.:



cat test.sql | perl -e '$/=";"; foreach $statement (<>){ print $statement; $statement =~ m/(MERGE INTO .*)|(DELETE FROM)/i && print "nAFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;" }'
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

SELECT another-non-matching-statement FROM table;

DELETE FROM truncate_me;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

end;
$





share|improve this answer














I have solved it by using perl instead of sed and using the IRS (Input Record Separator - $/) special variable to process lines by semi-colon, rather than by newline.



Any language that supports changing the IRS should work (probably possible with pure bash using IFS=';', but I haven't explored this).



In this example, perl will load it's buffer until the input record separator, then process all that content as a line - by changing what that separator is, you can process the file a statement at a time, rather than a line at a time. I can then match the pattern of the statement(s) I'm interested in, and append the affected rows logic to the line before it gets printed.



$ cat test.sql
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);

SELECT another-non-matching-statement FROM table;

end;

$ cat test.sql | perl -pe 'BEGIN{$/=";"} m/MERGE INTO .*/ && ($_ .= "nAFFECTED_ROWS := AFFECTED_ROWS + SQL %ROWCOUNT;")'
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

SELECT another-non-matching-statement FROM table;

end;

$


Using less perl shorthand, you might do this:



perl -e '$/=";"; foreach $statement (<>){ print $statement; $statement =~ m/(MERGE INTO .*)|(DELETE FROM)/i && print "nAFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;" }'


e.g.:



cat test.sql | perl -e '$/=";"; foreach $statement (<>){ print $statement; $statement =~ m/(MERGE INTO .*)|(DELETE FROM)/i && print "nAFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;" }'
SELECT non-matching-statement FROM table;

MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

SELECT another-non-matching-statement FROM table;

DELETE FROM truncate_me;
AFFECTED_ROWS := AFFECTED_ROWS + SQL%ROWCOUNT;

end;
$






share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 14 at 3:25

























answered Oct 25 at 0:00









GarethHumphriesAcc

812




812












  • perl $/ is the input record separator, not field. awk can do the same (portably) with -vRS=';' and bash can do read -d';' but that's nonstandard and less efficient. Note all such approaches fail if any of your statements has a char/string literal containing semicolon like SET recipe = 'mix this; stir that'
    – dave_thompson_085
    Oct 25 at 1:30












  • Good points, thanks dave_thompson. Embedded separators will be many grief, so issues - and handling them will require a lot more sophistication than can be encapsulated in a one-liner. Re field/separator, yeah, I had IFS on the brain from some other work, just typed it without thinking. Thanks for the catch, will edit.
    – GarethHumphriesAcc
    Oct 25 at 2:28


















  • perl $/ is the input record separator, not field. awk can do the same (portably) with -vRS=';' and bash can do read -d';' but that's nonstandard and less efficient. Note all such approaches fail if any of your statements has a char/string literal containing semicolon like SET recipe = 'mix this; stir that'
    – dave_thompson_085
    Oct 25 at 1:30












  • Good points, thanks dave_thompson. Embedded separators will be many grief, so issues - and handling them will require a lot more sophistication than can be encapsulated in a one-liner. Re field/separator, yeah, I had IFS on the brain from some other work, just typed it without thinking. Thanks for the catch, will edit.
    – GarethHumphriesAcc
    Oct 25 at 2:28
















perl $/ is the input record separator, not field. awk can do the same (portably) with -vRS=';' and bash can do read -d';' but that's nonstandard and less efficient. Note all such approaches fail if any of your statements has a char/string literal containing semicolon like SET recipe = 'mix this; stir that'
– dave_thompson_085
Oct 25 at 1:30






perl $/ is the input record separator, not field. awk can do the same (portably) with -vRS=';' and bash can do read -d';' but that's nonstandard and less efficient. Note all such approaches fail if any of your statements has a char/string literal containing semicolon like SET recipe = 'mix this; stir that'
– dave_thompson_085
Oct 25 at 1:30














Good points, thanks dave_thompson. Embedded separators will be many grief, so issues - and handling them will require a lot more sophistication than can be encapsulated in a one-liner. Re field/separator, yeah, I had IFS on the brain from some other work, just typed it without thinking. Thanks for the catch, will edit.
– GarethHumphriesAcc
Oct 25 at 2:28




Good points, thanks dave_thompson. Embedded separators will be many grief, so issues - and handling them will require a lot more sophistication than can be encapsulated in a one-liner. Re field/separator, yeah, I had IFS on the brain from some other work, just typed it without thinking. Thanks for the catch, will edit.
– GarethHumphriesAcc
Oct 25 at 2:28


















draft saved

draft discarded




















































Thanks for contributing an answer to Unix & Linux Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f477631%2fhow-can-i-add-some-text-after-some-sequence-of-text-if-this-sequence-matches-cer%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Morgemoulin

Scott Moir

Souastre