oracle xmlexists with variable path - sql

I have a table tsk with 2 columns : a task id in number, and a task scope in XMLTYPE which can be like :
<scope>
<siteCode>2</siteCode>
<supplierCode>1111</supplierCode>
<contractCode>464</contractCode>
<orderNumber>85235478</orderNumber>
</scope>
But the elements under the tag may vary from one record to another
I need to select task ids which match some conditions in the scope.
For example :
select tskid
from tsk t
where xmlexists('$a/scope[siteCode = 2 and supplierCode = 111]' passing t.tskscope as "a");
As the scope may vary, I have a PL/SQL function taking a xml path p_xmlpath to look for, in varchar2 type.
So for example, p_xmlpath will be :
p_xmlpath := 'scope[siteCode = 2 and supplierCode = 1111]';
Then I want to run the query with XMLEXISTS to find the matching records.
I thought to do it with bind variables in the following way :
select tskid
from tsk t
where xmlexists('$a/$b' passing t.tskscope as "a", p_xmlpath as "b" );
By doing this, the query returns all records, without taking the condition with xmlexists.
Does someone know how to manage this, i.e. having a variable path to give to XMLEXISTS ?
Additional info : until now, I used the function existsNode and the following query was doing the job correctly:
select tskid
from tsk t
where existsnode(t.tskscope, p_xmlpath) = 1;
But on one hand existsNode is deprecated and on the other I noticed that in my situation the function xmlexists was noticeably faster than existsNode, that's why I would to switch to xmlexists.
Thanks in advance.

I don't think you can; it seems to only allow the search values to be variables, not the whole search condition.
As a workaround you could build the XPath at runtome with replace():
select tskid
from tsk t
where xmlexists(replace('$a/$b', '$b', p_xmlpath) passing t.tskscope as "a");
or build the XPath string as a variable if you'd rather not have a replace in there, and include the $a/ part:
p_xmlpath := '$a/' || p_xmlpath;
select tskid
from tsk t
where xmlexists(p_xmlpath passing t.tskscope as "a");

Related

Execute SQL Task in SSIS string parameter

I created two string variables (tot and tot_value) and assigned a value (tot = MyVal) for testing. Then I created an Execute SQL Task which takes (tot) as parameter and the value returned is saved in tot_value.
In the General Tab, i set:
ResultSet to Single row. SQL Source Type to Direct input Query is listed below.
In Parameter Mapping I selected my tot variable with Input DirectionSQL_VARCHAR Data Type 1 as Parameter Name (Since i am using ODBC)Size set to default -1.
In Result SetResult Name to 1Variable Name to tot_value.
If in the query I hard code 'MyVal' i get the correct result, however when I use ? to use my variable as a parameter, I always get a 0 returned.
Note that my tot variable is set to MyVal
Any clue of what I might be missing? Thanks in advance
select TOP 1 CAST('' + ISNULL((SELECT distinct type_of_transfer_code
FROM SYSTEM.history_program_transfer
WHERE type_of_transfer_value = ?),'') AS VARCHAR(100)) as type_of_transfer_code
FROM SYSTEM.table_facility_defaults

Oracle 10.2.0.4.0 query on partial xpath

