postgresql - select from nested hstore and then delete - hstore

My code below works but is there a better approach to this? What would the syntax for the delete be?
Thanks in advance, my mainframe background is showing.
v_result boolean;
v_all_skills hstore [];
v_skill hstore;
v_skill_details hstore;
v_num_skills integer;
v_ii integer;
v_found boolean;
raise notice 'BEFORE (%)', v_all_skills;
select array_length(v_all_skills,1 ) into v_num_skills;
v_found = FALSE;
FOR v_ii IN 1..v_num_skills LOOP
v_skill = v_all_skills[v_ii];
v_found = v_skill -> 'skill_id' = v_skill_id;
IF v_found THEN
v_skill_details = v_skill -> 'skill_details';
**-- here I need to delete the selected v_skill from v_all_skills for the given skill_id**
EXIT;
END IF;
END LOOP;
raise notice 'v_found (%)', v_found;
raise notice 'AFTER v_all_skills (%)', v_all_skills;
raise notice 'AFTER v_skill_details (%)', v_skill_details;
NOTICE: BEFORE ({"\"skill_id\"=>\"aa000001\", \"skill_details\"=>\"\\"skill_level\\"=>\\"5\\", \\"level_confirmed\\"=>\\"true\\", \\"level_confirmed_by\\"=>\\"624\\"\""})
NOTICE: v_found (t)
NOTICE: AFTER v_all_skills \n ({"\"skill_id\"=>\"aa000001\", \"skill_details\"=>\"\\"skill_level\\"=>\\"5\\", \\"level_confirmed\\"=>\\"true\\", \\"level_confirmed_by\\"=>\\"624\\"\""})
NOTICE: AFTER v_skill_details ("skill_level"=>"5", "level_confirmed"=>"true", "level_confirmed_by"=>"624")

OK, I have re-designed it to get the desired result with a new hstore v_all_skills_new
FOR v_ii IN 1..v_num_skills LOOP
v_skill = v_all_skills[v_ii];
v_found = v_skill -> 'skill_id' = v_skill_id;
CASE
WHEN (v_action = 1 OR v_action = 2) THEN -- insert/update the a skill
IF NOT v_found THEN -- keep existing skill before inserting the new one
v_all_skills_new = array_append(v_all_skills_new , v_skill);
END IF;
-- build the new/updated skill from input
v_skill_details = hstore(ARRAY['skill_level','level_confirmed','level_confirmed_by'],
ARRAY[v_skill_level::TEXT, v_skill_level_confirmed::TEXT, v_skill_level_confirmed_by::TEXT]);
v_skill = hstore(ARRAY['skill_id', 'skill_details'],
ARRAY[v_skill_id::TEXT, v_skill_details::TEXT]);
v_all_skills_new = array_append(v_all_skills_new, v_skill); -- insert new/updated skill
WHEN v_action = 3 THEN -- delete(i.e. do not move to new array) skill if found
IF NOT v_found THEN -- keep existing skill before inserting the new one
v_all_skills_new = array_append(v_all_skills_new , v_skill);
END IF;
END CASE;
END LOOP;

Related

function in plsql

I have created this function and it works:
create or replace function log_in(
p_ssnr in customer.ssnr%type,
p_password in customer.password%type)
return number
as
v_number number(1);
begin
if
(p_ssnr is not null and p_password is not null) then
v_number:= 1;
else
v_number:= 0;
end if;
return v_number;
end;
If I then type: select log_in('social security number','the password') from dual; then I get a "1"
so it works. But you could basically type whatever you want and it will work so it is not a clean code. Since you can't include subquery in the if statement, how can you create the function so you only return 1 when you actually type a social security number (ssnr) and a password that matches the actual customer table? and otherwise you return 0?
NOt sure if you can have multiple rows for same customer. If yes, then use this:
create or replace function log_in(
p_ssnr in customer.ssnr%type,
p_password in customer.password%type)
return number
as
v_number number(1);
begin
select case when count(*) > 0 then 1 else 0 end
into v_number
from customer
where ssnr = p_ssnr and password = p_password;
return v_number;
end;
If not then this should be fine:
create or replace function log_in(
p_ssnr in customer.ssnr%type,
p_password in customer.password%type)
return number
as
v_number number(1);
begin
count(*)
into v_number
from customer
where ssnr = p_ssnr and password = p_password;
return v_number;
end;

How does PLSQL function return text validation work?

