I am using JPA2/Hibernate5 with Java8 over MySql.
I run the following native query:
Query q = entityManager.createNativeQuery(sb.toString(), JobWithDistance.class);
q.setParameter("ids", ids);
List<JobWithDistance> jobsWD = (List<JobWithDistance>) q.getResultList();
The sql in sb returns 3 rows when I run it directly against the database with the same parameters. However, when I run the native query via Hibernate, I only get one row.
Why are the results different?
More info:
Hibernate returns 1 row:
StringBuilder sb = getFindQuery();
sb.append(" where e.id in (:ids) ");
Query q = entityManager.createNativeQuery(sb.toString(), JobWithDistance.class);
q.setParameter("ids", ids);
//Object o = q.getResultList();
List<JobWithDistance> jobsWD = q.getResultList();
and
private StringBuilder getFindQuery() {
StringBuilder sb = new StringBuilder();
sb.append(" select * ");
sb.append(" , -1 as noReviews, -1 as averageRating ");
sb.append(" , -1 AS distance ");
sb.append(" from ");
sb.append(" www.job as e ");
sb.append(" inner join www.person_job as pj on e.id = pj.JOB_ID ");
sb.append(" inner join www.person as p on pj.PER_ID = p.id ");
sb.append(" left join www.rating_job rp ON e.id = rp.JOB_ID ");
sb.append(" left join www.rating r ON rp.RAT_ID = r.id ");
return sb;
}
The following SQl when run against the database, returns 3 rows:
select * , -1 as noReviews, -1 as averageRating , -1 AS distance from www.job as e inner join www.person_job as pj on e.id = pj.JOB_ID inner join www.person as p on pj.PER_ID = p.id left join www.rating_job rp ON e.id = rp.JOB_ID left join www.rating r ON rp.RAT_ID = r.id where e.id in (65, 66, 64)
Thanks
SOLUTION:
#Override
public List<Job> findById(String ids) {
String[] args = ids.split(",");
Set<String> idSet = new HashSet<String>(Arrays.asList(args));
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Job> query = builder.createQuery(Job.class);
Root<Job> post = query.from(Job.class);
query.select(post).where(post.get("id").in(idSet)); // or pass a tag collection to `in` method
TypedQuery<Job> typedQuery = entityManager.createQuery(query);
List<Job> results = typedQuery.getResultList();
return results;
}
Related
I am generating a query that returns a set of profiles that meet all the conditions posted below
I am receiving the data like so in Ruby, then making a dynamic MySQL query based on the contents -
[{ attribute_id: 58, parent_profile_name: 'Douglas-Connelly' },
{ attribute_id: 26, parent_profile_name: 'Brekke LLC' },
{ attribute_id: 35, val: 'Asa' },
{ attribute_id: 38, val: 'Stanton' }]
These are the current contents of the database
profile_attribute_values
profile_id attribute_id parent_profile_id val
6 58 2
6 26 5
6 35 nil 'Asa'
6 38 nil 'Stanton'
profile
id name
2 Douglas-Connelly
5 Brekke LLC
6 nil
I need to return all profiles that meet all the conditions - profiles that have a relation to profile_attribute_values, where the attribute_id is x, and the val is y, AND where the attribute_id is x, and the parent_profile name = y
WHAT I CURRENTLY HAVE
SELECT * FROM
(SELECT P2. *
FROM profile_attribute_values PAV
INNER JOIN profiles P1 ON P1.id = PAV.parent_profile_id
INNER JOIN profiles P2 ON P2.id = PAV.profile_id
WHERE (PAV.ne_attribute_id = '58' AND P1.`name` = 'Douglas-Connelly')
) A,
(SELECT P1. *
FROM profiles P1
INNER JOIN profile_attribute_values PAV ON P1.id = PAV.profile_id
INNER JOIN profile_attribute_values PAV2 ON P1.id = PAV2.profile_id
WHERE (PAV.ne_attribute_id = '35' AND PAV.val = 'ASA')
AND (PAV2.ne_attribute_id = '38' AND PAV2.val = 'Stanton')
) B
WHERE A.id = B.id
This will return
profile
id name
6 nil
which is exactly what I want, though the tricky part is the second parent_profile condition where I need attribute_id 26, and parent_profile_name: 'Brekke LLC'
I know this wont work, but I need this to do something like this
SELECT * FROM
(SELECT P2. *
FROM profile_attribute_values PAV
INNER JOIN profiles P1 ON P1.id = PAV.parent_profile_id
INNER JOIN profiles P2 ON P2.id = PAV.profile_id
WHERE (PAV.ne_attribute_id = '58' AND P1.`name` = 'Douglas-Connelly')
AND (PAV.ne_attribute_id = '26' AND P1.`name` = 'Brekke LLC')
) A,
.....
I am generating the SQL statement dynamically, so I really need it to be as clean as possible. I generally use ruby active record for everything, so I am a little babied when it comes to SQL statements. Thanks!
UPDATE
Okay I found a great solution to generate the dynamic query that I need, makes a single call to the database. This is the finished class
class ProfileSearch
def initialize(params, args = {})
#attr_vals = params
#options = args
filter_attrs
end
attr_accessor :parent_attrs, :string_attrs
def search
Profile.joins(generate_query)
end
def generate_query
q = ''
q << parents_query
q << attr_vals_query
end
def parents_query
str = ''
parent_attrs.each_with_index do |pa, i|
str << "INNER JOIN profile_attribute_values PAVP#{i} ON profiles.id = PAVP#{i}.profile_id "\
"AND PAVP#{i}.ne_attribute_id = #{pa} "\
"INNER JOIN profiles PP#{i} ON PP#{i}.id = PAVP#{i}.parent_profile_id "\
"AND PP#{i}.`name` = '#{#attr_vals[pa.to_s]}' "
end
str
end
def attr_vals_query
str = ''
string_attrs.each_with_index do |a, i|
str << "INNER JOIN profile_attribute_values PAVS#{i} ON profiles.id = PAVS#{i}.profile_id "\
"AND PAVS#{i}.ne_attribute_id = #{a} AND PAVS#{i}.val = '#{#attr_vals[a.to_s]}' "
end
str
end
def filter_attrs
ne = NeAttribute.find(#attr_vals.keys)
self.parent_attrs = ne.select{ |x| x.parent_profile)_attr? }.map(&:id)
self.string_attrs = ne.select{ |x| x.string_attr? }.map(&:id)
end
end
The first thing you need to know about is joins.
Use it like so:
relation_1 = ProfileAttributeValue.joins("
INNER JOIN profiles P1 ON P1.id = PAV.parent_profile_id
INNER JOIN profiles P2 ON P2.id = PAV.profile_id
").where(..).pluck(:id)
relation_2 = ProfileAttributeValue.joins...where...pluck(:id)
relation_1 and relation_2 have not yet been run. They are ActiveRecord relations.
I like the following trick:
ProfileAttributeValue.where(["profile_attribute_values.id in (?) or profile_attribute_values.id in (?)]", relation_1, relation_2)
Again, that's just an activerecord relation. Call to_sql on it if curious.
Add more .where or whatever, and when run, it'll be a single query on the DB.
Posting what I did as the answer, in case anyone misses it above. This essentially creates a single joins query that allows me to pull the exact data needed. The query generated would look like this -
SELECT `profiles`.*
FROM `profiles`
INNER JOIN profile_attribute_values PAVP0 ON profiles.id = PAVP0.profile_id
AND PAVP0.ne_attribute_id = 26
INNER JOIN profiles PP0 ON PP0.id = PAVP0.parent_profile_id
AND PP0.`name` = 'Brekke LLC'
INNER JOIN profile_attribute_values PAVP1 ON profiles.id = PAVP1.profile_id
AND PAVP1.ne_attribute_id = 58
INNER JOIN profiles PP1 ON PP1.id = PAVP1.parent_profile_id
AND PP1.`name` = 'Douglas-Connelly'
INNER JOIN profile_attribute_values PAVS0 ON profiles.id = PAVS0.profile_id
AND PAVS0.ne_attribute_id = 35 AND PAVS0.val = 'Asa'
INNER JOIN profile_attribute_values PAVS1 ON profiles.id = PAVS1.profile_id
AND PAVS1.ne_attribute_id = 38 AND PAVS1.val = 'Stanton'
This is the class that generates its
class ProfileSearch
def initialize(params, args = {})
#attr_vals = params
#options = args
filter_attrs
end
attr_accessor :parent_attrs, :string_attrs
def search
Profile.joins(generate_query)
end
def generate_query
q = ''
q << parents_query
q << attr_vals_query
end
def parents_query
str = ''
parent_attrs.each_with_index do |pa, i|
str << "INNER JOIN profile_attribute_values PAVP#{i} ON profiles.id = PAVP#{i}.profile_id "\
"AND PAVP#{i}.ne_attribute_id = #{pa} "\
"INNER JOIN profiles PP#{i} ON PP#{i}.id = PAVP#{i}.parent_profile_id "\
"AND PP#{i}.`name` = '#{#attr_vals[pa.to_s]}' "
end
str
end
def attr_vals_query
str = ''
string_attrs.each_with_index do |a, i|
str << "INNER JOIN profile_attribute_values PAVS#{i} ON profiles.id = PAVS#{i}.profile_id "\
"AND PAVS#{i}.ne_attribute_id = #{a} AND PAVS#{i}.val = '#{#attr_vals[a.to_s]}' "
end
str
end
def filter_attrs
ne = NeAttribute.find(#attr_vals.keys)
self.parent_attrs = ne.select{ |x| x.parent_profile)_attr? }.map(&:id)
self.string_attrs = ne.select{ |x| x.string_attr? }.map(&:id)
end
end
i just want to use LinqToSql classes query. here i just want to convert this sql query to appropriate linq query.
this is my sql query:
SELECT j.[JobID], p.[PreparedEmailID],
p.[Name] AS 'PreparedEmailName',
j.[CreatedOn], j.[CompletedOn],
j.[SubscriberCount], j.[EmailsSent],
(SELECT TOP 1 [Message] FROM
[LoggedMessages] WHERE [JobID] =
j.[JobID] ORDER BY [LoggedMessageID] DESC)
AS 'LoggedMessage' FROM [Jobs] AS j
INNER JOIN [PreparedEmails] AS p
ON p.[PreparedEmailID] =
j.[PreparedEmailID]
and my generated linq query is like:
var query = from j in db.Jobs
join p in db.PreparedEmails on j.PreparedEmailID equals p.PreparedEmailID
join l in db.LoggedMessages on j.JobID equals l.JobID into ej
from l in ej.DefaultIfEmpty() orderby l.LoggedMessageID descending
orderby l.LoggedMessageID descending
orderby j.CreatedOn descending
select new
{
JobID = j.JobID,
PreparedEmailID = p.PreparedEmailID,
PreparedEmailName = p.Name,
CreatedOn = j.CreatedOn,
CompletedOn = j.CompletedOn,
SubscriberCount = j.SubscriberCount,
EmailsSent = j.EmailsSent,
LoggedMsg = l.Message
};
I prepared some linQ query for you (but i didn't test it in VS because i have no access to it now, so please be careful because it can contain some errors):
var list = from Jobs
join PreparedEmails on Jobs.PreparedEmailID == PreparedEmails.PreparedEmailID
join LoggedMessages on LoggedMessages.JobID == Jobs.JobID
select
{
JobID = Jobs.JobID,
PreparedEmailID = PreparedEmails.PreparedEmailID,
PreparedEmailName = PreparedEmails.Name,
CreatedOn= Jobs.CreatedOn,
CompletedOn = Jobs.CompletedOn,
SubscriberCount = Jobs.SubscriberCount,
EmailsSent = Jobs.EmailsSent,
LoggedMessage = LoggedMessages.Message
} orderby descending LoggedMessages.LoggedMessageID;
It should help a little bit ...
this is solution:
var query = from j in db.Jobs
join p in db.PreparedEmails on j.PreparedEmailID equals p.PreparedEmailID
orderby j.CreatedOn descending
select new
{
JobID = j.JobID,
PreparedEmailID = p.PreparedEmailID,
PreparedEmailName = p.Name,
CreatedOn = j.CreatedOn,
CompletedOn = j.CompletedOn,
SubscriberCount = j.SubscriberCount,
EmailsSent = j.EmailsSent,
LoggedMsg = (from l in db.LoggedMessages
where j.JobID == l.JobID
orderby l.LoggedMessageID descending
select l.Message).FirstOrDefault()
};
I using mysql stored procedure which uses to retrieve list of object. Is this possible ?
I'm following this article
Question:
How to retrieve the list of object like in select statement using result set ?
How to map the result set to list of object ?
CREATE DEFINER=root#localhost PROCEDURE generateLCRReport(IN countryCodeParam INT, OUT countryCode INT, OUT dialCode INT, OUT custPrefix VARCHAR(50), OUT vendorPrefix VARCHAR(50), OUT custPrice FLOAT, OUT vendorCost FLOAT, OUT profit FLOAT)
LANGUAGE SQL
DETERMINISTIC
READS SQL DATA
SQL SECURITY DEFINER
COMMENT 'generateLCRReport'
BEGIN
select c.country_code as countryCode, c.dial_code as dialCode,
c.customer_prefix as custPrefix, c.vendor_prefix as vendorPrefix,
max(cust_rate.rate) as custPrice, min(ven_rate.rate) as vendorCost,
round(max(cust_rate.rate) - min(ven_rate.rate), 3) as profit
from cdr c
inner join
(select a.id, r.rate, re.country_code, re.dial_code, ap.prefix from rate r
inner join region re on r.region_id = re.id
inner join account_prefix ap on r.account_prefix_id = ap.id
inner join account a on a.id = ap.account_id
where ap.prefix_type = 0
) as cust_rate
on c.country_code = cust_rate.country_code
and c.dial_code = cust_rate.dial_code
and c.customer_prefix = cust_rate.prefix
and c.customer_id = cust_rate.id
inner join
(select a.id, r.rate, re.country_code, re.dial_code, ap.prefix from rate r
inner join region re on r.region_id = re.id
inner join account_prefix ap on r.account_prefix_id = ap.id
inner join account a on a.id = ap.account_id
where ap.prefix_type = 1
) as ven_rate
on c.country_code = ven_rate.country_code
and c.dial_code = ven_rate.dial_code
and c.vendor_prefix = ven_rate.prefix
and c.vendor_id = ven_rate.id
where c.country_code = countryCodeParam
group by c.country_code and c.dial_code
order by c.country_code asc
limit 5000;
END
public class LCRReportSP extends StoredProcedure {
/**
*
*/
#Autowired
public LCRReportSP(JdbcTemplate jdbcTemplate, String storedProcName, RowMapper<CostReport> mapper) {
super(jdbcTemplate, storedProcName);
SqlReturnResultSet rs = new SqlReturnResultSet("", mapper);
SqlOutParameter outParam = new SqlOutParameter("countryCode", Types.INTEGER);
SqlOutParameter outParam1 = new SqlOutParameter("dialCode", Types.INTEGER);
SqlOutParameter outParam2 = new SqlOutParameter("custPrefix", Types.VARCHAR);
SqlOutParameter outParam3 = new SqlOutParameter("vendorPrefix", Types.VARCHAR);
SqlOutParameter outParam4 = new SqlOutParameter("custPrice", Types.FLOAT);
SqlOutParameter outParam5 = new SqlOutParameter("vendorCost", Types.FLOAT);
SqlOutParameter outParam6 = new SqlOutParameter("profit", Types.FLOAT);
this.declareParameter(rs);
this.declareParameter(outParam);
this.declareParameter(outParam1);
this.declareParameter(outParam2);
this.declareParameter(outParam3);
this.declareParameter(outParam4);
this.declareParameter(outParam5);
this.declareParameter(outParam6);
this.setFunction(false);
this.compile();
}
/**
* #param countryCode
* #return
*/
public Map<String, ?> generateLCRReport(int countryCode) {
Map<String, Object> inParam = new HashMap<String, Object>();
inParam.put("countryCodeParam", new Integer(countryCode));
return this.execute(inParam);
}
}
Please help.
Thanks.
I'm using RowMapper and declared parameter SqlReturnResultSet.
I need to convert this sql query to linq to sql and the result returns a IEnumerable:
select VisualAidName, v.VisualAidID, vs.VisualAidStatusName,
br.BrandName, v.IsEnabled, v.VisualAidCode, v.DateApproved,
br.BrandID, type, UserFirstName+ ' ' + UserLastName as name, AreaID
from VisualAids v inner join VisualAidStatus vs
on v.VisualAidStatusId = vs.VisualAidStatusId
inner join brands br
on v.BrandID = br.BrandId
inner join VisualAids_Areas_Link vareas
on v.VisualAidID = vareas.VisualAidID
left join users us
on v.Owner = us.UserID
where
AreaID IN (
select areaid
from Users inner join Users_Area_Link
on Users.UserID = Users_Area_Link.UserID
where Users.UserID= 3
)
I did this:
IEnumerable<Visual_Aid> visualAll = from v in Context.VisualAids
join vs in Context.VisualAidStatus on v.VisualAidStatusId equals vs.VisualAidStatusId
join br in Context.Brands on v.BrandID equals br.BrandId
join us in Context.Users on v.Owner equals us.UserID into vadis
from x in vadis.DefaultIfEmpty()
select new Visual_Aid()
{
VisualAid_Name = v.VisualAidName,
VisualAid_Id = v.VisualAidID,
VisualAid_StatusName = vs.VisualAidStatusName,
VisualAid_BrandsName = br.BrandName,
VisualAid_IsEnabled = bool.Parse(v.IsEnabled.ToString()),
VisualAid_Code = v.VisualAidCode,
VisualAid_DateApp = v.DateApproved.ToString() ?? "",
VisualAid_BrandId = int.Parse(v.BrandID.ToString()),
VisualAid_Type = v.Type,
VisualAid_Owner = x.UserID == null ? "" : x.UserFirstName + " " + x.UserLastName
};
but I need to do the part of the subquery, ie, I need to include this:
where AreaID IN (
select areaid from Users inner join Users_Area_Link
on Users.UserID = Users_Area_Link.UserID where Users.UserID= 3
)
Anybody know how? thank you very much in advance
You can add this as a where statement:
.......
join us in Context.Users on v.Owner equals us.UserID into vadis
from x in vadis.DefaultIfEmpty()
where (
from user in Context.Users
join userArea in Users_Area_Link
on user.UserID equals userArea.UserID
where user.UserID==3
select userArea.areaid
).Contains(????.AreaID)
select new Visual_Aid()
{
.......
select m.messageID,m.[addeddate],m.message,count(*) as Comments
from intranet.dbo.Blog_Messages AS m inner join
intranet.dbo.Blog_Comments AS c on c.messageid = m.messageid
group by m.messageID,m.[addeddate],m.message
need help converting this to linq to sql
from m in context.Blog_Messages
select new
{
MessageId = m.MessageID,
AddedDate = m.AddedDate,
Message = m.Message,
Comments = m.Blog_Comments.Count()
}
It isn't a direct conversion, but I think that is what you are after.
from m in db.Blog_Messages
join c in db.Blog_Comments on m.MessageID equals c.MessageID
group m by new {
m.MessageID,
m.AddedDate,
m.Message
} into g
select new {
MessageID = g.Key.MessageID,
AddedDate = g.Key.AddedDate,
g.Key.Message,
Comments = g.Count()
}
Dim Msg = From m In db2.Blog_Messages _
Group Join c In db2.Blog_Comments On m.MessageID Equals c.MessageID Into Comments = Group _
Join u In db2.users On m.userID Equals u.userid _
Select New With {
m.Title, m.Message, m.MessageID,
.CommentCount = Comments.Count(),
.date1 = m.AddedDate.ToShortDateString,
.Time = m.AddedDate.ToShortTimeString(),
.fullName = u.fname & " " & u.lname
}
this is what I came up with..
thanks,
chris