How to create users from list in oracle? - sql

I'm trying to create users with the prefix sit from a list of the greek alphabet. Like sit-alpha, sit-beta, so on.
This is what I have so far:
BEGIN
LIST:= 'alpha, beta, gamma';
FOR u IN LIST
LOOP
EXECUTE IMMEDIATE 'CREATE USER SIT-' || TO_CHAR (U)||' IDENTIFIED BY
CLERK'||TO_CHAR (U) ;
EXECUTE IMMEDIATE 'GRANT CONNECT, RESOURCE TO SIT-'||TO_CHAR(U);
END LOOP;
END;
But it says "PLS-00201: identifier 'LIST' must be declared". How do I do this properly?

Your code is mostly correct. However, you need to split the comma-separated list of values into an array using the REGEXP_SUBSTR function to loop through each element in the list. About the error "PLS-00201: identifier 'LIST' must be declared" means that the LIST variable you used in your code is not declared. This error usually occurs when a variable has not been declared or initialized correctly. In your code, you must declare the LIST variable before using it. You can do this by using the DECLARE command at the beginning of your code, like this:
DECLARE
LIST VARCHAR2(200) := 'alpha, beta, gamma';
BEGIN
FOR u IN (SELECT trim(regexp_substr(LIST, '[^,]+', 1, LEVEL)) AS val FROM dual
CONNECT BY LEVEL <= regexp_count(LIST, ',') + 1)
LOOP
EXECUTE IMMEDIATE 'CREATE USER SIT-' || u.val || ' IDENTIFIED BY CLERK' || u.val;
EXECUTE IMMEDIATE 'GRANT CONNECT, RESOURCE TO SIT-' || u.val;
END LOOP;
END;
Here's a great explanation of my code :
The first line of the code is a DECLARE command that indicates the beginning of a variable declaration section. This section declares all the variables and constants that will be used in the rest of the code.
The second line declares a LIST variable of type VARCHAR2 with a maximum length of 200 characters. This variable contains a comma-separated list of the user names you wish to create.
The third line is the BEGIN command that indicates the start of the executable code block.
The fourth line begins a FOR loop that traverses each item in the list of usernames using a SELECT query.
The SELECT query uses the regexp_substr function to retrieve each comma-separated item in the list and returns it as a val. The trim function is used to remove any unnecessary spaces that may be present around each element in the list. The CONNECT BY clause is used to generate the rows necessary for the FOR loop to traverse each element in the list.
The FOR loop uses the variable u to store each element in the list at each iteration.
The two EXECUTE IMMEDIATE commands inside the FOR loop create a new user using the username SIT- followed by the value of val, and then add CONNECT and RESOURCE privileges to that user.
Finally, the last line of code is the END command which indicates the end of the executable code block.
In summary, this code extracts each item from the list of user names, creates a new user with a name that includes that item, and then adds CONNECT and RESOURCE privileges to that user. This code uses Oracle functions to extract each item from the list and dynamically create the users.

Related

How can I find / replace text in the Description field of a HelpNDoc file?

A HelpNDoc file allows you to provide a text value for the Description property. This field is used by search engines when crawling the HTML help.
I have added topics to my help over the years and some of these descriptions need updating. In my case I needed to replace all instances of Midweek Editor with Meeting Editor.
How can this be done since there is no built-in way to update the Description property in bulk.
This can be done by writing a script and using the HelpNDoc API. These scripts can be built and run with the Script Editor. The object we need to use is HndTopics.
The HndTopics object includes some useful methods:
GetTopicDescription
SetTopicDescription
These can be used in combination with the Pascal functions Pos / StringReplace.
var
// Current topic ID
aTopicId, aTopicDesc, aTopicDescNew: string;
begin
try
// Get first topic
aTopicId := HndTopics.GetTopicFirst();
// Loop through all topics
while aTopicId <> '' do
begin
// Does this topic description include the phrase?
aTopicDesc := HndTopics.GetTopicDescription(aTopicId);
if (pos('Midweek Editor', aTopicDesc) <> 0) then
begin
aTopicDescNew := StringReplace(aTopicDesc, 'Midweek Editor', 'Meeting Editor', [rfReplaceAll]);
HndTopics.SetTopicDescription(aTopicId, aTopicDescNew);
Print('Old: ' + aTopicDesc);
Print('New: ' + aTopicDescNew);
end;
// Get next topic
aTopicId := HndTopics.GetTopicNext(aTopicId);
end;
finally
end;
end.

Using NEW and COPY in a Postgres Trigger