Unfortunately my validation doesn't work when i click a submit button. When I do click the submit button 'what' appears as error which is b = null below. How would you validate a registration page after the person presses the submit button. Or how would you do validation after submit button?
DECLARE
error_message varchar2(4000);
b varchar2(500);
FUNCTION validate_field RETURN VARCHAR2
AS
BEGIN
b := :P101_REG_FIRST_NAME;
IF (REGEXP_LIKE(b, '[A-Za-z]') AND :P101_NEW <> NULL AND NOT(REGEXP_LIKE(b, '[:space:]'))) THEN
RETURN 'works' || b;
ELSIF b IS NULL THEN
RETURN b || 'what';
ELSIF REGEXP_COUNT(b, '[A-Za-z]') = 1 THEN
RETURN 'Name cannot be single letter';
ELSE RETURN 'HUH' || ' ' || b;
END IF;
END;
BEGIN
error_message := '';
error_message := validate_field;
IF error_message IS NULL THEN
RETURN NULL;
ELSE
RETURN error_message;
END IF;
COMMIT;
END;
I solved it. I'll post the answer in the morning, it's late and I've stayed up too long solving this issue. I feel good though. Thank you for reading all of this.

Delphi save packed record as blob in a sql database [duplicate]

I want to store images in a database using sql but cant seem to get it to work:
qry.SQL.Clear;
qry.Sql.Add('update tbl set pic = :blobVal where id = :idVal');
qry.Parameters.ParamByName('idVal')._?:=1;
.Parameters has no .asinteger like .Param has but .Param isn't compatible with a TADOquery - to workaround I tried:
a_TParameter:=qry.Parameters.CreateParameter('blobval',ftBlob,pdinput,SizeOf(TBlobField),Null);
a_TParam.Assign(a_TParameter);
a_TParam.asblob:=a_Tblob;
qry.ExecSql;
This also doesnt work:
qry.SQL.Clear;
qry.Sql.Add('update tbl set pic = :blobVal where id = 1')
qry.Parameters.ParamByName('blobVal').LoadFromStream(img as a_TFileStream,ftGraphic);//ftblob
//or
qry.Parameters.ParamByName('blobVal').LoadFromFile('c:\sample.jpg',ftgrafic);//ftblob
qry.ExecSql;
Should be something like:
qry.Parameters.Clear;
qry.Parameters.AddParameter.Name := 'blobVal';
qry.Parameters.ParamByName('blobVal').LoadFromFile('c:\sample.jpg', ftBlob);
// or load from stream:
// qry.Parameters.ParamByName('blobVal').LoadFromStream(MyStream, ftBlob);
qry.Parameters.AddParameter.Name := 'idVal';
qry.Parameters.ParamByName('idVal').Value := 1;
qry.SQL.Text := 'update tbl set pic = :blobVal where id = :idVal';
qry.ExecSQL;
To read the BLOB back from the DB:
qry.SQL.Text := 'select id, pic from tbl where id = 1';
qry.Open;
TBlobField(qry.FieldByName('pic')).SaveToFile('c:\sample_2.jpg');
I'm using Lazarus, not Delphi, but I guess its usually the same syntax. If so, here's a slight improvement on kobiks suggestion:
Parameters are added automatically if the SQL.Text is assigned before trying to assign values to the parameters. Like this:
qry.Parameters.Clear;
qry.SQL.Text := 'update tbl set pic = :blobVal where id = :idVal';
qry.Parameters.ParamByName('blobVal').LoadFromFile('c:\sample.jpg', ftBlob);
qry.Parameters.ParamByName('idVal').Value := 1;
qry.ExecSQL;
I wrote this as an answer to this q,
Delphi save packed record as blob in a sql database
which is currently flagged as a duplicate, possibly incorrectly because the technique
used by the OP as described in comments appears to be correct. So, the cause of the problem may lie elsewhere.
If the Duplicate flag gets removed, I'll re-post this answer there.
The following code works fine for me against a Sql Server table defined as shown below.
The data from Rec1 is saved into the table and correctly read back into Rec2.
(* MS Sql Server DDL
CREATE TABLE [blobs] (
[id] [int] NOT NULL ,
[blob] [image] NULL ,
CONSTRAINT [PK_blobs] PRIMARY KEY CLUSTERED
(
[id]
) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
*)
TForm1 = class(TForm)
ADOConnection1: TADOConnection;
qBlobInsert: TADOQuery;
qBlobRead: TADOQuery;
Button1: TButton;
procedure Button1Click(Sender: TObject);
[...]
type
TMyRecord = packed record
FontName: string[30];
FontSize: word;
FontColor: integer;
FontStyle: word;
Attachement: string[255];
URL: string[255];
end;
const
scInsert = 'insert into blobs(id, blob) values(:id, :blob)';
scSelect = 'select * from blobs where id = %d';
procedure TForm1.Button1Click(Sender: TObject);
begin
TestInsert;
end;
procedure TForm1.TestInsert;
var
Rec1,
Rec2 : TMyRecord;
MS : TMemoryStream;
begin
FillChar(Rec1, SizeOf(Rec1), #0);
FillChar(Rec2, SizeOf(Rec2), #0);
Rec1.FontName := 'AName';
Rec1.URL := 'AUrl';
MS := TMemoryStream.Create;
try
// Save Rec1 using an INSERT statement
MS.Write(Rec1, SizeOf(Rec1));
MS.Seek(0, soFromBeginning);
qBlobInsert.Parameters[0].Value := 1;
qBlobInsert.Parameters[1].LoadFromStream(MS, ftBlob);
qBlobInsert.SQL.Text := scInsert;
qBlobInsert.ExecSQL;
// Read saved data back into Rec2
qBlobRead.SQL.Text := Format(scSelect, [1]);
qBlobRead.Open;
MS.Clear;
TBlobField(qBlobRead.FieldByName('blob')).SaveToStream(MS);
MS.Seek(0, soFromBeginning);
MS.Read(Rec2, MS.Size - 1);
Caption := Rec2.FontName + ':' + Rec2.URL;
finally
MS.Free;
end;
end;
Extract from DFM
object qBlobInsert: TADOQuery
Connection = ADOConnection1
Parameters = <
item
Name = 'id'
DataType = ftInteger
Value = Null
end
item
Name = 'blob'
DataType = ftBlob
Value = Null
end>
Left = 56
Top = 32
end

Updating a record in database

Using TADOCommand to update a record.
using TADOCommand to insert a new record.
Name of table is Board
Using MS Access database
I get an error
Syntax error in UPDATE/INSERT INTO statement
I can connect and retrieve data just fine. Just never added or updated data before.
My database columns looks like this
ID (auto number)
SN (text)
CardType (text)
Desc (memo)
dbDate (date)
Tech (text)
Code looks like this:
procedure TForm2.BSaveClick(Sender: TObject);
const
sqlStringNew = 'INSERT INTO Board (SN,CardType,Desc,dbDate,Tech) VALUES (:aSN,:aCardType,:aDesc,:aDate,:aTech);';
sqlStringUpdate = 'UPDATE Board SET SN=:aSN, CardType=:aCardType, Desc=:aDesc, dbDate=:aDate, Tech=:aTech WHERE ID = :aID;';
var
ADOCommand : TAdoCommand;
begin
ADOCommand := TADOCommand.Create(nil);
// updating a board
if NewBoard = false then
begin
try
ADOCommand.Connection := adoConnection1;
ADOCommand.Parameters.Clear;
ADOCommand.Commandtext := sqlStringUpdate;
ADOCommand.ParamCheck := false;
ADOCommand.Parameters.ParamByName('aSN').Value := ESerialNumber.Text;
ADOCommand.Parameters.ParamByName('aCardType').Value := ECardType.Text;
ADOCommand.Parameters.ParamByName('aDesc').Value := MDescription.Text;
ADOCommand.Parameters.ParamByName('aDate').Value := strtodate(EDate.Text);
ADOCommand.Parameters.ParamByName('aTech').Value := ETech.Text;
ADOCommand.Parameters.ParamByName('aID').Value := UpdateID;
ADOCommand.Execute;
finally
ADOCommand.Free;
end;
Showmessage('Update Complete');
end;
//if a new board
if NewBoard = True then
Begin
try
ADOCommand.Connection := adoConnection1;
ADOCommand.Parameters.Clear;
ADOCommand.Commandtext := sqlStringNew;
ADOCommand.ParamCheck := false;
ADOCommand.Parameters.ParamByName('aSN').Value := ESerialNumber.Text;
ADOCommand.Parameters.ParamByName('aCardType').Value := ECardType.Text;
ADOCommand.Parameters.ParamByName('aDesc').Value := MDescription.Text;
ADOCommand.Parameters.ParamByName('aDate').Value := strtodate(EDate.Text);
ADOCommand.Parameters.ParamByName('aTech').Value := ETech.Text;
ADOCommand.Execute;
finally
ADOCommand.Free;
end;
NewBoard := false;
BSave.Enabled := false;
NoEdit;
Showmessage('New Record Added');
End;
end;
It is advisable not to use SQL keywords for table and field names. DATE is a function in many SQL dialects. If you choose to use a reserved word/function name for a table/field name, you have to escape it in SQL statement: [Date] for SQL Server and MS Access, "Date" - for Oracle.

Insert/update TBlobfield (aka image) using sql parameters

I want to store images in a database using sql but cant seem to get it to work:
qry.SQL.Clear;
qry.Sql.Add('update tbl set pic = :blobVal where id = :idVal');
qry.Parameters.ParamByName('idVal')._?:=1;
.Parameters has no .asinteger like .Param has but .Param isn't compatible with a TADOquery - to workaround I tried:
a_TParameter:=qry.Parameters.CreateParameter('blobval',ftBlob,pdinput,SizeOf(TBlobField),Null);
a_TParam.Assign(a_TParameter);
a_TParam.asblob:=a_Tblob;
qry.ExecSql;
This also doesnt work:
qry.SQL.Clear;
qry.Sql.Add('update tbl set pic = :blobVal where id = 1')
qry.Parameters.ParamByName('blobVal').LoadFromStream(img as a_TFileStream,ftGraphic);//ftblob
//or
qry.Parameters.ParamByName('blobVal').LoadFromFile('c:\sample.jpg',ftgrafic);//ftblob
qry.ExecSql;
Should be something like:
qry.Parameters.Clear;
qry.Parameters.AddParameter.Name := 'blobVal';
qry.Parameters.ParamByName('blobVal').LoadFromFile('c:\sample.jpg', ftBlob);
// or load from stream:
// qry.Parameters.ParamByName('blobVal').LoadFromStream(MyStream, ftBlob);
qry.Parameters.AddParameter.Name := 'idVal';
qry.Parameters.ParamByName('idVal').Value := 1;
qry.SQL.Text := 'update tbl set pic = :blobVal where id = :idVal';
qry.ExecSQL;
To read the BLOB back from the DB:
qry.SQL.Text := 'select id, pic from tbl where id = 1';
qry.Open;
TBlobField(qry.FieldByName('pic')).SaveToFile('c:\sample_2.jpg');
I'm using Lazarus, not Delphi, but I guess its usually the same syntax. If so, here's a slight improvement on kobiks suggestion:
Parameters are added automatically if the SQL.Text is assigned before trying to assign values to the parameters. Like this:
qry.Parameters.Clear;
qry.SQL.Text := 'update tbl set pic = :blobVal where id = :idVal';
qry.Parameters.ParamByName('blobVal').LoadFromFile('c:\sample.jpg', ftBlob);
qry.Parameters.ParamByName('idVal').Value := 1;
qry.ExecSQL;
I wrote this as an answer to this q,
Delphi save packed record as blob in a sql database
which is currently flagged as a duplicate, possibly incorrectly because the technique
used by the OP as described in comments appears to be correct. So, the cause of the problem may lie elsewhere.
If the Duplicate flag gets removed, I'll re-post this answer there.
The following code works fine for me against a Sql Server table defined as shown below.
The data from Rec1 is saved into the table and correctly read back into Rec2.
(* MS Sql Server DDL
CREATE TABLE [blobs] (
[id] [int] NOT NULL ,
[blob] [image] NULL ,
CONSTRAINT [PK_blobs] PRIMARY KEY CLUSTERED
(
[id]
) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
*)
TForm1 = class(TForm)
ADOConnection1: TADOConnection;
qBlobInsert: TADOQuery;
qBlobRead: TADOQuery;
Button1: TButton;
procedure Button1Click(Sender: TObject);
[...]
type
TMyRecord = packed record
FontName: string[30];
FontSize: word;
FontColor: integer;
FontStyle: word;
Attachement: string[255];
URL: string[255];
end;
const
scInsert = 'insert into blobs(id, blob) values(:id, :blob)';
scSelect = 'select * from blobs where id = %d';
procedure TForm1.Button1Click(Sender: TObject);
begin
TestInsert;
end;
procedure TForm1.TestInsert;
var
Rec1,
Rec2 : TMyRecord;
MS : TMemoryStream;
begin
FillChar(Rec1, SizeOf(Rec1), #0);
FillChar(Rec2, SizeOf(Rec2), #0);
Rec1.FontName := 'AName';
Rec1.URL := 'AUrl';
MS := TMemoryStream.Create;
try
// Save Rec1 using an INSERT statement
MS.Write(Rec1, SizeOf(Rec1));
MS.Seek(0, soFromBeginning);
qBlobInsert.Parameters[0].Value := 1;
qBlobInsert.Parameters[1].LoadFromStream(MS, ftBlob);
qBlobInsert.SQL.Text := scInsert;
qBlobInsert.ExecSQL;
// Read saved data back into Rec2
qBlobRead.SQL.Text := Format(scSelect, [1]);
qBlobRead.Open;
MS.Clear;
TBlobField(qBlobRead.FieldByName('blob')).SaveToStream(MS);
MS.Seek(0, soFromBeginning);
MS.Read(Rec2, MS.Size - 1);
Caption := Rec2.FontName + ':' + Rec2.URL;
finally
MS.Free;
end;
end;
Extract from DFM
object qBlobInsert: TADOQuery
Connection = ADOConnection1
Parameters = <
item
Name = 'id'
DataType = ftInteger
Value = Null
end
item
Name = 'blob'
DataType = ftBlob
Value = Null
end>
Left = 56
Top = 32
end