Change condition from column index to column value in DB cross tab in Fast Report - crosstab

I have a scrip in DB Cross tab in fast report but i want change condition from ColumnIndex to ColumnValue
procedure DBCross1OnPrintCell(Memo: TfrxMemoView; RowIndex, ColumnIndex, CellIndex: Integer; RowValues, ColumnValues, Value: Variant);
begin
if ColumnIndex = 0 then
if Value <> null then
Set('Var0', Value)
else
Set('Var0', 0);
if DBCross1.IsGrandTotalColumn(ColumnIndex) then
Memo.Text := Format('%2.0n', [StrToFloat(VarToStr(value- Get('Var0')))]);
end;
enter image description here
I want Instead ColumnIndex = 0 . i have for example
if ColumnValue = 'joy' and columnvalue = 'jack'
...

Try
procedure Cross1OnPrintCell(Memo: TfrxMemoView; RowIndex, ColumnIndex, CellIndex: Integer; RowValues, ColumnValues, Value: Variant);
begin
if ColumnValues[0] = '2000' then if ColumnValues[1] = '2' then Memo.Color := clRed;
end;

Related

Postgres User-defined Aggregation

i'd like to create a user defined aggregation function.
My own type:
CREATE TYPE state AS(
reservoir integer[5],
skipcnt int,
reservoir_size int
);
SFUNC:
create function res_trans (currentstate state,newsample int)
returns state
as $$
DECLARE
pos integer := 0;
BEGIN
IF currentstate.skipcnt = -1 THEN
currentstate.skipcnt := 5;
ELSIF currentstate.skipcnt = 0 THEN
pos := floor(random()*currentstate.reservoir_size+1);
currentstate.reservoir := res_array_replace(currentstate.reservoir,pos,newsample);
currentstate.skipcnt := 5;
ELSE
currentstate.skipcnt := currentstate.skipcnt - 1;
END IF;
RETURN currentstate;
END;
$$LANGUAGE plpgsql;
finalfunc:
CREATE FUNCTION finalize_trans(finalstate state) RETURNS integer[]
AS $$
BEGIN
RETURN finalstate.reservoir;
END;
$$LANGUAGE plpgsql;
All the functions above can be created successfully. However, when i create the aggregation. It shows some error.
CREATE AGGREGATE reservoir_sampling(int)
(
INITCOND = ROW('{1,2,3,4,5}',-1,5),
STYPE = state,
SFUNC = res_trans,
FINALFUNC = finalize_trans
);
enter image description here
Is there a problem of the initcond?
Please help me, Thanks!
I tried to let the initcond = null and deal with the null case in SFUNC, but i got enter image description here
The manual about initial_condition says
This must be a string constant in the form accepted for the data type state_data_type
So you need to provide a string constant, not a "row" expression:
CREATE AGGREGATE reservoir_sampling(int)
(
INITCOND = '("{1,2,3,4,5}",-1,5)',
STYPE = state,
SFUNC = res_trans,
FINALFUNC = finalize_trans
);

Postgresql Simple IF ELSE Statement

In MS SQL I can execute a statement like:
Declare #foo int = 1, #foo1 int = 42
IF #foo <> 0
BEGIN
SELECT #foo
END
ELSE
BEGIN
SELECT #foo, #foo1
END
Does anyone have any idea how to run this statement on postgresql?
EDIT: MS SQL Example like :
CREATE PROCEDURE dbo.spIFtest
#p1 int = 1,
#p2 int = 10,
#isFilter bit = 0
AS
BEGIN
IF #isFilter = 1
BEGIN
SELECT idx FROM rw.octest where idx between #p1 and #p2
END
ELSE
BEGIN
SELECT idx FROM rw.octest
END
END
GO
Using DO With caveats:
DO $$
DECLARE
foo integer := 1;
foo1 integer := 42;
BEGIN
IF foo <> 0 THEN
PERFORM foo;
ELSE
PERFORM foo, foo1;
END IF;
END;
$$
;
DO cannot return anything.
You can fake a return:
DO $$
DECLARE
foo integer := 0;
foo1 integer := 42;
BEGIN
IF foo <> 0 THEN
SELECT INTO foo 1;
RAISE NOTICE 'foo is %', foo;
ELSE
SELECT INTO foo, foo1 1, 42 ;
RAISE NOTICE 'foo is %, foo1 is %', foo, foo1;
END IF;
END;
$$
;
NOTICE: foo is 1, foo1 is 42
DO
In PostgreSQL DO Block can execute the queries but they can not return any value.
So the first part of your question is not possible directly in postgresql.
For second part of your question: In PostgreSQL you can use Function (which is very powerful and effective) like below:
create or replace function spiftest()
returns table(idx_ int)
as $$
declare
p1 int := 1;
p2 int := 10;
isfilter boolean := 0;
begin
if isfilter then
return query
SELECT idx FROM octest where idx between p1 and p2;
else
return query
SELECT idx FROM octest ;
end if;
end;
$$
language plpgsql
calling above function for result:
select * from spiftest()
You can write it with parameters also like below:
create or replace function spiftest(p1 int, p2 int, isfilter boolean)
returns table(idx_ int)
as $$
begin
if isfilter then
return query
SELECT idx FROM octest where idx between p1 and p2;
else
return query
SELECT idx FROM octest ;
end if;
end;
$$
language plpgsql
to call above function
select * from spiftest(1,10,'t')

