I have a query look like this.
<select id="select..." resulType="???">
SELECT
COUNT(1) AS count,
NAME AS name
FROM
...
GROUP BY
...
ORDER BY
count ASC
</select>
I actually need to fetch those names as ordered and I want my mapper interface be looked like this.
/**
* Lists names ordered by ... count.
* ...
*/
List<String> select...(...);
How can I do this? What type of resultType is required?
Do I need a specified resultMap?
You can just mention resultType="string".
For example, I tried the below query:
<select id="getCountriesSortedByLanguages" resultType="string">
SELECT c.name, count(cl.language)
FROM country c
JOIN countrylanguage cl ON cl.countrycode = c.code
GROUP BY c.code
ORDER BY 2 DESC
</select>
And my mapper is defined as:
public List<String> getCountriesSortedByLanguages();
Related
I am trying to select from one table using the select result from another table. I can run this in two queries but would like to optimize it into just one.
First query.. Select ids where matching other id
select id from lookuptable where paid = '547'
This results in something like this
6316352
6316353
6318409
6318410
6320468
6320469
6320470
6322526
6322527
6324586
6324587
6326648
I would like to then use this result to make another selection. I can do it manually like below. Note, there could be many rows with these values so I've been using a IN statement
select * from "othertable" where id in (6316352,6316353,6318409,6318410,6320468,6320469,6320470,6322526,6322527,6324586,6324587,6326648);
select
ot.*
from
"othertable" as ot
join
lookuptable as lt
on
ot.id = lt.id
where
lt.paid = '547'
The IN operator supports not just value lists but also subqueries, so you can literally write
select * from "othertable" where id in (select id from lookuptable where paid = '547');
Is it possible to use Inner Join in the FromSql method of Entity Framework core?
I used, but I got this error:
SqlException: The column 'Id' was specified multiple times for 'c'.
This is my code:
return DbContext.Contacts
.FromSql<Contact>("Select * From Contacts Inner Join Phones on Phones.ContactId = Contacts.Id Where Contacts.Id <= 2 And Phones.PhoneNumber='01234567890'")
.Include(o => o.RegisteredByUser)
.AsNoTracking()
.ToListAsync();
Your Id column appears in both the tables, Phones and Contacts. Instead of putting *, you better choose the fields required in your query like following.
Please note, you need to specify which Id you want, If you want both, in that case you can use alias names like following.
Select Phones.Id as PhoneId, Contacts.Id as ContactsId, ....
Your final query should look like following query.
Select Contacts.Id, ... From Contacts Inner Join Phones on Phones.ContactId = Contacts.Id Where Contacts.Id <= 2 And Phones.PhoneNumber='01234567890
Schema
Customer -> (Edge)Ownes -> Vehicle {vehicle_number}
tried to query the customer record who "Ownes" a vehicle by its number like below and it worked. (both 'in' and 'contains' worked fine)
select from Customer where "KL-01-B-8898" in out("Ownes").vehicle_number
I want to do the same query but using a case insensitive search, like below, but returned '0' records
select from Customer where "kl-01-b-8898" in out("Ownes").vehicle_number.toLowerCase()
I changed the query like below and it returned the rows. Is it possible to use functions like 'toLowerCase' in the queries like above, with out sub select ?
select from Customer where #rid in (select in("Ownes").#rid from Vehicle where vehicle_number.toLowerCase() ="kl-01-b-8898")
You can use this:
select from Customer
let $a= ( select number.toUpperCase() from (select out("Ownes").vehicle_number as number from $parent.$current unwind number))
where "KL-01-B-8898" in first($a).number
This doesn't work:
select from Customer where "kl-01-b-8898" in out("Ownes").vehicle_number.toLowerCase()
because
out("Ownes").vehicle_number
return a list of String
This works:
select from Customer where #rid in (select in("Ownes").#rid from Vehicle where vehicle_number.toLowerCase() ="kl-01-b-8898")
because vehicle_number is a String
See the documentation: http://orientdb.com/docs/last/SQL-Methods.html#bundled-methods
Here's my scenario:
--ORDER table
OrderID OrderCode DateShipped ShipmentXML
1 ABC 08/06/2013 <Order><Item CustomerName="BF" City="Philadelphia" State="PA"></Item></Order>
2 XYZ 08/05/2013 <Order><Item CustomerName="TJ" City="Richmond" State="VA"></Item></Order>
At some point in the process, I will know the respective TrackingNumber for these Orders. The tracking numbers are available in another table like this:
--TRACKING table
TrackingID OrderCode TrackingNumber
98 ABC 1Z1
99 XYZ 1Z2
The output I'm expecting is as below:
OrderID OrderCode ShipmentXML
1 ABC <Order><Item CustomerName="BF" City="Philadelphia" State="PA" DateShipped="08/06/2013" TrackingNumber="1Z1"></Item></Order>
2 XYZ <Order><Item CustomerName="TJ" City="Richmond" State="VA" DateShipped="08/05/2013" TrackingNumber="1Z2"></Item></Order>`
As you can see, I'm trying to get the TrackingNumber and the DateShipped for each OrderCode and have them as an attribute. The intent is a SELECT, not UPDATE.
All the examples I've seen demonstrate how to update the XML with a Constant value or a variable. I couldn't find one that demonstrates XML updates with a JOIN. Please help with how this can be accomplished.
UPDATE:
By 'Select not Update', I meant that no updates to the permanent table; UPDATE on temp tables are perfectly fine, as Mikael commented below the first answer.
A version using a temp table to add the attributes to the XML.
select OrderID,
OrderCode,
DateShipped,
ShipmentXML
into #Order
from [Order]
update #Order
set ShipmentXML.modify
('insert attribute DateShipped {sql:column("DateShipped")}
into (/Order/Item)[1]')
update O
set ShipmentXML.modify
('insert attribute TrackingNumber {sql:column("T.TrackingNumber")}
into (/Order/Item)[1]')
from #Order as O
inner join Tracking as T
on O.OrderCode = T.OrderCode
select OrderID,
OrderCode,
ShipmentXML
from #Order
drop table #Order
Prevous answer is good, but you have to explicitly specify columns and cast them into varchar, and that's not good for future support (if you add attributes to ShipmentXML you'll have to modify the query).
Instead, you could use XQuery:
select
O.OrderID, O.OrderCode,
(
select
(select O.DateShipped, T.TrackingNumber for xml raw('Item'), type),
O.ShipmentXML.query('Order/*')
for xml path(''), type
).query('<Order><Item>{for $i in Item/#* return $i}</Item></Order>')
from [ORDER] as O
left outer join [TRACKING] as T on T.OrderCode = O.OrderCode
or even like this:
select
O.OrderID, O.OrderCode,
O.ShipmentXML.query('
element Order {
element Item {
attribute DateShipped {sql:column("O.DateShipped")},
attribute TrackingNumber {sql:column("T.TrackingNumber")},
for $i in Order/Item/#* return $i
}
}')
from [ORDER] as O
left outer join [TRACKING] as T on T.OrderCode = O.OrderCode
see sqlfiddle with examples
The only way I know allowing partial modification of data in columns of xml type is using modify method, but as stated in documentation
The modify() method of the xml data type can only be used in the SET
clause of an UPDATE statement.
Since UPDATE is not desired, as a workaround I see shredding and reassembling it manually as:
select
o.OrderID,
o.OrderCode,
(
cast((select
t.c.value('#CustomerName', 'varchar(50)') as '#CustomerName',
t.c.value('#City', 'varchar(50)') as '#City',
t.c.value('#State', 'varchar(50)') as '#State',
o.DateShipped as '#DateShipped',
tr.TrackingNumber as '#TrackingNumber'
for xml path('Item'), root('Order')) as xml)
) as ShipmentXML
from
[ORDER] o
join [TRACKING] tr on tr.OrderCode = o.OrderCode
cross apply o.ShipmentXML.nodes('Order/Item') t(c)
You may have to apply formatting to o.DateShipped.
I have 3 tables like:
A AB B
------------- ------------ ---------------
a1 a1,b1 b1
AB is a transition table between A and B
With this, my classes have no composition within these two classes to each other. But I want to know that , with a JPQL Query, if any records exist for my element from A table in AB table. Just number or a boolean value is what I need.
Because AB is a transition table, there is no model object for it and I want to know if I can do this with a #Query in my Repository object.
the AB table must be modeled in an entity to be queried in JPQL. So you must model this as
an own entity class or an association in your A and or your B entity.
I suggest to use Native query method intead of JPQL (JPA supports Native query too). Let us assume table A is Customer and table B is a Product and AB is a Sale. Here is the query for getting list of products which are ordered by a customer.
entityManager.createNativeQuery("SELECT PRODUCT_ID FROM
SALE WHERE CUSTOMER_ID = 'C_123'");
Actually, the answer to this situation is simpler than you might think. It's a simple matter of using the right tool for the right job. JPA was not designed for implementing complicated SQL queries, that's what SQL is for! So you need a way to get JPA to access a production-level SQL query;
em.createNativeQuery
So in your case what you want to do is access the AB table looking only for the id field. Once you have retrieved your query, take your id field and look up the Java object using the id field. It's a second search true, but trivial by SQL standards.
Let's assume you are looking for an A object based on the number of times a B object references it. Say you are wanting a semi-complicated (but typical) SQL query to group type A objects based on the number of B objects and in descending order. This would be a typical popularity query that you might want to implement as per project requirements.
Your native SQL query would be as such:
select a_id as id from AB group by a_id order by count(*) desc;
Now what you want to do is tell JPA to expect the id list to comeback in a form that that JPA can accept. You need to put together an extra JPA entity. One that will never be used in the normal fashion of JPA. But JPA needs a way to get the queried objects back to you. You would put together an entity for this search query as such;
#Entity
public class IdSearch {
#Id
#Column
Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
Now you implement a little bit of code to bring the two technologies together;
#SuppressWarnings("unchecked")
public List<IdSearch> findMostPopularA() {
return em.createNativeQuery("select a_id as id from AB group by a_id
order by count(*) desc", IdSearch.class).getResultList();
}
There, that's all you have to do to get JPA to get your query completed successfully. To get at your A objects you would simply cross reference into your the A list using the traditional JPA approach, as such;
List<IdSearch> list = producer.getMostPopularA();
Iterator<IdSearch> it = list.iterator();
while ( it.hasNext() ) {
IdSearch a = it.next();
A object = em.find(A.class,a.getId());
// your in business!
Still, a little more refinement of the above can simplify things a bit further actually given the many many capabilities of the SQL design structure. A slightly more complicated SQL query will an even more direct JPA interface to your actual data;
#SuppressWarnings("unchecked")
public List<A> findMostPopularA() {
return em.createNativeQuery("select * from A, AB
where A.id = AB.a_id
group by a_id
order by count(*) desc", A.class).getResultList();
}
This removes the need for an interm IdSearch table!
List<A> list = producer.getMostPopularA();
Iterator<A> it = list.iterator();
while ( it.hasNext() ) {
A a = it.next();
// your in business!
What may not be clear tot the naked eye is the wonderfully simplified way JPA allows you to make use of complicated SQL structures inside the JPA interface. Imagine if you an SQL as follows;
SELECT array_agg(players), player_teams
FROM (
SELECT DISTINCT t1.t1player AS players, t1.player_teams
FROM (
SELECT
p.playerid AS t1id,
concat(p.playerid,':', p.playername, ' ') AS t1player,
array_agg(pl.teamid ORDER BY pl.teamid) AS player_teams
FROM player p
LEFT JOIN plays pl ON p.playerid = pl.playerid
GROUP BY p.playerid, p.playername
) t1
INNER JOIN (
SELECT
p.playerid AS t2id,
array_agg(pl.teamid ORDER BY pl.teamid) AS player_teams
FROM player p
LEFT JOIN plays pl ON p.playerid = pl.playerid
GROUP BY p.playerid, p.playername
) t2 ON t1.player_teams=t2.player_teams AND t1.t1id <> t2.t2id
) innerQuery
GROUP BY player_teams
The point is that with createNativeQuery interface, you can still retrieve precisely the data you are looking for and straight into the desired object for easy access by Java.
#SuppressWarnings("unchecked")
public List<A> findMostPopularA() {
return em.createNativeQuery("SELECT array_agg(players), player_teams
FROM (
SELECT DISTINCT t1.t1player AS players, t1.player_teams
FROM (
SELECT
p.playerid AS t1id,
concat(p.playerid,':', p.playername, ' ') AS t1player,
array_agg(pl.teamid ORDER BY pl.teamid) AS player_teams
FROM player p
LEFT JOIN plays pl ON p.playerid = pl.playerid
GROUP BY p.playerid, p.playername
) t1
INNER JOIN (
SELECT
p.playerid AS t2id,
array_agg(pl.teamid ORDER BY pl.teamid) AS player_teams
FROM player p
LEFT JOIN plays pl ON p.playerid = pl.playerid
GROUP BY p.playerid, p.playername
) t2 ON t1.player_teams=t2.player_teams AND t1.t1id <> t2.t2id
) innerQuery
GROUP BY player_teams
", A.class).getResultList();
}