Help converting SQL query to JPQL - sql

I have a SQL query that I need to translate over into JPQL, and I'm beginning to wonder if this is one of the cases where I'll just have to use native SQL. For reference, here is the SQL query.
SELECT c.title, a.approval_total, r.requested_total
FROM
codes c
INNER JOIN
(SELECT code_id, year, SUM(requested_amount) requestedTotal
FROM requests
GROUP BY code_id, year) r
ON c.id = r.code_id
INNER JOIN
(SELECT code_id, year, SUM(approved_amount) approvedTotal
FROM approvals
GROUP BY code_id, year) a
ON c.id = a.code_id
WHERE c.title = ? AND r.fiscal_year = ? and a.fiscal_year = ?
Does anyone know of a way to translate an in line view like these two into JPQL? Or alternatively a different way of structuring the query that might make it easier to translate?

I would first rewrite the SQL query without the use of inline selects
not sure if I write it correctly, but it would be something like this :
SELECT c.title, sum(a.approved_amount) as approval_total, SUM(r.requested_amount) as requested_total
FROM codes c
INNER JOIN requests r ON c.id = r.code_id
INNER JOIN approvals a ON c.id = a.code_id
WHERE c.title = ? AND r.fiscal_year = ? and a.fiscal_year = ?
GROUP By r.code_id, r.year, a.code_id, a.year

Related

How do you write this table filters into SQL SELECT Statement?

I am trying to retrieve records from a database with multiple reports/tables.
Here is the filter from the report I am trying to convert into an SQL statement:
And here is my SQL statement from that given report:
SELECT c.ClientId,
c.State,
c.BranchId,
c.ClientName,
c.AddressLine1,
c.AddressLine2,
c.AddressLine3,
c.Suburb,
c.City,
c.CountryName,
c.Postcode,
c.Telephone,
c.Mobile,
c.Email,
c.TradingAs,
c.Contact,
c.JobTitle,
c.Classification,
c.SalesTeamId,
c.ServiceTeamId,
c.AuthorisedRep1Id,
c.ABN,
p.PolicyDescription,
p.PolicyNumber,
t.ClassOfRiskname,
t.InsurerId,
t.ToDate
FROM Reports_Clients_Prospects c
INNER JOIN Reports_Policies p ON c.ClientId = p.ClientId
INNER JOIN Reports_Policy_Transactions t ON t.PolicyTransactionId = p.LatestTransactionId
WHERE c.ClientStatus = 'Current'
AND c.Branch = 'ValueOne'
AND c.AuthorisedRep1 != 'ValueTwo'
AND p.RenewalType = 'Renewable'
AND t.TransactionType != 'Quotation'
AND t.ToDate >=: startDate
AND t.ToDate <=: endDate;
The problem is that the filter from the report and the data from the sql are not the same. I was thinking the problem might be the sql using the 'inner join' statement? If it is, how would you write the sql select statement from the given filters above?
INNER JOINs are commutative operations. that's :
A INNER JOIN B <=> B INNER JOIN A
So there is no importance of the precendence of tables involved in the INNER JOINs...
The only part that is a little bit different from the report tool is the interval on the date that sould be write with the BETWEEN operator, like this :
AND t.ToDate BETWEEN :startDate AND :endDate
Some procedural languages use :anystring for variables...

Oracle SQL - how to NOT SHOW athlete name that apears only once