How get row count from return type in postgres?

I have a function that return a table (my customer type).
How I can get row count of return object?
CREATE TYPE observer_holder AS ("CustomerName" TEXT,"CustomerFamily" TEXT)
CREATE OR REPLACE FUNCTION getItem(i_callStateText TEXT, i_maxText TEXT)
RETURNS SETOF observer_holder
LANGUAGE plpgsql
AS $$
declare
sendOffset INTEGER;
fetchRecord RECORD;
result observer_holder;
runQuery2 BOOLEAN := lower(trim(both ' ' from i_callStateText)) ='notnull' AND (position('::tsrange' in i_maxText) < 1);
query1 TEXT := '...';
query2 TEXT := '...';
BEGIN
FOR fetchRecord IN EXECUTE CASE WHEN runQuery2 THEN query2 ELSE query1 END LOOP
result."CustomerFamily" := customerRecord.family;
result."CustomerName" := customerRecord.name;
.
.
.
RETURN next result;
END LOOP;
-- my question , how get result count?
RAISE notice 'row count: %', length(result::observer_holder); >> Exception
RETURN;
END; $$;
I need result row count. Please help me.

Hide column in DB cross-tab for FastReport

I've been trying to hide column from a DB cross-tab in FastReport when the column header Value is 14001 ; but is not work down syntax !!!
My Report
Here's the code:
procedure DBCross2OnCalcWidth(ColumnIndex: Integer; ColumnValues: Variant;var Width: Extended);
begin
if (VarToStr(ColumnValues[0]) = '14001') then
Width := 0;
end;
Try add procedure trigged on print and collection HeaderValues[0]
procedure DBCross2OnPrintColumnHeader(Memo: TfrxMemoView; HeaderIndexes, HeaderValues, Value: Variant);
begin
if (VarToStr(HeaderValues[0]) = '14001') then
begin
Memo.Width := 0;
Memo.Height := 0;
Memo.Printable := false;
Memo.Visible := false;
end;
end;

How can I return optional results from a dynamic query in a plpgsql function?

