IBM i Access Client Solutions (ACS) Run SQL Scripts - print variable - sql-scripts

is there an easy way to display/print a variable on the output of the IBM i ACS Run SQL Script screen?
For having a quick check when writing a script it would very helpful to be able to display the content of a variable. E.g. in below script, I want to know the value of "my_counter".
BEGIN
DECLARE my_counter INT;
SET my_counter = my_counter + (SELECT count(*) FROM QSYS2.OBJECT_LOCK_INFO WHERE SYSTEM_OBJECT_SCHEMA = 'ABC' AND SYSTEM_OBJECT_NAME = 'DEF' AND OBJECT_TYPE = '*FILE');
SET my_counter = my_counter + (SELECT count(*) FROM QSYS2.OBJECT_LOCK_INFO WHERE SYSTEM_OBJECT_SCHEMA = 'ABC' AND SYSTEM_OBJECT_NAME = 'XYZ' AND OBJECT_TYPE = '*FILE');
PRINT my_counter; --> I want to print the content of variable my_counter but PRINT is not a valid keyword (all other valid keywords have a blue color, this one does not).
END;
You probably also notice that I'm doing "my_counter = my_counter + ...", I tried using "my_counter += ..." but no such thing. Is there a better way of doing this?

Hellow KoenS,
This is how I do this:
create or replace variable #my_Counter integer default 0;
SET #my_counter = #my_counter + (SELECT count(*) FROM QSYS2.OBJECT_LOCK_INFO WHERE SYSTEM_OBJECT_SCHEMA = 'ABC' AND SYSTEM_OBJECT_NAME = 'ABC' AND OBJECT_TYPE = '*FILE');
SET #my_counter = #my_counter + (SELECT count(*) FROM QSYS2.OBJECT_LOCK_INFO WHERE SYSTEM_OBJECT_SCHEMA = 'XYZ' AND SYSTEM_OBJECT_NAME = 'XYZ' AND OBJECT_TYPE = '*FILE');
select #my_Counter from sysibm.sysdummy1;
drop variable #my_Counter;
Variables are CL SRVPGM that are located in a library, if you have problems with it, especify library (abc.#my_Counter or use SET SCHEMA and SET PATH comands before create and use the variable.
I use # before variables by convention.
To display a variable use sysibm.sysdummy1 file.

Related

Assigning variable to Snowflake SQL based on condition

I am trying to execute a sql command based on input variable passed as parameter in Stored Procedure. If the parameter passed was INCR, I would like to append a part of the sql to final sql query variable.
var exec_cmnd = (load_type == 'INCR') ? "AND EXISTS (SELECT 1 FROM tbl T WHERE inner_tbl.id = outer_tbl.id)" : "1 = 1";
var qry = "`select * from tbl_a where name=name and `+exec_cmnd+`";
snowflake.execute({sqlText:qry});
But the condition seem to throw an error. Please let me know how i can assign a variable to a sql command query variable based on IF condition?
If load_type is passed into the stored procedure, you need to uppercase it in the body of the JavaScript.
https://docs.snowflake.com/en/sql-reference/stored-procedures-usage.html#case-sensitivity-in-javascript-arguments
Your concatenation is off slightly. I highly recommend using JavaScript literal templates for SQL in JavaScript stored procedures.
Open your string with a back tick and close with a back tick. You can then replace any JavaScript variable by wrapping it like this: ${myVariable}. It also allows you to use single and double quotes and multi-line statements in your SQL without issues.
create or replace procedure foo(load_type string)
returns string
language javascript
as
$$
var exec_cmnd = (LOAD_TYPE == 'INCR') ? "EXISTS (SELECT 1 FROM tbl T WHERE inner_tbl.id = outer_tbl.id)" : "1 = 1";
var qry = `select * from tbl_a where name=name and ${exec_cmnd}`;
return qry;
$$;
call foo('INCR');

informix update based on values in another table

I have the following select statement that works just fine:
select stock_master.stock_code, stk_stock_status, reorder_buyer, default_route_id, main_work_centre
from stock_master, bill_of_materials_header, production_routing
where stock_master.stock_code = bill_of_materials_header.stock_code
and bill_of_materials_header.default_route_id = production_routing.prh_route_id
and main_work_centre != "CNC";
and stock_group >= 3201 and stock_group <= 3299;
What I want to do is update the stk_stock_status to "M" for this condition, but can't seem to work out the correct syntax for the update command. Any pointers would be extremely helpful.
If stk_stock_status is instock_master table and this table has some ID column then convert your select into select that returns only identifiers which should be updated. It will look like:
UPDATE stock_master SET stk_stock_status = 'M' WHERE stk_stock_id IN
(
SELECT stk_stock_id
FROM stock_master, bill_of_materials_header, production_routing
WHERE stock_master.stock_code = bill_of_materials_header.stock_code
AND bill_of_materials_header.default_route_id = production_routing.prh_route_id
AND main_work_centre != 'CNC';
)
PS Do not use " for sting literals. It is allowed by Informix but not by SQL standard. Better use '.

T-SQL Matching process using only provided fields

I am trying to write a stored procedure to match lists of physicians with existing records in our database based off of the information provided to us by our clients. Currently we use MS Access to join manually based on the given identifiers, but this process tends to be tedious and overly time consuming, hence the desire to automate it.
What I am trying to do is create a temporary table that contains all columns that could potentially be matched on, and then run through a series of matching queries using the fields as join conditions to get our identifier to pass back.
For instance, the available matching fields are Name, NPI, MedicaidNum, and DOB so I would write something like:
UPDATE Temp
SET Temp.RECID = Phy.RECID
FROM TempTable Temp
INNER JOIN Physicians Phy
ON Phy.Name = Temp.Name
AND Phy.NPI = Temp.NPI
AND Phy.MedicaidNum = Temp.MedicaidNum
AND Phy.DOB = Temp.DOB
UPDATE Temp
SET Temp.RECID = Phy.RECID
FROM TempTable Temp
INNER JOIN Physicians Phy
ON Phy.Name = Temp.Name
AND Phy.NPI = Temp.NPI
AND Phy.MedicaidNum = Temp.MedicaidNum
WHERE Temp.RECID IS NULL
...etc
The problem lies in the fact that there about 15 different identifiers which could potentially be provided and clients usually only provide three or four per record set. So by the time null values are accounted for, there are potentially over a hundred different queries that need to be written to match on only half a dozen provided fields.
I am thinking that there may be a way to pass in a variable (or variables) which indicate which columns are actually provided with the data set, and then write a dynamic join statement and/or where clause, but I do not know if this will work in T-SQL. Something like:
DECLARE #Field1
DECLARE #Field2
....
UPDATE Temp
SET Temp.RECID = Phy.RECID
FROM TempTable Temp
INNER JOIN Physicians Phy
ON Phy.#Field1 = Temp.#Field1
AND Phy.#Field2 = Temp.#Field2
This way I would limit the number of queries I need to write, and only need to worry about the number of fields I am matching, rather then which specific ones. Perhaps there is a better approach to this problem however?
You can do something like this, but be warned this method is super prone to SQL injection. It's just to illustrate the principle of how to do something like this. I leave it up to you what you want to do with it. For this code, I made the proc take three fields:
CREATE PROC DynamicUpdateSQLFromFieldList #Field1 VARCHAR(50) = NULL,
#Field2 VARCHAR(50) = NULL,
#Field3 VARCHAR(50) = NULL,
#RunMe BIT = 0
AS
BEGIN
DECLARE #SQL AS VARCHAR(1000);
SELECT #SQL = 'UPDATE Temp
SET Temp.RECID = Phy.RECID
FROM TempTable Temp
INNER JOIN Physicians Phy ON ' +
COALESCE('Phy.' + #Field1 + ' = Temp.' + #Field1 + ' AND ', '') +
COALESCE('Phy.' + #Field2 + ' = Temp.' + #Field2 + ' AND ', '') +
COALESCE('Phy.' + #Field3 + ' = Temp.' + #Field3, '') + ';';
IF #RunMe = 0
SELECT #SQL AS SQL;
ELSE
EXEC(#SQL)
END
I've added a debug mode flag just so you can see the SQL if you don't want to run it. So, for example, if you run:
EXEC DynamicUpdateSQLFromFieldList #field1='col1', #field2='col2', #field3='col3'
or
EXEC DynamicUpdateSQLFromFieldList #field1='col1', #field2='col2', #field3='col3', #RunMe=0
the SQL produced will be:
UPDATE Temp
SET Temp.RECID = Phy.RECID
FROM TempTable Temp INNER JOIN Physicians Phy
ON Phy.col1 = Temp.col1 AND
Phy.col2 = Temp.col2 AND
Phy.col3 = Temp.col3;
If you run this line:
EXEC DynamicUpdateSQLFromFieldList #field1='col1', #field2='col2', #field3='col3', #RunMe=1
It will perform the update. If you wanted it to be more secure, you could whitelist the incoming field names against the sys tables to make sure the columns actually exist in each table before you execute any code.

MySql syntax question regarding CONCAT and strings

Environment is MySql 5.1.5.
This is a snippet from a larger stored procedure. Assume the variables are properly declared and set before this code is reached.
When I run the following loop, something seems to be failing in the CONCAT. #columnName and #xmlQuery are both VARCHARs. When I "SELECT #xmlQuery" at the end of the procedure, it is {null}.
If I simply replace:
SET #xmlQuery = CONCAT(#xmlQuery, #columnName);
with:
SET #xmlQuery = CONCAT(#xmlQuery, 'test');
then I get a nice string back like:
select xml_tag('result',null,null,concat(testtesttesttesttesttest
as one would expect.
WHY doesn't the CONCAT work with the local VARCHAR variable?
SET #xmlQuery = 'select xml_tag(''result'',null,null,concat(';
SET #columnCount = (SELECT COUNT(*) FROM ColumnNames);
WHILE (#rowIndex <= #columnCount) DO
SELECT #columnName = ColumnName FROM ColumnNames WHERE ID = #rowIndex;
SET #xmlQuery = CONCAT(#xmlQuery, #columnName);
SET #rowIndex = #rowIndex + 1;
END WHILE;
The problem turned out to be a conflict between the local variable #columnName and the column ColumnName in my temporary table.

Find Sybase stored procedure in db given a text string that appears in the proc

How do I find a stored procedure in a Sybase database given a text string that appears somewhere in the proc? I want to see if any other proc in the db has similar logic to the one I'm looking at, and I think I have a pretty unique search string (literal)
Edit:
I'm using Sybase version 11.2
Two variations on Graeme's answer (So this also won't work on 11.2):
This lists the name of the sproc too, but will return multiple rows for each sproc if the text appears several times:
select object_name(id),* from syscomments
where texttype = 0 and text like '%whatever%'
This lists each sproc just once:
select distinct object_name(id) from syscomments
where texttype = 0 and text like '%whatever%'
In SQL Anywhere and Sybase IQ:
select * from SYS.SYSPROCEDURE where proc_defn like '%whatever%'
I'm not that familiar with ASE, but according to the docs (available from sybooks.sybase.com), it's something like:
select * from syscomments where texttype = 0 and text like '%whatever%'
Please remember, that text column in syscomments is varchar(255), so one big procedure can consist of many lines in syscomments, thus, the above selects will not find the procedure name if it has been splitted into 2 text rows in syscomments.
I suggest the following select, which will handle the above case:
declare #text varchar(100)
select #text = "%whatever%"
select distinct o.name object
from sysobjects o,
syscomments c
where o.id=c.id
and o.type='P'
and (c.text like #text
or exists(
select 1 from syscomments c2
where c.id=c2.id
and c.colid+1=c2.colid
and right(c.text,100)+ substring(c2.text, 1, 100) like #text
)
)
order by 1
-- kudos for this go to the creator of ASEisql
select * from sysobjects where
id in ( select distinct (id) from syscomments where text like '%SearchTerm%')
and xtype = 'P'
select distinct object_name(syscomments.id) 'SearchText', syscomments.id from syscomments ,sysobjects
where texttype = 0 and text like '%SearchText%' and syscomments.id=sysobjects.id and sysobjects.type='P'
Multiple rows are used to store text for database objects the value might be accross two rows. So the more accurate answer is:
select distinct object_name(sc1.id)
from syscomments sc1
left join syscomments sc2
on (sc2.id = sc1.id and
sc2.number = sc1.number and
sc2.colid2 = sc1.colid2 + ((sc1.colid + 1) / 32768) and
sc2.colid = (sc1.colid + 1) % 32768)
where
sc1.texttype = 0 and
sc2.texttype = 0 and
lower(sc1.text + sc2.text) like lower('%' || #textSearched || '%')

Resources