converting sql to hql query - sql

Have to convert below working query into hql query. product and car is the domain.
Product {
long id
hasmany car: Car
string code
}
Car {
int no
int value
}
select p.id from products p
inner join car c on c.id=p.id and p.code='car'
inner join car cr on cr.id=p.id and p.code='car'
where c.no=1 and c.value>=10 and c.no=2 and c.value<=30

Looking at the definition of your model it should be enough to do the following query
var query = session.CreateQuery("select p.id from Product p join p.car c" +
" where c.no=1 " +
" and c.value>=10 " +
" and c.no=2 " +
" and c.value<=30 " +
" and p.code='car' ");
var results = query.List<int>();
with session being instance of ISession interface.

Related

Extract the list of brands associated with a category in WooCommerce

In woocommerce, I have products which are classified in one (or more) categories (product_cat), and which have a brand attribute (pa_marque), and are only in one brand.
I'm trying to extract the list of brands associated with a category ...
By doing a SQL JOIN (this may not be the best solution) on the term_relationships, term_taxonomy, terms and posts tables I get something like this:
{"post_id":"23391","term_taxonomy_id":"1217","taxonomy":"product_cat","taxonomy_parent":"0"},
{"post_id":"23391","term_taxonomy_id":"1219","taxonomy":"product_cat","taxonomy_parent":"1217"},
{"post_id":"23391","term_taxonomy_id":"1943","taxonomy":"pa_marque","taxonomy_parent":"0"}
(i.e. product 23391 has 2 product_cat and 1 pa_marque ... but that's where I don't really know how to continue ...)
Would you have a clue?
I found Get WooCommerce product categories that contain a specific product brand answer code and I got it working making some little changes to the code as follow:
// Inspired by https://stackoverflow.com/a/61624358/1256770
function get_taxovalues_in_another_taxo_from_a_product_categories($taxonomy_tofind, $taxonomy_known, $cat_term_slug)
{
global $wpdb;
$results = $wpdb->get_results("
SELECT DISTINCT
t1.*
FROM {$wpdb->prefix}terms t1
INNER JOIN {$wpdb->prefix}term_taxonomy tt1
ON t1.term_id = tt1.term_id
INNER JOIN {$wpdb->prefix}term_relationships tr1
ON tt1.term_taxonomy_id = tr1.term_taxonomy_id
INNER JOIN {$wpdb->prefix}term_relationships tr2
ON tr1.object_id = tr2.object_id
INNER JOIN {$wpdb->prefix}term_taxonomy tt2
ON tr2.term_taxonomy_id = tt2.term_taxonomy_id
INNER JOIN {$wpdb->prefix}terms t2
ON tt2.term_id = t2.term_id
WHERE
tt1.taxonomy = '$taxonomy_tofind'
AND tt2.taxonomy = '$taxonomy_known'
AND t2.slug = '$cat_term_slug'
ORDER BY t1.name
");
$return = [];
if (!empty($results)) {
$term_names = [];
foreach ($results as $result) {
$term_link = get_term_link(get_term($result->term_id, $taxonomy_tofind), $taxonomy_tofind);
$term_names[] = '<a class="' . $result->slug . '" href="' . $term_link . '">'
. $result->name . '</a>';
}
$return = $term_names;
}
return $return;
}
// searching 'pa_marque' associated to product_cat "aiguilles-et-crochets"
$brands = get_taxovalues_in_another_taxo_from_a_product_categories('pa_marque', 'product_cat', 'aiguilles-et-crochets');
print(implode(" - ", $brands));
// searching 'pa_epaisseur-laine' associated to product_cat "laines"
$brands = get_taxovalues_in_another_taxo_from_a_product_categories('pa_epaisseur-laine', 'product_cat', 'laines');
print(implode(" - ", $brands));

How to do a write a JPQL query to find records not found in this join?

For the life of me, I can't figure out how to construct this JPA query.
I need to find TransactionLogs which have not been transmitted under a given SyncSendingConfig, ordered by ID.
Researching it on SO, I figure it should be possible in SQL to do an outer join where the IDs are null for the one side, as in this diagram:
Here's the Entities I have to work with.
#Entity
public class SyncSendingConfig {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "sendingConfig")
private Set<SyncJob> sendJobs = new HashSet<>();
}
#Entity
public class SyncJob {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "sending_config_id")
private SyncSendingConfig sendingConfig;
#ManyToMany(cascade = { CascadeType.ALL })
#JoinTable(
name = "SyncJob_TransactionLog",
joinColumns = { #JoinColumn(name = "sync_job_id") },
inverseJoinColumns = { #JoinColumn(name = "transaction_log_id") }
)
private Set<TransactionLog> transmitted = new HashSet<>();
}
#Entity
public class TransactionLog {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#ManyToMany(mappedBy = "transmitted")
private Set<SyncJob> syncJobs = new HashSet<>();
}
And the DAO I'm trying to write:
public interface SyncSendingConfigDao extends JpaRepository<SyncSendingConfig, Long> {
// TODO: This is the query I'm trying to get to work
/** Returns those transactions that were never sent for the given SyncSenderConfig, ordered by ID */
#Query("SELECT tl FROM SyncJob sj "+
"JOIN SyncSendingConfig ssc ON sj.sendingConfig = ssc.id AND ssc.id= :sendingConfigId "+
"RIGHT JOIN TransactionLog tl on tl.syncJobs = sj "+
"WHERE sj.id is null"
)
Stream<TransactionLog> findTransactionsNotSentForSyncSendingConfigId(#Param("sendingConfigId") long sendingConfigId);
// If this part is relevant, this join shows how I can get only those SyncJobs which are related to the SyncSendingConfig of interest
#Query("SELECT sj FROM SyncJob sj JOIN SyncSendingConfig ssc ON sj.sendingConfig = ssc.id WHERE ssc.id= :sendingConfigId ")
#QueryHints(value = #QueryHint(name = org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE, value = "500"))
Stream<SyncJob> findJobs(#Param("sendingConfigId") long sendingConfigId);
}
The query above on the DAO shows what I'm attempting to do. I'm really unsure of how to translate SQL to JPQL... especially on the join conditions and order.
Update:
Here's the exact SQL query which I'm trying to translate. It matches all the relationships defined by hibernate in the classes above.
select tl.*
from sync_job sj
join sync_sending_config ssc
on ssc.id = sj.sending_config_id and ssc.id=2
join sync_job_transaction_log sjtl
on sjtl.sync_job_id = sj.id
RIGHT JOIN transaction_log tl
on tl.id = sjtl.transaction_log_id
where sjtl.sync_job_id is null
When this query is run directly, it returns the exact results being sought.
If anyone can offer help, I'd greatly appreciate it. I've been running against a wall trying to figure the JPQL syntax out.
Thanks
Update 2
After working with '#S B', it appears that JPQL doesn't support a right join. Short of finding out how to write this in JPQL with a left join (if possible), I went with a native query:
#Query(value = "select tl.* from sync_job sj "+
"join sync_sending_config ssc on ssc.id = sj.sending_config_id and ssc.id = :sendingConfigId "+
"join sync_job_transaction_log sjtl on sjtl.sync_job_id = sj.id "+
"RIGHT JOIN transaction_log tl on tl.id = sjtl.transaction_log_id "+
"where sjtl.sync_job_id is null",
nativeQuery = true)
#QueryHints(value = #QueryHint(name = org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE, value = "500"))
Stream<TransactionLog> findTransactionsNotSentForSyncSendingConfigId(#Param("sendingConfigId") long sendingConfigId);
Assuming the below dummy data setup:
Transaction Log IDs: 1, 2, 3, 4
SyncSendingConfig IDs: 1, 2
Sync Jobs:
ID 1, SyncSendingConfigID 1
ID 2, SyncSendingConfigID 1
ID 3, SyncSendingConfigID 2
ID 4, SyncSendingConfigID 2
sync_job_transaction_log
SyncJobId 1, TransactionLogId 1
SyncJobId 1, TransactionLogId 2
SyncJobId 2, TransactionLogId 1
SyncJobId 2, TransactionLogId 2
TransactionLogs 1 and 2 are transmitted under SyncSendingConfig ID 1 as per the mapping in sync_job_transaction_log table.
Therefore, TransactionLogs not transmitted under SyncSendingConfig ID 1 would be 3 and 4.
So, in order to find TransactionLogs which have not been transmitted under a given SyncSendingConfig, corresponding JPQL is -
#Query("select t from TransactionLog t where t not in (" +
"select t1 from TransactionLog t1 join t1.syncJobs tsj where tsj in "
+ "(select sj from SyncJob sj where sj.sendingConfig.id = :sendingConfigId)"
+ ")")
Consider JPQL as SQL applied to Java objects with entities representing tables, their properties representing columns and the has-a relationship as expressing the mapping relationship.
Now, when you want to join two tables, just refer to the corresponding entities and so long as the join columns are correctly specified, the SQL query will be correctly formed on the join tables and columns.
Example SQL -
select column(s) from table1 <type of> join table2 on table1.column1 = table2.column1 where <filter conditions here>
Corresponding JPQL setup -
Entity1 (corresponds to table1) ->
property1 (corresponds to column)
property2 (corresponds to mapping relationship, has #JoinColumn details)
JPQL for above setup -
select property1 from entity1 <type of> join entity1.property2 where <filter condition here>
Update after discussion in comments -
Since a right join in the current setup is not possible, suggest to evaluate JPQL on performance parameters or alternatively to use the working SQL as nativeQuery.
#Query(value = "select tl.* from sync_job sj "+
"join sync_sending_config ssc on ssc.id = sj.sending_config_id "+
"join sync_job_transaction_log sjtl on sjtl.sync_job_id = sj.id "+
"RIGHT JOIN transaction_log tl on tl.id = sjtl.transaction_log_id "+
"where sjtl.sync_job_id is null and ssc.id = :sendingConfigId",
nativeQuery = true)