I need to change the below query to be able to query any kind of tender item.
/Basket/CardTenderItem/Description
/Basket/CashTenderItem/Description
So
/Basket/WildcardTenderItem/Description
I have looked at various examples on but cannot them to bring back any results when running (happily admit to user error if can get working!)
SELECT
RETURN_ID
,SALE_ID,
,extractValue(xmltype(RETURNxml),'/Basket/CashTenderItem/NetValue')
,extractValue(xmltype(RETURNxml),'/Basket/CashTenderItem/Description')
FROM SPR361
WHERE return_id = '9999.0303|20170327224954|2063'
If you only want to match anything the ends with TenderItem, but doesn't have anything after that, you could be specific with substring checks:
SELECT
RETURN_ID
,SALE_ID
,extractValue(xmltype(RETURNxml),
'/Basket/*[substring(name(), string-length(name()) - 9) = "TenderItem"]/NetValue')
,extractValue(xmltype(RETURNxml),
'/Basket/*[substring(name(), string-length(name()) - 9) = "TenderItem"]/Description')
FROM SPR361
WHERE return_id = '9999.0303|20170327224954|2063'
If you never have any nodes with anything after that fixed string then #Shnugo's contains approach is easier, and in Oracle would be very similar:
...
,extractValue(xmltype(RETURNxml),
'/Basket/*[contains(name(), "TenderItem")]/NetValue')
,extractValue(xmltype(RETURNxml),
'/Basket/*[contains(name(), "TenderItem")]/Description')
I'm not sure there's any real difference between name() and local-name() here.
If a basket can have multiple child nodes (card and cash, or more than one of each) you could also switch to XMLTable syntax:
SELECT
s.RETURN_ID
,s.SALE_ID
,x.netvalue
,x.description
FROM SPR361 s
CROSS JOIN XMLTable(
'/Basket/*[contains(name(), "TenderItem")]'
PASSING XMLType(s.RETURNxml)
COLUMNS netvalue NUMBER PATH './NetValue'
, description VARCHAR(80) PATh './Description'
) x
WHERE s.return_id = '9999.0303|20170327224954|2063'
And it's overkill here maybe, but for more complicated tests you can use other XPath syntax, like:
CROSS JOIN XMLTable(
'for $i in /Basket/*
where contains($i/name(), "TenderItem") return $i'
PASSING XMLType(s.RETURNxml)
...
This is SQL-Server syntax and I cannot test, if this works with Oracle too, but I think it will. You can use XQuery function contains():
DECLARE #xml XML=
N'<root>
<abcTenderItem>test1</abcTenderItem>
<SomeOther>should not show up</SomeOther>
<xyzTenderItem>test2</xyzTenderItem>
</root>';
SELECT #xml.query(N'/root/*[contains(local-name(),"TenderItem")]')
only the elements with "TenderItem" in their names show up:
<abcTenderItem>test1</abcTenderItem>
<xyzTenderItem>test2</xyzTenderItem>

How to write Select query for selecting particular xml nodes in DB2 which occur multiple times?

I have a XML structure as below:
<root>
<firstChild>
<a>
<a1>someText</a1>
<a2>someNumber</a2>
<a>
<a>
<a1>someText1</a1>
<a2>someNumber1</a2>
<a>
<a>
<a1>someText2</a1>
<a2>someNumber2</a2>
<a>
<a>
<a1>someText3</a1>
<a2>someNumber3</a2>
<a>
</firstChild>
</root>
I want to write a DB2 SQL which will return all application id which have a1 as someText1 and a2 as someNumber1.
For more information I have a table say APPLICATION which has application_xml as column. This column has all the xml documents as shown above and are stored against each application id.
Can someone please suggest.
I have tried below query but it did not succeed.
select XMLQUERY('copy $new := $application_xml
for $i in $new/root/firstChild/a[a1 = "someText1"], $new/root/firstChild/a[a2 = "someNumber1"]
return $new') from application
Based on your description I assume that the table has two columns application id (aid) and application_xml. As you want to return the application id the base structure of the query is
select aid from application
Now we need the condition of which rows qualify. You state that in the related XML document the elements a1 and a2 need to have a certain value. The function xmlexists is the one to use in the WHERE clause of SQL:
select aid from application
where xmlexists('$d/root/firstChild/a[a1 = "someText1" and a2 = "someNumber1"]' passing application_xml as "d")
The XMLEXISTS is used as filtering predicate. The "passing" clause tells DB2 to expect "application_xml" under the name "d" inside the XPath/XQuery expression. The XPath expression itself is looking for the path /root/firstChild/a and under a specific "a" both the condition for "a1" and "a2" need to be true. If you want a broader condition, there would be also ways to express that.

Apex parse error when creating SQL query with sql function

I have the following function:
CREATE OR REPLACE FUNCTION calc_a(BIDoctor number) RETURN number
IS
num_a number;
BEGIN
select count(NAppoint)
into num_a
from Appointment a
where BIDoctor = a.BIDoctor;
RETURN num_a;
END calc_a;
What we want is adding a column to a report that shows us the number of appointments that doc have.
select a.BIdoctor "NUM_ALUNO",
a.NameP "Nome",
a.Address "Local",
a.Salary "salary",
a.Phone "phone",
a.NumberService "Curso",
c.BIdoctor "bi",
calc_media(a.BIdoctor) "consultas"
FROM "#OWNER#"."v_Doctor" a, "#OWNER#"."Appointment" c
WHERE a.BIdoctor = c.BIdoctor;
and we got this when we are writing the region source on apex.
But it shows a parse error, I was looking for this about 2 hours and nothing.
Apex shows me this:
PARSE ERROR ON THE FOLLOWING QUERY
This is probably because of all your double quotes, you seem to have randomly cased everything. Double quotes indicate that you're using quoted identifiers, i.e. the object/column must be created with that exact name - "Hi" is not the same as "hi". Judging by your function get rid of all the double quotes - you don't seem to need them.
More generally don't use quoted identifiers. Ever. They cause far more trouble then they're worth. You'll know when you want to use them in the future, if it ever becomes necessary.
There are a few more problems with your SELECT statement.
You're using implicit joins. Explicit joins were added in SQL-92; it's time to start using them - for your future career where you might interact with other RDBMS if nothing else.
There's absolutely no need for your function; you can use the analytic function, COUNT() instead.
Your aliases are a bit wonky - why does a refer to doctors and c to appointments?
Putting all of this together you get:
select d.bidoctor as num_aluno
, d.namep as nome
, d.address as local
, d.salary as salary
, d.phone as phone
, d.numberservice as curso
, a.bidoctor as bi
, count(nappoint) over (partition by a.bidoctor) as consultas
from #owner#.v_doctor a
join #owner#.appointment c
on d.bidoctor = a.bidoctor;
I'm guessing at what the primary keys of APPOINTMENT and V_DOCTOR are but I'm hoping they're NAPPOINT and BIDOCTOR respectively.
Incidentally, your function will never have returned the correct result because you haven't limited the scope of the parameter in your query; you would have just counted the number of records in APPOINTMENT. When you're naming parameters the same as columns in a table you have to explicitly limit the scope to the parameter in any queries you write, for instance:
select count(nappoint) into num_a
from appointment a
where calc_a.bidoctor = a.bidoctor; -- HERE

How to query with string variable in rails 3.2.12?

We would like to store both rails query string and table name in db and retrieve them for execution at run time. Here is the scenario:
Retrieve active customer records from customers table. Let's say we have 2 variable defined as:
table_name = 'Customer'
query_string = ':active => true'
In rails, the query could be:
records = Customer.where(:active => true)
Now with table name and query string stored in variables table_name and query_string, is it possible to assemble a query string with 2 variables like:
records = table_name.where(query_string) ?
Thanks for the help.
You could do this, but it's not generally recommended to evaluate a string as a hash. Also, table_name is an unfortunate name for the variable, because you actually are storing the class name (table would be 'customers'). In any event, what you are missing is the eval of these strings:
records = class_name.constantize.where(instance_eval(query_string))
Note that running instance_eval on a user-inputted string can be disasterous for security and the well-being of your application. Use with care, and stick to building an actual hash.
The definition of instance_eval is: Evaluates a string containing Ruby source code, or the given block, within the context of the receiver (obj).
Another way to eval a query string is to include where in the string, like:
table_name = 'Customer'
query_string = 'where(:active => true)'
Then the record could be retrieved by:
records = table_name.constantize.instance_eval(query_string)
By putting where into the string, we can use the full power of instance_eval instead of just returning the source code to where as in the question above.