created a view called winners, it contains the columns: athlete_name,year,medal_won
its basicly athletes that won olympic medal and the year,
it look like that,
data base is in live sql: https://livesql.oracle.com/apex/f?p=590:1000:0
select distinct year,athlete_name,medal
from olym.olym_medals
join olym.olym_athlete_games on olym_athlete_games.id = olym_medals.athlete_game_id
join olym.olym_nations on olym_nations.id = olym_athlete_games.nation_id
join olym.olym_games on olym_games.id = Olym_athlete_games.game_id
join olym.olym_athletes on olym_athletes.id = olym_athlete_games.athlete_id
order by athlete_name
as you can see some name show only once and some names are showing more than once, i want to get rid off all lines of those who show ONLY ONCE, please help me.
thank you!
if i have understand your problem, must group your data,
select year,athlete_name,medal, count(*) "number of Medals"
from olym.olym_medals
join olym.olym_athlete_games on olym_athlete_games.id = olym_medals.athlete_game_id
join olym.olym_nations on olym_nations.id = olym_athlete_games.nation_id
join olym.olym_games on olym_games.id = Olym_athlete_games.game_id
join olym.olym_athletes on olym_athletes.id = olym_athlete_games.athlete_id
group by year,athlete_name,medal;
If I followed you correctly, you can use window functions:
select *
from (
select og.year, oa.athlete_name, om.medal, count(*) over(partition by oa.id) cnt
from olym.olym_medals om
join olym.olym_athlete_games oag on oag.id = om.athlete_game_id
join olym.olym_nations ona on ona.id = oag.nation_id
join olym.olym_games og on og.id = oag.game_id
join olym.olym_athletes oa on oa.id = oag.athlete_id
) t
where cnt > 1
order by athlete_name
Notes:
I am unsure why you were using distinct in the first place, so I removed it (I suspect it is actually not needed)
I added table aliases to shorten the query, and prefixed the columns in the select clause with the table they belong to (you might want to review that) - these are best practices when dealing with multi-table queries
Use GROUP BY and HAVING COUNT(*) > 1:
SELECT year,
athlete_name,
medal
FROM olym.olym_medals
INNER JOIN olym.olym_athlete_games
ON olym_athlete_games.id = olym_medals.athlete_game_id
INNER JOIN olym.olym_nations
ON olym_nations.id = olym_athlete_games.nation_id
INNER JOIN olym.olym_games
ON olym_games.id = Olym_athlete_games.game_id
INNER JOIN olym.olym_athletes
ON olym_athletes.id = olym_athlete_games.athlete_id
GROUP BY
year,
athlete_name,
medal
HAVING COUNT(*) > 1
ORDER BY athlete_name

Need help in optimizing sql query

I am new to sql and have created the below sql to fetch the required results.However the query seems to take ages in running and is quite slow. It will be great if any help in optimization is provided.
Below is the sql query i am using:
SELECT
Date_trunc('week',a.pair_date) as pair_week,
a.used_code,
a.used_name,
b.line,
b.channel,
count(
case when b.sku = c.sku then used_code else null end
)
from
a
left join b on a.ma_number = b.ma_number
and (a.imei = b.set_id or a.imei = b.repair_imei
)
left join c on a.used_code = c.code
group by 1,2,3,4,5
I would rewrite the query as:
select Date_trunc('week',a.pair_date) as pair_week,
a.used_code, a.used_name, b.line, b.channel,
count(*) filter (where b.sku = c.sku)
from a left join
b
on a.ma_number = b.ma_number and
a.imei in ( b.set_id, b.repair_imei ) left join
c
on a.used_code = c.code
group by 1,2,3,4,5;
For this query, you want indexes on b(ma_number, set_id, repair_imei) and c(code, sku). However, this doesn't leave much scope for optimization.
There might be some other possibilities, depending on the tables. For instance, or/in in the on clause is usually a bad sign -- but it is unclear what your intention really is.

how to select count of rows an other table