I'm playing around with plpgsql and have put together a function that assembles a dynamic query. I've tested it and it executes (i've included a test wrapper to output the assembled query).
Where I'm stumbling is capturing the output of the EXECUTE command once it's run, because I'd like to return some or all of the values, depending on the nature of the dynamic query. I've set up a type userprofile, and have the setProfileDynamic function return this type.
With the full complement of parameters, the output checks out (except for the second query, more on that in a bit). But when some of the parameters are missing (ie not all the user preferences are updated, only one eg: measuresystem) then the output is corrupted, so that measuresystem_id might appear as username in the output.
Secondly, is how to get the result of the second query (updateDefaultMealplan) into the userprofile type (where the columns mealplan_id and mealplan_name are waiting patiently). Currently this query returns into mp_id (and mp_name is filled from the _values array if 'defaultmealplan' key is present).
I'm quite new to this and I might be trying to do too much in one function, and I might be doing it completely the wrong way, so I don't mind whatever corrections might come to pass.
The userprofile type:
DROP TYPE IF EXISTS userprofile CASCADE;
CREATE TYPE userprofile AS (
username text,
measuresystem_id int,
blanksymbol_id int,
mealplan_id int,
mealplan_name text
);
The main function
DROP FUNCTION IF EXISTS setProfileDynamic (int, text, text[], text[]);
CREATE OR REPLACE FUNCTION setProfileDynamic (_userid int, _token text, _keys text[], _values text[])
RETURNS userprofile AS $$
DECLARE
_query text;
numkeys int;
i int;
_update text[];
_from text[];
_where text[];
_return text[];
_into text[];
test text[];
up userprofile;
mp_name text;
mp_id int;
u text;
f text;
w text;
r text;
c_update int := 1;
c_from int := 1;
c_where int := 3;
c_return int := 1;
runupdate boolean := false; --bc passing default mealplan through this fn too.
changedefaultmp boolean := false;
BEGIN
test[1] := 'users.id';
test[2] := 'users.token';
test[3] := _userid;
test[4] := _token;
numkeys := array_length(_keys, 1);
raise notice 'numkeys = %', numkeys;
_where[1] := test[1] || ' = ' || quote_literal(test[3]);
_where[2] := test[2] || ' = ' || quote_literal(test[4]);
--raise notice '_where[1] = %', _where[1];
--raise notice '_where[2] = %', _where[2];
for i in 1..numkeys loop
raise notice 'keys[%] = %', i, _keys[i];
CASE _keys[i]
WHEN 'email' THEN
runupdate := true;
_update[c_update] := quote_ident(_keys[i]) || ' = ' || quote_literal(_values[i]);
c_update := c_update + 1;
WHEN 'password' THEN
runupdate := true;
_update[c_update] := quote_ident(_keys[i]) || ' = ' || quote_literal(_values[i]);
c_update := c_update + 1;
WHEN 'username' THEN
runupdate := true;
_update[c_update] := quote_ident(_keys[i]) || ' = ' || quote_literal(_values[i]);
c_update := c_update + 1;
_return[c_return] := quote_ident(_keys[i]);
c_return := c_return + 1;
WHEN 'measuresystem' THEN
runupdate := true;
_update[c_update] := 'measuresystem_id = ms.id';
c_update := c_update + 1;
_from[c_from] := 'measuresystem as ms';
c_from := c_from + 1;
_where[c_where] := 'ms.name = ' || quote_literal(_values[i]);
c_where := c_where + 1;
_return[c_return] := 'ms.id';
c_return := c_return + 1;
WHEN 'blanksymbol' THEN
runupdate := true;
_update[c_update] := 'blanksymbol_id = bs.id';
c_update := c_update + 1;
_from[c_from] := 'blanksymbol as bs';
c_from := c_from + 1;
_where[c_where] := 'bs.name = ' || quote_literal(_values[i]);
c_where := c_where + 1;
_return[c_return] := 'bs.id';
c_return := c_return + 1;
ELSE
changedefaultmp := true;
mp_name := _values[i];
END CASE;
end loop;
u := 'UPDATE users SET ' || array_to_string(_update, ', ');
f := 'FROM ' || array_to_string(_from, ', '); --if a_t_s is null, the whole f is null and not included so no error
w := 'WHERE ' || array_to_string(_where, ' AND ');
r := 'RETURNING ' || array_to_string(_return, ', ');
raise notice 'u = %', u;
raise notice 'f = %', f;
raise notice 'w = %', w;
raise notice 'r = %', r;
_query = concat_ws(' ', u, f, w, r);
raise notice '_query = %', _query;
IF runupdate THEN
if r IS NULL THEN
EXECUTE _query;
ELSE
EXECUTE _query INTO up;
END IF;
END IF;
IF changedefaultmp THEN
SELECT into mp_id updateDefaultMealplan(_userid, mp_name);
END IF;
return up;
END
$$ LANGUAGE PLPGSQL;
This is the wrapper function where you can see the query generated for different inputs:
DROP FUNCTION IF EXISTS T ();
CREATE OR REPLACE FUNCTION T ()
RETURNS setof userprofile AS $$
declare
_keys text[];
_values text[];
_userid int := 1;
_token text := 'beet';
begin
_keys := ARRAY['email', 'password', 'username', 'measuresystem', 'blanksymbol', 'defaultmealplan'];
_values := ARRAY['s#p.com', 'secret', 'myname', 'metric', '?', 'new'];
--_keys := ARRAY['email', 'blanksymbol'];
--_values := ARRAY['k#d.com', '[]'];
return query
SELECT * from setProfileDynamic(_userid, _token, _keys, _values);
end
$$ LANGUAGE PLPGSQL;
I realize it's a lot of code to get through, I hope the T function helps to clarify things. 'email' and 'password' params are not returning. 'defaultmealplan' triggers the second query. Any of 'username', 'measuresystem', 'blanksymbol' or 'defaultmealplan' should return a value into the userprofile type. Thanks for any forthcoming feedback.
the basic issue is so your dynamic query doesn't returns all necessary columns, second issue - you probably expecting, but it is not valid expectation, so records are assigned with respecting field' names. But when you assign some values to some composite type, postgres dosn't check name - only order is important. So you have to use NULLs for filling gaps and return all field.
you can simplify your code with array concating
DECLARE _return_cols text[] = '{}';
BEGIN
_return_cols := _return_cols || quote_ident('some_column');
_return_cols := _return_cols || quote_ident('some_other_column');
...