PL/SQL and SQL Developer different results from each other - sql

I am executing a query in PL / SQL in version 7 and version 14, with a function created by me, and both bring me some results, the rest bring 0.
However, when executing the same query in Oracle SQL Developer, the query brings all the results correctly.
I executed the procedure through PL / SQL and Oracle SQL Developer as well, but then none brought me the right result, all the lines were left as "0".
I can't find the problem at all, even on Google.
Basically, the function multiplies the number of rows by columns that start with "ID_", as shown below.
Function:
CREATE OR REPLACE FUNCTION DS_FUNCESP.FNBIGB_CheckDataCells
(pOwn IN VARCHAR2,
pTab IN VARCHAR2)
RETURN NUMBER
IS
v_Qtd NUMBER;
v_str VARCHAR2(2000);
BEGIN
v_Qtd := 1;
v_str := ' SELECT
SUM((SELECT COUNT(1) AS QTY_ROWS FROM ' || pOwn || '.' || pTab || ' d WHERE d.LINORIGEM <> ''CARGA MANUAL'')) AS QTY_DATA
FROM DW_FUNCESP.D_BI_COLUMNS a
LEFT JOIN
DW_FUNCESP.D_BI_TABLES b
ON a.ID_TABLE = b.ID_TABLE
AND a.ID_OWNER = b.ID_OWNER
LEFT JOIN DW_FUNCESP.D_BI_OWNERS c
ON a.ID_OWNER = c.ID_OWNER
WHERE b.NM_TABLE = ''' || pTab || '''
AND a.IN_PRIMARYKEY = ''NAO''
AND SUBSTR(a.NM_COLUMN,1,3) = ''ID_'' ';
DBMS_OUTPUT.put_line(v_str);
EXECUTE IMMEDIATE v_str into v_Qtd ;
return (v_Qtd);
EXCEPTION WHEN OTHERS THEN
RETURN 0;
END FNBIGB_CheckDataCells;
Select statement:
SELECT
c.NM_OWNER ,
b.NM_TABLE ,
DS_FUNCESP.FNBIGB_CHECKDATACELLS(c.NM_OWNER, b.NM_TABLE) AS QTY_DATA
FROM DW_FUNCESP.D_BI_TABLES b
LEFT JOIN DW_FUNCESP.D_BI_OWNERS c
ON b.ID_OWNER = c.ID_OWNER;
Results from PL/SQL:
Results from Oracle SQL Developer:
Clearly we can see the difference from any row, the right one is the Oracle SQL Developer. So I'd like to know what is the problem, how to fix, because the procedure is adding "0" to all the rows, no matter where I run.

Reading those examples from WHEN OTHERS - A Bug, thanks to #Lalit Kumar B for that, I changed:
EXCEPTION WHEN OTHERS THEN
RETURN 0;
To:
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('SQLCODE: '||SQLCODE);
DBMS_OUTPUT.PUT_LINE('Message: '||SQLERRM);
RAISE;
To find out the problem, and thanks for that I found that it was trying to count from a table where it doesn't exist anymore.
So I using an error handling as below, from #Jeffrey Kemp
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -942 THEN
RAISE;
END IF;
Also, thanks for #Belayer, my code was the problem, agreed on that. Also, executing on both softwares, made me even more confused. I'll read also that documentation for sure.

Related

Oracle SQL - table type in cursor causing ORA-21700: object does not exist or is marked for delete