I'm trying to copy the last inserted row from a table into a csv file using a trigger.
CREATE TRIGGER new_tbc_order
AFTER INSERT
ON trig_test
FOR EACH ROW
EXECUTE PROCEDURE write_last_tbc_order();
CREATE OR REPLACE FUNCTION write_last_tbc_order()
RETURNS TRIGGER
LANGUAGE plpgsql
as $$
BEGIN
EXECUTE 'COPY (
select i.id, i.paid, i.no_items FROM (SELECT NEW.*) AS i
) TO ''/Users/fred/Desktop/last_tbc_order.csv'' csv;' USING NEW;
RETURN NEW;
END; $$
I've tried this in various incarnations, with or without EXECUTE but I'm still getting the error.
ERROR: missing FROM-clause entry for table "new"
LINE 1: ...opy (select i.id, i.paid, i.no_items FROM (SELECT NEW.*) AS ...
^
Just cannot get it to access the NEW data.
Where am I going wrong ?
The only way I could get this to work is something like this:
CREATE OR REPLACE FUNCTION write_last_tbc_order()
RETURNS TRIGGER
LANGUAGE plpgsql
as $$
BEGIN
EXECUTE 'COPY (
select id, paid, no_items FROM trig_test WHERE id = ' || NEW.id ||
') TO ''/Users/fred/Desktop/last_tbc_order.csv'' csv;';
RETURN NEW;
END; $$
COPY does not seem to 'see' the NEW record. Be aware that the above will fail if the Postgres server does not have permissions on /Users/fred/Desktop/ as COPY runs as the server user. Personally I think a better solution is to write to a audit table and periodically harvest the records from there.
Adrian's answer inspired me to experiment more with the NEW record where it was actually available.
The actual answer, as usual, turned out to be simple-ish:
CREATE OR REPLACE FUNCTION write_last_tbc_order()
RETURNS TRIGGER
AS
$$
BEGIN
EXECUTE 'copy (select '''||NEW.id||''','''||NEW.paid||''','''||NEW.no_items||''')
to ''/Users/shaun/Desktop/last_tbc_order.csv'' csv;' USING NEW;
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
Thus keeping the NEW record outside of the copy statement and building it dynamically before the execute.
This still required the USING NEW part at the end to make it work correctly.
Also required all the quoting.
UPDATE:
The above code does require almost everything to be running as a Postgres Superuser, (as mentioned by several commenters), which is not ideal.
To get around this, you can create a PlPython function as follows:
CREATE OR REPLACE FUNCTION write_last_tbc_order()
RETURNS TRIGGER AS
'
import os
row = str(TD["new"]["id"]) + "," + TD["new"]["paid"] + "," + str(TD["new"]["noitems"])
path = "/tmp/db-data/last_order.csv";
with open(path,"w") as o:
os.chmod(path, 0o644)
o.write(row)
return None
'
LANGUAGE 'plpythonu';
This function must be created as a Superuser, but it can be used in triggers created by standard users, and those triggers also work when inserts are fired by standard users.
The place to where the file is written must have write permission for the postgres user in every part of the path, so I created a subdirectory of /tmp with 777 permissions.
Also needed to add in the os chmod 644 statement to make the file readable by other users on the system. Without this, the file is created with permissions of 600.
FURTHER NOTES:
In the end Apache doesn't like you to setup a virtual directory inside the /tmp directory so in the end had to create another called /tmp-wh specifically for this purpose.

Binding a foreign key when adding a new value to the master-detail table Delphi

There are 2 tables linked by master-detail. When adding a new value to the detail table, the foreign key selected from the master table is not bound.
The M-D connection itself is performed on the form using two Dblookupcombobox and DataSource, ADOQuery for each, respectively.
enter image description here
Using the [ + ] buttons, new values are added that are not present in the combobox. But the problems start at the second [ + ] (aka detail), when creating a new line, you need it to bind the foreign key from the previous LookUpComboBox (Master). Button code of the second button [+]:
begin
Form4.ADOQuery1.SQL.Clear;
Form4.ADOQuery1.SQL.Add('Select City from City WHERE City='+#39+Form5.DBEdit1.Text+#39); //checking for duplicates
Form4.ADOQuery1.Open;
if Form4.ADOQuery1.IsEmpty then
begin
Form4.Query_city.FieldByName('City').AsString := Form5.DBEdit1.Text; //The PROBLEM is SOMEWHERE HERE! It Adds a new value without binding the foreign key
Form4.Query_city.Open;
Form4.Query_city.Post;
MessageBox(Handle, 'New data entered','Adding a new value',MB_ICONINFORMATION);
end
else
begin
Form4.Query_spec.Cancel;
Form4.ADOQuery1.Cancel;
MessageBox(Handle,PChar(''+Form5.DBEdit1.text+' already on the list!'),'Error',MB_ICONWARNING);
end;
end;
The new value is written to DBEdit1. It has a corresponding binding to tables.
So How i can insert field with with the corresponding foreign key?
You are making this unneccessarily difficult because of the way your
code is structured. Try something like this instead:
Open ADOQuery1, SELECTing its entire contents, with e.g.
procedure TForm4.OpenCitiesTable;
begin
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('Select City from City');
ADOQuery1.Open;
end;
and leave it open while the user does whatever operations lead to wanting to add a new city.
Then, when the users wants to add a city, call this procedure, e.g. supplying the City
value from Form5.DBEdit1.Text.
procedure TForm4.AddCity(ACity : String);
begin
ACity := Trim(ACity); // remove any leading or trailing blanks
// Do any formatting checks on ACity here, re.g convert it to Proper case
// check for adding a duplicate
if ADOQuery1.Locate('City', ACity, []) then begin
ShowMessageFmt('%s is already in the City table', [ACity]);
Exit;
end;
try
ADOQuery1.Insert;
ADOQuery1.FieldByName('City').AsString := ACity;
finally
ADOQuery1.Post;
// at this point you might want to refresh the contents of whatever source
// you are populating Form5.DBEdit1.Text from
end;
end;
I assume you can adjust the code relating to TForm4.Query_spec yourself;
Btw, you might want to consider using a TDBLookUpComboBox instead of your DBEdit1.

How to fix error when value in SQL contains an apostrophe

I am updating a string in a table using a Firebird SQL statement, with information typed by a user. However, if the string entered by a user has an apostrophe then it creates an error because the SQL syntax no longer reads correctly.
I guess I could read the string and remove all instances of apostrophes, but I wonder if there is an easier way.
{Edit 17 May 2017}
I am using Firebird 2.5 (as part of a software program called Ostendo)
Here is an extract of the code:
UpdatedMsg := frmPOLineNotesMemo.Lines.text;
SQLUpdateStr := 'update ASSEMBLYLINES set LINENOTES = LINENOTES || '''+ UpdatedMsg +''' Where SYSUNIQUEID = ' + AssyPropertyLine + '';
ExecuteSQL(SQLUpdateStr);
frmPOLineNotesMemo.Lines.Text is information entered by the user via a form.
You need to double the apostrophes in the string.
Found here: https://firebirdsql.org/manual/qsg10-firebird-sql.html
However keep in mind the comments. User input should be passed as parameters to avoid security problems.

How use the insert query using parameters?

When i try with this query i get an error says that Perameter email doesn't exist, i am sure that the variables : email, login_pass, payment_method,operateur are valid and exists.
SQLQuery2.sql.Text := 'INSERT INTO registered (email,login_pass,payment_method,operateur) VALUES (":email",":login_pass",":payment_method",":avecpuce")';
SQLQuery2.ParamByName('email').AsString := email;
SQLQuery2.ParamByName('login_pass').AsString := login_pass;
SQLQuery2.ParamByName('payment_method').AsString := payment_method;
SQLQuery2.ParamByName('avecpuce').AsString := avecpuce;
SQLQuery2.ExecSQL(true);
I tried removing the quotation, but i get
You have an error in your Sql syntax, check the manual that corresponds to your SQL server for the right syntax to use near
':email,:login_pass,:payment_method,:avecpuce)' at line 1
How to use the insert query above using parameters?
From the TSQLQuery.ExecSQL documentation:
ExecDirect indicates that the query does not need to be prepared
before it is executed. This parameter can be set to true if the query
does not include any parameters.
So if the code uses
SQLQuery2.ExecSQL(true);
this means that there will be no support for parameters.
But because you use parameters, just use
SQLQuery2.ExecSQL;
and also remove the quotes around parameters.
Remove quotation marks:
SQLQuery2.sql.Text := 'INSERT INTO registered (email,login_pass,payment_method,operateur)
VALUES (:email, :login_pass, :payment_method, :avecpuce)';
Found the answer !
MySQLQuery2.SQL.Clear;
MySQLQuery2.SQL.Add('INSERT INTO COUNTRY (NAME, CAPITAL, POPULATION)');
MySQLQuery2.SQL.Add('VALUES (:Name, :Capital, :Population)');
MySQLQuery2.Params[0].AsString := 'Lichtenstein';
MySQLQuery2.Params[1].AsString := 'Vaduz';
MySQLQuery2.Params[2].AsInteger := 420000;
MySQLQuery2.ExecSQL;
Thankyou All !!
You don't usually quote parameters, only literals. So instead of:
VALUES (":email",":login_pass",":payment_method",":avecpuce")
Try:
VALUES (:email,:login_pass,:payment_method,:avecpuce)
You should not use quotes around the parameter name.
Parameters are automatically generated for you if your TSQLQuery has a connection assigned and ParamCheck is true and you assign TSQLQuery.CommandText.
It will not generate the parameters when you assign the query to TSQLQuery.SQL.Text.
You can have the parameters generated for you by calling TSQLQuery.Params.ParseSQL:
SQLQuery2.Params.ParseSQL(SQLQuery2.SQL.Text, True);
Or you can add them yourself by calling TSQLQuery.Params.AddParameter.