I am trying to convert the following code to xquery so that the results remain the same. I am trying to calculate the total freight costs for each customer
SELECT
c.CompanyName, SUM(o.freight) AS [Total Freight Costs]
FROM
Customers c, Orders o
WHERE
c.CustomerID = o.CustomerID
GROUP BY
CompanyName
The test data for the customers.xml and orders are as follows
<dataroot>
<Customers>
<CustomerID>ALFKI</CustomerID>
<CompanyName>Alfreds Futterkiste</CompanyName>
<ContactName>Maria Anders</ContactName>
<ContactTitle>Sales Representative</ContactTitle>
<Address>Obere Str. 57</Address>
<City>Berlin</City>
<PostalCode>12209</PostalCode>
<Country>Germany</Country>
<Phone>030-0074321</Phone>
<Fax>030-0076545</Fax>
</Customers>
<Customers>
<CustomerID>ANATR</CustomerID>
<CompanyName>Ana Trujillo Emparedados y helados</CompanyName>
<ContactName>Ana Trujillo</ContactName>
<ContactTitle>Owner</ContactTitle>
<Address>Avda. de la Constitución 2222</Address>
<City>México D.F.</City>
<PostalCode>05021</PostalCode>
<Country>Mexico</Country>
<Phone>(5) 555-4729</Phone>
<Fax>(5) 555-3745</Fax>
</Customers>
</dataroot>
Orders.xml
<dataroot>
<Orders>
<OrderID>10248</OrderID>
<CustomerID>WILMK</CustomerID>
<EmployeeID>5</EmployeeID>
<OrderDate>1996-07-04T00:00:00</OrderDate>
<RequiredDate>1996-08-01T00:00:00</RequiredDate>
<ShippedDate>1996-07-16T00:00:00</ShippedDate>
<ShipVia>3</ShipVia>
<Freight>32.38</Freight>
<ShipName>Vins et alcools Chevalier</ShipName>
<ShipAddress>59 rue de l'Abbaye</ShipAddress>
<ShipCity>Reims</ShipCity>
<ShipPostalCode>51100</ShipPostalCode>
<ShipCountry>France</ShipCountry>
</Orders>
</dataroot>
This is what I have so far
for $o in doc("Orders.xml")/dataroot/Orders,
$c in doc("Customers.xml")/dataroot/Customers[CustomerID = $o/CustomerID]
return
<OrderDetails>
{
$c/CompanyName,
sum($o/Freight)
}
</OrderDetails>
Simple enough:
(: select only customers with at least one order :)
for $c in doc("Customers.xml")/dataroot/Customers
[doc("Orders.xml")/dataroot/Orders/CustomerID=./CustomerID]
(: get the list of orders for this customer :)
let $o := doc("Orders.xml")/dataroot/Orders[CustomerID = $c/CustomerID]
(: ...and properly encapsulate the calculated value in the result :)
return
<OrderDetails>
{$c/CompanyName}
<TotalFreight>{sum($o/Freight)}</TotalFreight>
</OrderDetails>
The test data you gave has no matching CustomerIDs, however, so it returns nothing for this query; I had to mock up my own. With that done, however, I get output akin to the following:
<OrderDetails>
<CompanyName>Alfreds Futterkiste</CompanyName>
<TotalFreight>45.58</TotalFreight>
</OrderDetails>
Actually, since XQuery 3.0 there is a standardized "group by" for FLWOR expressions.
Related
I have got this query:
SELECT Sites.Master_ID AS Master_ID, Scopes.Name AS Scope, Brands.Extension AS [Brand], Sites.ID AS [Site ID], Sites.Name AS [Site Name], Sites.Address, Sites.CAP, Sites.City, Countries.Name AS Country
From Sites
INNER Join Scopes ON Sites.scope_ID = Scopes.ID
INNER JOIN Brands ON Sites.brand_ID = Brands.ID
INNER Join Countries ON Sites.country_ID = Countries.ID
WHERE CONCAT (Scopes.Name, Brands.Extension, Sites.ID, Sites.Name, CONVERT(nvarchar(MAX),Sites.Address), Sites.CAP, Sites.City, Countries.Name) Like '%BA%'
That is producing the following result:
[
While if I remove a %, writing "Like 'BA%'" (instead of '%BA%') the SELECT is empty.
I really cannot understand the reason for that.
Thanks in advance for your help.
Regards,
The LIKE pattern matches the entire string.
So, '%BA%' looks for 'BA' anywhere in the string. But, 'BA%' looks only for strings that begin with 'BA'. And in your case, that probably means that scopes.name begins with 'BA'.
More recent versions of SQL Server support concat_ws() which allows you to do something like:
WHERE CONCAT_WS('|', '|', Scopes.Name, Brands.Extension, . . .) Like '%|BA%'
This would check that each column starts with 'BA'. It is something of a hack. It is probably better to be explicit:
WHERE Scopes.Name LIKE 'BA%' OR
Brands.Extension LIKE 'BA%' OR
. . .
Or perhaps:
WHERE 'BA' IN (LEFT(Scopes.Name, 2), LEFT(Brands.Extension, 2), . . .)
I have two table interest and subint, I want to get data related to every interest so I have tried inner join select interest,subinterest from interest inner join subint on subint.interest_id = interest.id; and the result is
"interest" "subinterest"
"foodie" "tea"
"foodie" "biryani"
"foodie" "chocolate"
"foodie" "cookies"
"foodie" "fast-food"
"cooking" "cooking"
Is there any way to format my output and make it like
"interest" "subinterest"
"foodie" "tea"
"biryani"
"chocolate"
"cookies"
"fast-food"
"cooking" "cooking"
is it possible through any SQL query? or I need to do it by coding.
I want this because I am creating an API using node and knex.js and I want the JSON to be well formatted
{
"interest": "foodie",
"subinterest": "coffee",
"subinterest": "tea",
"subinterest": "biryani"
}
Construct the JSON you want in Postgres. This gives you a JSON record per row, which is what I think you want:
select row_to_json(i)
from (select interest, array_agg(subinterest) as subinterests
from t
group by interest
) i;
Here is a db<>fiddle.
You should try and build an object or array structure like this:
arr=[{interest:"foodie",
subinterest:["tea","biryani","chocolate",
"cookies","fast-food"]},
{interest:"cooking",
subinterest:["cooking"]}];
outside SQL by using some serverside code like PHP, then transport it via a JSON string for "safe consumption" by your knex.js script.
(The above code depicts the resulting Javascript array, after JSON parsing.)
select rg.guardian_name,
rg.guardian_id,
rg.guardian_email
from rts_guardian rd, rts_ward rw, rts_wrdgrd_junction junct
where rg.guardian_id = junct.guardian_id and rw.ward_id=junct.ward_id and rw.garde='VIII';
You can begin by this simple example :
Query query = session.createQuery
("select stock_code, stock_name from backup_stock where id_stock= :id");
Here is how you can set parameters :
query.setParameter("id", "1");
And to get the result:
List list = query.list();
please search more before asking here. You can find many documentation on this subject so make an effort.
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>
I have a table of people which build from two columns the first one is id and the second one is XML which counties the person details.
For example the person XML file can be:
<Person>
<name>First Last</name>
<address>5 Champ de Mars</address>
<city>Paris</city>
<country>France</country>
<phone-number>+3312345</phone-number>
</Person>
I would like to know how I can extract the value of each one of the parameters in the XML using regexp_substr, I have tried to use the function EXTRACTVALUE which caused me too many problems.
I am ruining oracle.
For example if querying the XML I gave:
select regexp_substr(XML_file, 'pattern name') from peoples where id = 1;
will result in: First Last.
Thank you in advance
Yonatan
What kind of problems did you run into with EXTRACTVALUE?
Because it seems to be what you need...
Something along the lines of SELECT EXTRACTVALUE(my_xml_column, '/Person/name') FROM my_table WHERE id=; should return 'First Last' as asked...