I have problem with my function, I'm getting ORA-21700: object does not exist or is marked for delete error. It's caused by table type parameter in cursor, but I've no idea how to fix it.
I've read that table type part should be assigned to a variable, but it can't be done in cursor, right? I've marked the part which causing the issue
Can anyone help? Is there any other way I can do this?
My package looks something like this:
FUNCTION createCSV(DateFrom date
,DateTo date)
RETURN clob IS
CURSOR c_id (c_DateFrom date
,c_DateTo date) IS
SELECT id
FROM limits
WHERE utcDateFrom <= NVL(c_DateTo, utcDateFrom)
AND NVL(utcDateTo, c_DateFrom + 1) >= c_DateFrom + 1;
CURSOR c (c_DateFrom date
,c_DateTo date
,pc_tDatePeriods test_pkg.t_date_periods) IS -- this is table type (TYPE xx AS TABLE OF records)
SELECT l.id limit_id
,TO_CHAR(time_cond.utcDateFrom, og_domain.cm_yyyymmddhh24mi) time_stamp_from
,TO_CHAR(time_cond.utcDateTo, og_domain.cm_yyyymmddhh24mi) time_stamp_to
FROM limits l
JOIN (SELECT limit_id, utcDateFrom, utcDateTo FROM TABLE(pc_tDatePeriods) --This part is causing the issue
) time_cond
ON l.id = time_cond.limit_id
WHERE l.utcDateFrom <= NVL(c_DateTo, l.utcDateFrom)
AND NVL(l.utcDateTo, c_DateFrom + 1) >= c_DateFrom + 1;
CSV clob;
tDatePeriods test_pkg.t_date_periods := test_pkg.t_date_periods();
BEGIN
FOR r_id IN c_id(DateFrom, DateTo)
LOOP
tDatePeriods := test_pkg.includeTimeGaps(p_Id => r_id.id); --this loop is ok
FOR r IN c(DateFrom, DateTo, tDatePeriods) --here I'm getting error
LOOP
CSV := CSV || chr(13) || r.limit_id || ',' || r.time_stamp_from || ',' || r.time_stamp_to;
END LOOP;
END LOOP;
RETURN CSV;
END createCSV;
Your problem should be solved by declaring type test_pkg.t_date_periods on schema level instead of in package.
Similar answer can be found here but with more details.

Oracle APEX 4.2 Custom search in classic report