EclipseLink/TopLink full outer join instead left join

On model Card can have or not CardHolder ( 1:1 ), and I would like getting every cards filter by issuer linked to actived cardHolders plus cards without cardHolders, so I need a full outer join. Although the query below translate to left join returning just cards with cardHolders
final ExpressionBuilder builder = new ExpressionBuilder( Card.class );
Expression queryExp = builder.get( "cardIssuer" ).equal( cardIssuer );
queryExp = queryExp.and( builder.get( "cardStatus" ).get( "statusType" ).equal( "ACTIVATED" ) );
queryExp = queryExp.and( builder.getAllowingNull( "cardHolder" )isNull().or(
builder.get( "cardHolder" ).get( "status" ).get( "status" ).equal( "ACTIVE" ) ) );
Expression orderExpression = builder.get( "cardHolder" ).get( "surname" ).descending();
return getMultiple( queryExp, pageable , Card.class, orderExpression );
Translate query is
SELECT COUNT(t0.CARD_ID) FROM CARD t0 LEFT JOIN CARD_HOLDER t3
ON (t3.CARD_HOLDER_ID = t0.CARD_HOLDER_ID), CARD_HOLDER_STATUS t2, CARD_STATUS t1
WHERE (((((t0.CARD_ISSUER_ID = 10006) AND (t1.STATUS_TYPE = 'ACTIVATED')) AND (t2.STATUS = 'ACTIVE'))
AND (t0.CARD_ID IN ('52683','52692')))
AND ((t1.CARD_STATUS_ID = t0.CARD_STATUS_ID) AND (t2.STATUS_ID = t3.STATUS_ID)))
Due to JPA version the outer join is not properly done, so I found a way through native queries
#NamedNativeQueries( {
#NamedNativeQuery( name = Card.USER_DIRECTORY_BASE,
query = "select * from card c full outer join card_holder ch on c.card_holder_id = ch.card_holder_id "
+ "where c.CARD_ISSUER_ID = ?1 and c.card_status_id = 1 and ( ch.STATUS_ID = 1 or c.CARD_HOLDER_ID is null) "
+ "order by ch.FORENAME asc",
resultClass = Card.class ),
#NamedNativeQuery( name = Card.USER_DIRECTORY_BASE_COUNT,
query = "select count(*) from card c full outer join card_holder ch on c.card_holder_id = ch.card_holder_id "
+ "where c.CARD_ISSUER_ID = ?1 and c.card_status_id = 1 and ( ch.STATUS_ID = 1 or c.CARD_HOLDER_ID is null) "
+ "order by ch.FORENAME asc" )
} )
And getting results
Query query = em.createNamedQuery( Card.USER_DIRECTORY_BASE);
query.setParamenter(1,10000);
query.getResultList();

