Initialize generator with existing value - firebird

I am trying to set a generator with a value that is in some table, I have already seen this question How to set initial generator value? and did what they suggested but I don't know where am I going wrong here.
set term #
execute block
as
declare i int = 0;
begin
i = (select max(some_col) from Table);
gen_id(some_gen,-(gen_id(some_gen,0))); ---set some_gen to 0
gen_id(some_gen,:i); --- set to i
end #
set term ;#

The problem with your code is that you can't execute gen_id in isolation; the parser expects gen_id (or more precisely: a function call) only in a place where you can have a value (eg in a statement or an assignment). You need to assign its return value to a parameter, for example:
set term #;
execute block
as
declare i int = 0;
declare temp int = 0;
begin
i = (select max(id) from items);
temp = gen_id(GEN_ITEMS_ID, -(gen_id(GEN_ITEMS_ID, 0))); ---set some_gen to 0
temp = gen_id(GEN_ITEMS_ID, :i); --- set to i
end #
set term ;#
Please be aware that changing sequences like this is 'risky': if there are any interleaving actions using this same sequence, you might not actually get the result you expected (the sequence might end up at a different value than i and you might get duplicate key errors when another transaction uses the sequence after you subtract the current value (set to 0) and before you add i.
As also noted in the comments, you can also replace your code with:
set term #;
execute block
as
declare i int = 0;
declare temp int = 0;
begin
i = (select max(id) from items);
temp = gen_id(GEN_ITEMS_ID, :i - gen_id(GEN_ITEMS_ID, 0));
end #
set term ;#
Doing it in one statement will reduce the risk of interleaving operations (although it will not remove it entirely).

If you want to use "execute block", you may use something like :
execute block
as
declare i int = 0;
begin
i = (select max(some_col) from some_table);
execute statement ('set generator MY_GENERATOR to ' || :i);
end

Related

Getting a value from stored procedure within a stored procedure

I have a stored procedure which returns an XML file. At the moment some calculations are done in XSL but I would like to do these within the database using another stored procedure. (adding the result of that calculation to the XML)
ALTER PROCEDURE [dbo].[app_Get_Phone_And_Tariffs]
-- Add the parameters for the stored procedure here
#phone nvarchar(150)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT
PB.UID as '#phoneid',
PB.Short_Title as '#title',
PB.Description as '#desc',
PB.Camera as '#camera',
PB.Storage as '#storage',
PB.Screen_Size as '#screensize',
PB.OS as '#os',
PB.Processor as '#chip',
PB.Image1 as '#image',
PB.Trade_Price as '#tradeprice',
(SELECT
TB.UID as '#tariffid',
TB.Tariff_Name as '#name',
TB.Carrier as '#network',
TB.Inclusive_Minutes as '#mins',
TB.Inclusive_Texts as '#texts',
TB.Inclusive_Data as '#data',
TB.Monthly_Cost as '#monthly',
TB.Commission as '#comm',
(TB.Commission - PB.Trade_Price) as '#upfront'
FROM dbo.Tariff_Base TB
WHERE TB.Active = 1 AND TB.Type = 1
FOR XML PATH('tariff'), TYPE
),
(SELECT
OP.GP_Margin as '#gpmargin'
FROM dbo.Options OP
FOR XML PATH('options'), TYPE
)
FROM dbo.Phone_Base PB
WHERE PB.Friendly_URL_Name = #phone AND PB.Active = 1
FOR XML PATH('detail'), TYPE
END
What I want to do is:
In the inner select (TB) is to call another SP lets call it "calculate" passing 2 variables (TB.Commission and PB.Trade_Price) for the sum
Calculate will return a value i.e. #hp to the stored procedure which can be added/used in the XML List.
Can this be done in SQL Server 2014/T-SQL?
No. But you could do it with a function. See the MSDN documentation, especially example A.
Something like this (untested):
CREATE FUNCTION dbo.Calculate (#Comission float, #TradePrice float)
RETURNS float
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE #SumVal float;
SET #SumVal = #Commission + # TradeValue;
RETURN(#SumVal);
END;
GO
--In your sub-query
SELECT values, dbo.Calculate(TB.Commission, PB.Trade_Price) AS A_Sum
FROM ...;

How to assign variable if Cursor returns Bit of 0

I have written a cursor to search through a table looking at one bit value.
If all values are 1, I send an email. But if one value is 0 in any row, I don't send the email. The issue that I am having comes in my If statement. In SSMS, "#isComplete = 0" is breaking with only an "Incorrect syntax" error. I am not sure what I am missing here. My code is below. Thank you.
-------------------------------------------------
-- Start the INNER Cursor --
-------------------------------------------------
DECLARE #Complete int
DECLARE #isComplete Bit = 1
DECLARE INNERCur CURSOR FOR
SELECT Complete
FROM #AAEAPVS
OPEN INNERCur
FETCH NEXT FROM INNERCur INTO #Complete
WHILE ##FETCH_STATUS = 0
BEGIN
If #Complete = 0
BEGIN
#isComplete = 0
END
FETCH NEXT FROM INNERCur INTO #Complete
END
CLOSE InnerCurs
DEALLOCATE InnerCurs
-------------------------------------------------
-- INNER Curser END --
-------------------------------------------------
The incorrect syntax is that you need to use SET to assign the variable value, so change
#isComplete = 0
to
SET #isComplete = 0
And assuming you want to exit as soon as you find something that is not complete you should change your WHILE condition to
WHILE ##FETCH_STATUS = 0 AND #isComplete = 1
But most important of all, you probably don't need to use a cursor at all - you should avoid cursors in SQL if possible. You can probably just do something like this
DECLARE #isComplete Bit = 1
IF EXISTS (SELECT * FROM #AAEAPVS WHERE Complete = 0)
BEGIN
SET #isComplete = 0
END
and even that is more than you need, you can do it in a single statement
DECLARE #isComplete Bit = 1
SELECT #isComplete = 0 FROM #AAEAPVS WHERE Complete = 0
The syntax error results from not having a statement on the line. You need to use either SET or SELECT to assign a value to a variable, e.g. set #isComplete = 0.
Why, pray tell, a cursor rather than a simple EXISTS query? A far more efficient solution is:
select #isComplete = case
when exists ( select 42 from #AAEAPVS where Complete = 0 ) then 0
else 1 end;
Tip: It is helpful to tag database questions with both the appropriate software (MySQL, Oracle, DB2, ...) and version, e.g. sql-server-2014. Differences in syntax and features often affect the answers.

How to update a record on another table based on the values of the record being modified using a trigger

I have two simple (only for explain my problem) tables
X with columns (among others): IDX,CODE,NUMBER
Y with columns (among others): CODE,NUMBER,id_fromX
I want to (after insert or update table X) update table Y using variables from actual record from X.
To do this I try to use trigger (in table X) like below:
SET TERM ^^ ;
CREATE TRIGGER XYZFOR X ACTIVE AFTER INSERT OR UPDATE POSITION 0 AS
begin
if (new.CODE is distinct old.CODE) then
BEGIN
EXECUTE STATEMENT ('UPDATE Y SET CODE=:old.CODE, id_fromX=:old.IDX WHERE NUMBER=:old.NUMBER');
END
end ^^
but I get error from the server:
Execute statement error at jrd8_prepare :\
335544569 : Dynamic SQL Error
335544436 : SQL error code = -104
335544634 : Token unknown - line 1, column 23
335544382 : .
Statement : UPDATE Y SET CODE=:old.CODE, id_fromX=:old.IDX WHERE NUMBER=:old.NUMBER\
Data source : Internal::
At trigger 'XYZ' line: 15, col: 7
Static update like this below:
CREATE TRIGGER XYZ FOR X ACTIVE AFTER INSERT OR UPDATE POSITION 0 AS
begin
if (new.CODE is distinct from old.CODE) then
BEGIN
EXECUTE STATEMENT ('UPDATE Y SET CODE=1, id_fromX=111 WHERE NUMBER=1');
END
end ^^
SET TERM ; ^^
works perfect.
How to reference to X table fields to update table Y (fields with similar names)?
You're using a colon, but the old/new records don't use it. Also, don't use a execute statement here, since the sql statement is static.
Change it to:
SET TERM ^^ ;
CREATE TRIGGER XYZFOR X ACTIVE AFTER INSERT OR UPDATE POSITION 0 AS
begin
if (new.CODE is distinct old.CODE) then
BEGIN
UPDATE Y
SET CODE = old.CODE, id_fromX = old.IDX
WHERE NUMBER = old.NUMBER;
END
end ^^
You can't write parameters directly into statement with EXECUTE STATEMENT, see documentation for correct syntax. Basically, it should be something like
EXECUTE STATEMENT ('UPDATE Y SET CODE = :CODE, id_fromX = :IDX WHERE NUMBER=:NUMBER')
(CODE := old.CODE, IDX := old.IDX, NUMBER := old.NUMBER);
But you actually don't need the EXECUTE STATEMENT here, use UPDATE statement "directly".
You can't use the trigger context variables (old.<column> and new.<column>) in EXECUTE STATEMENT as they are separate contexts (the statement in EXECUTE STATEMENT can't see them). You either need to use a normal UPDATE statement without resorting to EXECUTE STATEMENT, or you should pass parameters. Like:
EXECUTE STATEMENT
('UPDATE Y SET CODE=:code, id_fromX=:idx WHERE NUMBER=:number')
(code := old.CODE, idx := old.IDX, number := old.NUMBER);
Shouldn't :old.CODE be old.CODE?

Using patterns in REPLACE

I need to find and replace an expression within a dynamic query. I have a subset of a where condition in string type like
'fieldA=23 OR field_1=300 OR fieldB=4'
What I need is to find a way to detect expression field_1=300 within the string and replace it while retaining the expression field_1=300.
I can do the detection part using CHARINDEX or PATINDEX but I'm not able to figure out how to use the patterns in the REPLACE function and how to get the value of the field_1 parameter.
Thanks in advance.
I'm not entirely clear on what you're trying to acheieve (e.g. what are you wanting to replace "field_1=300" with, and is it the exact string "field_1=300" that you're looking for, or just the field name, i.e. "field_1"?).
Also, could you paste in the code you've written so far?
Here's a simple script which will extract the current value of a given field name:
DECLARE #str VARCHAR(100),
#str_tmp VARCHAR(100),
#field_pattern VARCHAR(10),
#field_val INT;
SET #str = 'fieldA=23 OR field_1=300 OR fieldB=4';
SET #field_pattern = 'field_1='
-- This part will extract the current value assigned to the "#field_pattern" field
IF CHARINDEX(#field_pattern, #str) > 0
BEGIN
SELECT #str_tmp = SUBSTRING(#str,
CHARINDEX(#field_pattern, #str) + LEN(#field_pattern),
LEN(#str)
);
SELECT #field_val = CAST(SUBSTRING(#str_tmp, 1, CHARINDEX(' ', #str_tmp)-1) AS INT);
END
PRINT #field_val
If you want to replace the value itself (e.g. replacing "300" in this case with "600"), then you could add something like this:
DECLARE #new_val INT;
SET #new_val = 600;
SET #str = REPLACE(#str, (#field_pattern+CAST(#field_val AS VARCHAR)), (#field_pattern+CAST(#new_val AS VARCHAR)));
PRINT #str;
Which would give you "fieldA=23 OR field_1=600 OR fieldB=4".
Cheers,
Dave

Setting a variable in T-SQL from a Query

So I have this query:
select ens_use_new_models_bit from cfo_transaction
inner join dbo.cfo_trans_entity_rel on te_tr_transaction_id=tr_transaction_id
inner join cfo_tran_quote on tq_tr_transaction_id = tr_transaction_id
left outer join cfo_engine_sponsor on ens_rs_sponsor_id = te_co_re_entity_id
where te_rv_rel_type_id=713 and tq_tran_quote_id = 3
It returns a bit value, which can also be NULL. I hardcoded 3 for testing but in reality another proc passes this value in, but that's not important here.
Now, in a stored proc, I need to set a variable that's declared in the proc:
SET #vRtn = NULL
as the string - either 'VBEngines' or 'WFModels', or keep it NULL if the bit from above returns NULL.
'VBEngines' if the bit is off, 'WFModels' if the bit is on.
Then after that, I need to perform a T-SQL condition on the value, to see if it's NULL or not. How would I do this? I'm so bad with SQL.
Thanks.
Assuming that you don't need the bit value itself stored in a variable as that was just a means to an end then this should do it.
select #vRtn = case ens_use_new_models_bit
when 0 then 'VBEngines'
when 1 then 'WFModels'
end /*Implicit Else NULL case*/
from cfo_transaction ...
In the case 0 rows are returned no assignment is made so #vRtn keeps its initial value,
declare #newmodelsbit bit, #vRtn varchar(10)
select #newmodelsbit = ens_use_new_models_bit from cfo_transaction
inner join dbo.cfo_trans_entity_rel on te_tr_transaction_id=tr_transaction_id
inner join cfo_tran_quote on tq_tr_transaction_id = tr_transaction_id
left outer join cfo_engine_sponsor on ens_rs_sponsor_id = te_co_re_entity_id
where te_rv_rel_type_id=713 and tq_tran_quote_id = 3
if #newmodelsbit is null
begin
set #vRtn = null
end
else
begin
if #newmodelsbit = 1 --bit is on
begin
set #vRtn = 'WFModels'
end
else -- bit is off
begin
set #vRtn = ' VBEngines'
end
end