I am using Oracle APEX 4.2. I want to implement a search function in my classic report. I have a working code that retrieve data and the search function works perfectly. But when I want to use an order by clause inside that code I get "no data found" how can I implement an order by clause into this code so my report will be sorted correctly and the search function will still work correctly.
Here is the working code below that allows you to search the classic report:
declare
a_query varchar2(5000);
this_strin varchar2(50);
begin
a_query := 'select flight_nmbr, sequence_nmbr'||
'from flights '||
'where sequence_nmbr >= 0'||
'and data_version_name = '''||
:P3_DATA_VERSION || '''';
if :P3_SEARCH_NUMBER is not null then
if instr(:P3_SEARCH_NUMBER, '%') > 0 then
this_strin := :P3_SEARCH_NUMBER;
else
this_strin := '%'||:P3_SEARCH_NUMBER||'%';
end if;
a_query := a_query||chr(10)||
' and flight_nmbr like '''|| upper(this_strin) ||'''';
end if;
return a_query;
end;
Here is same piece of code that does says "no data found" when I add the order by clause to the query:
declare
a_query varchar2(5000);
this_strin varchar2(50);
begin
a_query := 'select flight_nmbr, sequence_nmbr'||
'from flights '||
'where sequence_nmbr >= 0'||
'and data_version_name = '''||
'order by sequence_nmbr 1'|| ------------------Order by clause
:P3_DATA_VERSION || '''';
if :P3_SEARCH_NUMBER is not null then
if instr(:P3_SEARCH_NUMBER, '%') > 0 then
this_strin := :P3_SEARCH_NUMBER;
else
this_strin := '%'||:P3_SEARCH_NUMBER||'%';
end if;
a_query := a_query||chr(10)||
' and flight_nmbr like '''|| upper(this_strin) ||'''';
end if;
return a_query;
end;
Obviously, your problem is here:
begin
a_query := 'select flight_nmbr, sequence_nmbr'||
'from flights '||
'where sequence_nmbr >= 0'||
'and data_version_name = '''|| -- double qoute!!!
'order by sequence_nmbr 1'|| ------------------Order by clause
:P3_DATA_VERSION || '''';
Due to that redundant double quote, your resulting query looks like this:
select flight_nmbr, sequence_nmbr
from flights
where sequence_nmbr >= 0
and data_version_name = 'order by sequence_nmbr 1<value of P3_DATA_VERSION item>';
As soon as the table has no value order by sequence_nmbr 1 in the column data_version_name, the query returns no rows.
The second problem you will encounter when you'll fix this one is here:
if :P3_SEARCH_NUMBER is not null then
When this statement will be true, you will get a query where the condition and flight_nmbr like ... stands after the ORDER BY clause.
By the way, I would recommend you write a simple query for the report. Generating SQL dynamically leads to such errors and costs you a performance decrease also.
Not related to your question, but - why don't you switch to interactive report? It offers much more than a classic report, don't you think?
As of your problem: if you look at query that fails, its SELECT looks like this (I've removed single quotes):
and data_version_name = ||
order by sequence_nmbr 1 || ------------------Order by clause
:P3_DATA_VERSION ||
and flight_nmbr like upper(this_strin)
Either you didn't post actual code, or this is generally wrong - I hope you see what is wrong here. ORDER BY should be the last clause. Besides, what's that "1" doing at the end of the ORDER BY?
I'd suggest you to first display contents of the A_QUERY, check whether it works OK (in SQL*Plus, TOAD, SQL Developer or any other tool you use), and - once you're satisfied with it - let it work in Apex.

Oracle : String Concatenation is too long

I have below SQL as a part of a view. In one of the schema I am getting "String Concatenation is too long" error and not able to execute the view.
Hence I tried the TO_CLOB() and now VIEW is not throwing ERROR, but it not returning the result as well it keep on running..
Please suggest....
Sql:
SELECT Iav.Item_Id Attr_Item_Id,
LISTAGG(La.Attribute_Name
||'|~|'
|| Lav.Attribute_Value
||' '
|| Lau.Attribute_Uom, '}~}') WITHIN GROUP (
ORDER BY ICA.DISP_SEQ,LA.ATTRIBUTE_NAME) AS ATTR
FROM Item_Attribute_Values Iav,
Loc_Attribute_Values Lav,
Loc_Attribute_Uoms Lau,
Loc_Attributes La,
(SELECT *
FROM Item_Classification Ic,
CATEGORY_ATTRIBUTES CA
WHERE IC.DEFAULT_CATEGORY='Y'
AND IC.TAXONOMY_TREE_ID =CA.TAXONOMY_TREE_ID
) ICA
WHERE IAV.ITEM_ID =ICA.ITEM_ID(+)
AND IAV.ATTRIBUTE_ID =ICA.ATTRIBUTE_ID(+)
AND Iav.Loc_Attribute_Id =La.Loc_Attribute_Id
AND La.Locale_Id =1
AND Iav.Loc_Attribute_Uom_Id =Lau.Loc_Attribute_Uom_Id(+)
AND Iav.Loc_Attribute_Value_Id=Lav.Loc_Attribute_Value_Id
GROUP BY Iav.Item_Id;
Error:
ORA-01489: result of string concatenation is too long
01489. 00000 - "result of string concatenation is too long"
*Cause: String concatenation result is more than the maximum size.
*Action: Make sure that the result is less than the maximum size.
You can use the COLLECT() function to aggregate the strings into a collection and then use a User-Defined function to concatenate the strings:
Oracle Setup:
CREATE TYPE stringlist IS TABLE OF VARCHAR2(4000);
/
CREATE FUNCTION concat_List(
strings IN stringlist,
delim IN VARCHAR2 DEFAULT ','
) RETURN CLOB DETERMINISTIC
IS
value CLOB;
i PLS_INTEGER;
BEGIN
IF strings IS NULL THEN
RETURN NULL;
END IF;
value := EMPTY_CLOB();
IF strings IS NOT EMPTY THEN
i := strings.FIRST;
LOOP
IF i > strings.FIRST AND delim IS NOT NULL THEN
value := value || delim;
END IF;
value := value || strings(i);
EXIT WHEN i = strings.LAST;
i := strings.NEXT(i);
END LOOP;
END IF;
RETURN value;
END;
/
Query:
SELECT Iav.Item_Id AS Attr_Item_Id,
CONCAT_LIST(
CAST(
COLLECT(
La.Attribute_Name || '|~|' || Lav.Attribute_Value ||' '|| Lau.Attribute_Uom
ORDER BY ICA.DISP_SEQ,LA.ATTRIBUTE_NAME
)
AS stringlist
),
'}~}'
) AS ATTR
FROM your_table
GROUP BY iav.item_id;
LISTAGG is limited to 4000 characters unfortunately. So you may want to use another approach to concatenate the values.
Anyway ...
It is strange to see LISTAGG which is a rather new feature combined with error-prone SQL1992 joins. I'd suggest you re-write this. Are the tables even properly joined? It looks strange that there seems to be no relation between Loc_Attributes and, say, Loc_Attribute_Values. Doesn't have Loc_Attribute_Values a Loc_Attribute_Id so an attribute value relates to an attribute? It would be hard to believe that there is no such relation.
Moreover: Is it guaranteed that your classification subquery doesn't return more than one record per attribute?
Here is your query re-written:
select
iav.item_id as attr_item_id,
listagg(la.attribute_name || '|~|' || lav.attribute_value || ' ' || lau.attribute_uom,
'}~}') within group (order by ica.disp_seq, la.attribute_name) as attr
from item_attribute_values iav
join loc_attribute_values lav
on lav.loc_attribute_value_id = iav.loc_attribute_value_id
and lav.loc_attribute_id = iav.loc_attribute_id -- <== maybe?
join loc_attributes la
on la.loc_attribute_id = lav.loc_attribute_id
and la.loc_attribute_id = lav.loc_attribute_id -- <== maybe?
and la.locale_id = 1
left join loc_attribute_uoms lau
on lau.loc_attribute_uom_id = iav.loc_attribute_uom_id
and lau.loc_attribute_id = iav.loc_attribute_id -- <== maybe?
left join
(
-- aggregation needed to get no more than one sortkey per item attribute?
select ic.item_id, ca.attribute_id, min (ca.disp_seq) as disp_seq
from item_classification ic
join category_attributes ca on ca.taxonomy_tree_id = ic.taxonomy_tree_id
where ic.default_category = 'y'
group by ic.item_id, ca.attribute_id
) ica on ica.item_id = iav.item_id and ica.attribute_id = iav.attribute_id
group by iav.item_id;
Well, you get the idea; check your keys and alter your join criteria where necessary. Maybe this gets rid of duplicates, so LISTAGG has to concatenate less attributes, and maybe the result even stays within 4000 characters.
Xquery approach.
Creating extra types or function isn't necessary.
with test_tab
as (select object_name
from all_objects
where rownum < 1000)
, aggregate_to_xml as (select xmlagg(xmlelement(val, object_name)) xmls from test_tab)
select xmlcast(xmlquery('for $row at $idx in ./*/text() return if($idx=1) then $row else concat(",",$row)'
passing aggregate_to_xml.xmls returning content) as Clob) as list_in_lob
from aggregate_to_xml;
I guess you need to write a small function to concatenate the strings into a CLOB, because even when you cast TO_CLOB() the LISTAGG at the end, this might not work.
HereĀ“s a sample-function that takes a SELECT-Statement (which MUST return only one string-column!) and a separator and returns the collected values as a CLOB:
CREATE OR REPLACE FUNCTION listAggCLob(p_stringSelect VARCHAR2
, p_separator VARCHAR2)
RETURN CLOB
AS
cur SYS_REFCURSOR;
s VARCHAR2(4000);
c CLOB;
i INTEGER;
BEGIN
dbms_lob.createtemporary(c, FALSE);
IF (p_stringSelect IS NOT NULL) THEN
OPEN cur FOR p_stringSelect;
LOOP
FETCH cur INTO s;
EXIT WHEN cur%NOTFOUND;
dbms_lob.append(c, s || p_separator);
END LOOP;
END IF;
i := length(c);
IF (i > 0) THEN
RETURN dbms_lob.substr(c,i-length(p_separator));
ELSE
RETURN NULL;
END IF;
END;
This function can be used f.e. like this:
WITH cat AS (
SELECT DISTINCT t1.category
FROM lookup t1
)
SELECT cat.category
, listAggCLob('select t2.name from lookup t2 where t2.category = ''' || cat.category || '''', '|') allcategorynames
FROM cat;

Searching in the source of a particular schema(PL/SQL)

In the source code if I want to find out something, say where a particular column is getting updated. I am using the below query to find where the column(BUCKET) of table(LEA_AGREEMENT_DTL)is getting updated.
select * from user_source where upper(text) like '%UPDATE%LEA_AGREEMENT_DTL%BUCKET%';
Now if the source in that paticular schem is written as below my query will tell me in which procedure the code is written :
Update Lea_agreement_dtl Set Dpd = No_Days_OverDuE, bucket=V_bucket
where ProposalID = T_ProposalID;
But if the code is written as below my query will not give any result :
Update Lea_agreement_dtl
Set Dpd = No_Days_OverDuE,
bucket=V_bucket
where ProposalID = T_ProposalID;
My question is how should I modify my query to search in the source code of a particular schema/user so that I get successful result in both the cases. Basically I want to find all the procedure's/objects where this column is getting updated in that particular schema.
As per my analysis if the whole query is written in one line then i am able to search it otherwise it doesn't work.
You can use this view.
CREATE OR REPLACE VIEW V_UPDATE_USER_SOURCE AS
SELECT TYPE,
NAME,
line,
LISTAGG(regexp_replace(text,'[[:space:]]',' '), ' ') WITHIN GROUP(ORDER BY norder) text
FROM (SELECT a.TYPE,
a.NAME,
a.line,
b.text,
b.line norder
FROM (SELECT line,
TYPE,
NAME,
text
FROM user_source
WHERE regexp_like(text, '[[:space:]]update[[:space:]]', 'i')) a,
user_source b
WHERE a.type = b.TYPE
AND a.name = b.name
AND b.line BETWEEN a.line AND (SELECT MIN(g.line)
FROM user_source g
WHERE regexp_like(g.TEXT, ';', 'i')
AND g.TYPE = a.TYPE
AND g.NAME = a.name
AND g.line >= a.line)
ORDER BY b.TYPE,
b.NAME,
b.line) c
GROUP BY TYPE,
NAME,
line
LISTAGG working on Oracle 11g or higher.
If you using previous version Oracle, you need this view
CREATE OR REPLACE VIEW V_UPDATE_USER_SOURCE AS
SELECT TYPE,
NAME,
line,
XMLAGG(XMLELEMENT(E, regexp_replace(text, '[[:space:]]', ' ') || ' ')).EXTRACT('//text()') text
FROM (SELECT a.TYPE,
a.NAME,
a.line,
b.text,
b.line norder
FROM (SELECT line,
TYPE,
NAME,
text
FROM user_source
WHERE regexp_like(text, '[[:space:]]update[[:space:]]', 'i')) a,
user_source b
WHERE a.type = b.TYPE
AND a.name = b.name
AND b.line BETWEEN a.line AND (SELECT MIN(g.line)
FROM user_source g
WHERE regexp_like(g.TEXT, ';', 'i')
AND g.TYPE = a.TYPE
AND g.NAME = a.name
AND g.line >= a.line)
ORDER BY b.TYPE,
b.NAME,
b.line)
GROUP BY TYPE,
NAME,
line;
It returns the data set, which contains all the update is in line with a number, in which the update started.
View can be used with regexp_like:
select * from V_UPDATE_USER_SOURCE t where regexp_like(text,'clients.*STATE','i')
Description:
clients - table.
STATE - column for update.
There are 3 main approaches to this problem:
Hack something together with string functions and regular expressions. This is the most common solution but is also full of holes. Those holes may not matter depending on why you're searching for the code. This is good enough for finding where to start coding but is probably not sufficient for proving to someone that the code is covered.
Tokenize the input and loop through the tokens looking for a pattern. A lexer can take care of some problems that are not easily handled by single regular expressions, like comments and the alternative quoting syntax. With a good understanding of Oracle syntax it's possible to build a highly-accurate solution. It would still miss extremely broken code (for example, it's possible to create code with UPDATE as a variable), dynamic SQL, and recursive references through synonyms and views.
Parse the input and walk an abstract syntax tree looking for a pattern. This would be a nice 100%-accurate solution. Unfortunately there are no high-quality PL/SQL parsers available in PL/SQL.
The solution below uses an open-source PL/SQL lexer I created to solve problems like this.
Sample Procedure
The string pattern, UPDATE-LEA_AGREEMENT_DTL-BUCKET, occurs three times below. But only the first UPDATE on line 4 really satisfies the conditions. (The third update may look weird in the Stackoverflow syntax highlighting, but in real PL/SQL that second quotation mark does not close the string.)
create or replace procedure search_test is
begin
--Real match.
Update Lea_agreement_dtl Set Dpd = No_Days_OverDuE,
bucket=V_bucket
where ProposalID = T_ProposalID;
--Exclude - ignore comments.
/*Update Lea_agreement_dtl Set Dpd = No_Days_OverDuE, bucket=V_bucket
where ProposalID = T_ProposalID;*/
--Exclude - watch out for alternative quoting syntax.
Update Lea_agreement_dtl Set Dpd = q'[No_Days_OverDuE', bucket=V_bucket ]'
where ProposalID = T_ProposalID;
end;
/
Anonymous Block to Find the Lines
--Find lines that update LEA_AGREEMENT_DTL.BUCKET.
--Does not search dynamic SQL and does not recurse through view or synonyms.
declare
v_tokens token_table;
v_update_line_number number;
v_has_update boolean := false;
v_has_table boolean := false;
v_has_column boolean := false;
begin
--Get source and tokenize it.
v_tokens := tokenizer.tokenize(dbms_metadata.get_ddl('PROCEDURE', 'SEARCH_TEST'));
--Loop through tokens and look for UPDATE/LEA_AGREEMENT_DTL/BUCKET between semicolons.
for i in 1 .. v_tokens.count loop
--Reset if a semicolon is found.
if v_tokens(i).value = ';' then
v_has_update := false;
v_has_table := false;
v_has_column := false;
--Look for relevant tokens, in order.
elsif upper(v_tokens(i).value) = 'UPDATE' then
v_update_line_number := v_tokens(i).line_number;
v_has_update := true;
elsif v_has_update and upper(v_tokens(i).value) = 'LEA_AGREEMENT_DTL' then
v_has_table := true;
elsif v_has_table and upper(v_tokens(i).value) = 'BUCKET' then
v_has_column := true;
end if;
--Success if all conditions are met.
if v_has_update and v_has_table and v_has_column then
--Subtract 1 because DBMS_METADATA put a blank line at the beginning.
dbms_output.put_line('Found on line '||to_char(v_update_line_number-1));
v_has_update := false;
v_has_table := false;
v_has_column := false;
end if;
end loop;
end;
/
Results
Found on line 4

SQL Query fails on empty result

I have a function that performs a query on a SQL database with an ADO connection, it is simply designed to provide a single result for a database entry that can only have one match for a SELECT type of query (i.e. get me the x value from ID 45, where there is and can only be one ID 45 entry).
The function works fine, until I hit a query that returns no results. The query just hangs, and the application cannot continue. Here is an example query string:
'SELECT Cost FROM MaterialCost ' +
'WHERE MaterialType = ''' + 'MS' +
''' AND Thickness = ''' + '0.250' + '''';
Again this exact string will work fine until I maybe query for something that I know before hand doesn't exist, which should return null or an empty string. Here is the function:
function SelectOneQuery(AQueryString : String; AADOConnectionString : String) : String;
var
ADOQuery: TADOQuery;
begin
//Create empty ADO Query, then connect to connection string
ADOQuery := TADOQuery.Create(nil);
ADOQuery.ConnectionString:=AADOConnectionString;
ADOQuery.SQL.Clear;
ADOQuery.SQL.Add(AQueryString);
ADOQuery.ExecSQL;
ADOQuery.Open;
//Set first query result and return first result
ADOQuery.First;
if(ADOQuery.Fields.Count > 0) then begin
result:=ADOQuery.Fields[0].Value;
end
else begin
result := '';
end;
end;
I added the fields count thing, but I'm not sure if that's helping at all. Basically, if there are no result, i want result := ''
You have a few problems in your code snippet:
The main problem is that you are checking FieldCount. FieldCount will always be nonzero because it contains the number of columns your query returns, regardless of the fact your query returned records or not. One option is to check RecordCount which represents the number of rows returned but a better option is to check EOF flag.
you are leaking ADOQuery. Always use try/finally blocks to create and cleanup objects.
ExecSQL is used for queries that don't return recordsets (like INSERT and DELETE),
use Open instead
No need to use First after Open
If you use the same query over and over you are better off using parameters, as a bonus your code will be more readable.
Example:
ADOQuery.SQL.Text := 'SELECT Cost FROM MaterialCost WHERE MaterialType = :MaterialType AND Thickness = :Thickness';
ADOQuery.Parameters.ParamByname('MaterialType').Value := 'MS';
ADOQuery.Parameters.ParamByname('Thickness').Value := 0.25;
Your function code should be something like this:
function SelectOneQuery(const AQueryString, AADOConnectionString: string): string;
var
ADOQuery: TADOQuery;
begin
Result := '';
ADOQuery := TADOQuery.Create(nil);
try
ADOQuery.ConnectionString := AADOConnectionString;
ADOQuery.SQL.Text := AQueryString;
ADOQuery.Open;
if not ADOQuery.EOF then
Result := ADOQuery.Fields[0].AsString;
finally
ADOQuery.Free;
end;
end;