Convert from SQL to DQL

Can you please convert it to DQL :
SELECT molecule.cas, molecule.id_molecule, molecule.statutvlep8h, statutvlepct,
vlep8h_mg, vlepct_mg,molecule.unitevlep, prelevement.id_laboratoire
FROM thym_dev.molecule
INNER JOIN thym_dev.prelevement
WHERE molecule.id_molecule = prelevement.id_molecule
UNION ALL
SELECT molecule.cas, molecule.id_molecule, molecule.statutvlep8h, statutvlepct,
vlep8h_mg, vlepct_mg,molecule.unitevlep, analyse.id_laboratoire
FROM thym_dev.molecule
INNER JOIN thym_dev.analyse
WHERE molecule.id_molecule = analyse.id_molecule;
I get the answer :
$queryBuilder0 = "
SELECT molecule.molecule, molecule.cas, molecule.statutvlep8h,molecule.statutvlepct,molecule.vlep8hMg, molecule.vlepctMg,molecule.unitevlep,IDENTITY(prelevement.laboratoire)
FROM AppBundle:Molecule molecule
INNER JOIN AppBundle:Prelevement prelevement
WHERE prelevement.molecule= molecule.id
";
$queryBuilder1 = "
SELECT molecule.molecule , molecule.cas, molecule.statutvlep8h, molecule.statutvlepct, molecule.vlep8hMg, molecule.vlepctMg,molecule.unitevlep,IDENTITY(analyse.laboratoire)
FROM AppBundle:Molecule molecule
INNER JOIN AppBundle:Analyse analyse
WHERE analyse.molecule= molecule.id
";
$results = array_merge($this->_em->createQuery($queryBuilder0)->getResult(), $this->_em->createQuery($queryBuilder1)->getResult());