i'm using this query to select count of comments on other table but it give me error
SELECT
dbo.tblEmails.id, dbo.tblEmails.eTitle, dbo.tblEmails.ePreDesc, dbo.tblEmails.eTags, dbo.tblEmails.eFaDate, dbo.tblEmails.eViewCount,
dbo.tblEmails.ePrice, dbo.tblEmails.eImg, COUNT(tblComments.id) AS cCount
FROM
dbo.tblEmails as tblEmails
INNER JOIN
dbo.tblComments AS tblComments ON dbo.tblEmails.id = dbo.tblComments.PostID
GROUP BY
tblEmails.id, tblEmails.eTitle, tblEmails.ePreDesc, tblEmails.eTags, tblEmails.eFaDate, tblEmails.eViewCount, tblEmails.ePrice, tblEmails.eImg
UPDATE:
error is this :
the text,ntext, and image data types cannot be compared or
stored,except when using IS NULL or LIKE operator.
but i have not image data type in my table
Well, you haven't specified what error text is... But in this particular case it is easy to deduce.
Your problem is incorrect usage of aliases in join and select.
It should be not
INNER JOIN dbo.tblComments AS tblComments ON dbo.tblEmails.id = dbo.tblComments.PostID
but
INNER JOIN dbo.tblComments AS tblComments ON tblEmails.id = tblComments.PostID
And the same story is about select - not dbo.tblEmails.id but tblEmails.id since you've specified alias.
But note - using exact table_name as alias to dbo.table_name looks like a bad idea and may lead to confusion (and in fact, it has lead in your case).
Instead consider using short acronyms for aliases, like this:
SELECT
E.id, E.eTitle, E.ePreDesc, E.eTags,
E.eFaDate, E.eViewCount,E.ePrice, E.eImg,
COUNT(C.id) AS cCount
FROM dbo.tblEmails as E
INNER JOIN dbo.tblComments AS C ON E.id = C.PostID
GROUP BY
E.id, E.eTitle, E.ePreDesc, E.eTags,
E.eFaDate, E.eViewCount,E.ePrice, E.eImg
Do a sub-select to get the count:
SELECT dbo.tblEmails.id, dbo.tblEmails.eTitle, dbo.tblEmails.ePreDesc, dbo.tblEmails.eTags, dbo.tblEmails.eFaDate, dbo.tblEmails.eViewCount,
dbo.tblEmails.ePrice, dbo.tblEmails.eImg,
(select COUNT(*) from dbo.tblComments
where dbo.tblEmails.id = dbo.tblComments.PostID) AS cCount
FROM dbo.tblEmails as tblEmails

sql select in select query

I'm using plsql developer with oracle db
and i'm trying to select from some selection.
select *
from (select max(mrs.no), mrs.material_id
from material_route_step mrs, documents d
where d.document_id(+) = mrs.document_id
and mrs.prod_order_id = 121673
and d.document_type_id = 1
and mrs.unit_id = 2606
group by mrs.material_id) as sa,
material_route_step mrs1,
documents d1
where mrs1.material_id = sa.material_id
and mrs1.no = sa.no
and d.name like '%N%'
But i think my syntax isn't right. Thanks in advance.
It looks like your "d.name" reference might be incorrect as the "d" alias is on your Inner query vs d1 in your OUTER query... Maybe that should be a "d1.name", but you should also include your left-outer join (+) reference by the document ID too otherwise you will have a Cartesian result.
where
mrs1.material_id = sa.material_id
and mrs1.no = sa.no
and d1.document_id(+) = mrs1.document_id
and d1.name like '%N%'
But, to better offer an answer, I will try to answer by writing what I THINK you are looking for, then a query to get that. Since you are looking for the maximum "mrs.no", this would imply you want a JOIN and not a left-join via Oracle's syntax of (+)=, but for a specific product, document type and unit. Once that has been found, get every document name associated with the materials route.
select
*
from
( select
mrs.material_id,
max( mrs.no ) as maxno
from
material_route_step mrs
JOIN documents d
on mrs.document_id = d.document_id
AND d.document_type_id = 1
where
mrs.prod_order_id = 121673
and mrs.unit_id = 2606
group by
mrs.material_id ) PreQuery
JOIN material_route_step mrs2
on PreQuery.material_id = mrs2.material_id
AND PreQuery.maxno = mrs2.no
JOIN documents d2
on mrs2.document_id = d2.document_id
Without applying a join condition on your outer documents "d1" alias, you WILL get a Cartesian result set.