convert sql subquery with multiple joins to linq

I'm having trouble working in my subselect into LINQ. Here is the SQL followed by the LINQ. The SQL Query runs fine. The problem is incorporating the subquery. Any assistance would be appreciated:
SELECT DISTINCT
cic.CommitmentItemCategoryName + '( ' + cicType.CommitmentItemCategoryTypeName + ' )' AS displayCategory
, 'CategoryType_' + CAST(cic.CommitmentItemCategoryID AS VARCHAR(10)) AS displayCategoryID
, ISNULL(vwPAD.DollarsAllocated, 0) AS DisplayDollarsAllocated
,cic.CommitmentItemCategoryID
FROM
tblCommitmentItemCategory cic
LEFT OUTER JOIN
tblCommitmentItemCategoryType cicType ON cic.CommitmentItemCategoryTypeID = cicType.CommitmentItemCategoryTypeID
LEFT OUTER JOIN
tblAccountDirectToCommitmentItemCategory adToCIC ON adToCIC.CommitmentItemCategoryID IN (SELECT CommitmentItemCategoryID FROM tblCommitmentItemCategory)
LEFT OUTER JOIN
vw_ParentAccountDollarsAllocatedByCommitmentItemCategory vwPAD ON vwPAD.FiscalYear = 2015
AND cic.CommitmentItemCategoryID = vwPAD.CommitmentItemCategoryID
AND vwPAD.AccountDirectParentID = 19
WHERE
adToCIC.AccountDirectParentID = 19
ORDER BY
displayCategory
var queryInner = from cic in MyContext.tblCommitmentItemCategory
select new
{
cic.CommitmentItemCategoryID
};
var queryDollars = (from cic in MyContext.tblCommitmentItemCategory
join cicType in MyContext.tblCommitmentItemCategoryType
on cic.CommitmentItemCategoryTypeID equals cicType.CommitmentItemCategoryTypeID
into t2
from cicType in t2.DefaultIfEmpty()
join adToCIC in MyContext.tblAccountDirectToCommitmentItemCategory
//What goes here?
on ...
// on cic.CommitmentItemCategoryID equals adToCIC.CommitmentItemCategoryID
into t3
from adToCIC in t3.DefaultIfEmpty()
join vw in MyContext.vw_ParentAccountDollarsAllocatedByCommitmentItemCategory
on new { FiscalYear = currentFiscalYear, CommitmentItemCategory = cic.CommitmentItemCategoryID, ParentAccountID = currentParentAccountID }
equals new { FiscalYear = vw.FiscalYear, CommitmentItemCategory = vw.CommitmentItemCategoryID, ParentAccountID = vw.AccountDirectParentID }
into t
from vw in t.DefaultIfEmpty()
where adToCIC.AccountDirectParentID == currentParentAccountID
let displayCategory = cic.CommitmentItemCategoryName + " ( " + cicType.CommitmentItemCategoryTypeName + " )"
// Called CategoryType but it's actually the ID below
let displayCategoryTypeID = "CategoryType_" + cic.CommitmentItemCategoryID.ToString()
//let displayCategoryTypeID = "CategoryType!" + cic.CommitmentItemCategoryID + "_" + adToCIC.AccountDirectToCommitmentItemCategoryID.ToString()
let displayDollarsAllocated = vw.DollarsAllocated == null ? 0 : vw.DollarsAllocated
orderby cic.CommitmentItemCategoryName
select new
{
displayCategory,
displayCategoryTypeID,
cic.CommitmentItemCategoryID,
displayDollarsAllocated
}).Distinct();
Can you convert queryInner to a join? Then use that result in the larger query:
var queryInner =
from atcic in MyContext.tblAccountDirectToCommitmentItemCategory
join cic in MyContext.tblCommitmentItemCategory on atcic.CommitmentItemCategoryID equals cic.CommitmentItemCategoryID
select atcic;
And in the big query:
join adToCIC in queryInner into t3
from adToCIC in t3.DefaultIfEmpty()