I have built the following query with the Doctrine Query Builder in my Symfony application.
$qb->select('c')
->from('AppBundle:Course', 'c')
->join('AppBundle:Log', 'a', Expr\Join::WITH, $qb->expr()->eq('c.id', 'a.course'))
->where($qb->expr()->in('a.type', ':type'))
->andWhere($qb->expr()->between('a.time', ':start', ':end'))
->andWhere($qb->expr()->eq('c.status', ':status'))
->setParameter(':type', ['opened'])
->setParameter(':standardScratchScore', [74])
->setParameter(':status', Course::OPENED)
->setParameter(':start', $dateFrom->format('Y-m-d H:i:s'))
->setParameter(':end', $dateTo->format('Y-m-d H:i:s'))
;
In my code I iterate over the Courses and then again query the Log table to check that an entry with a specific type doesn't exist for the Course. Is there a way I can incorporate the exclusion of log.type = 'log.sent-email' for this Course into this initial query, without using something like a sub-select?
Querying the same table again within the loop feels sub-optimal to me and NewRelic suggests it is hurting the performance of my application.
Well you can always join the table one more time for this specific need:
$qb->select('c')
->from('AppBundle:Course', 'c')
->join('AppBundle:Log', 'a', Expr\Join::WITH, $qb->expr()->eq('c.id', 'a.course'))
->leftjoin(
'AppBundle:Log',
'b',
Expr\Join::WITH,
$qb->expr()->andx(
$qb->expr()->eq('c.id', 'b.course'),
$qb->expr()->eq('b.type', 'log.sent-email')
))
) // join log a second time, with the type condition
->where($qb->expr()->in('a.type', ':type'))
->andWhere($qb->expr()->between('a.time', ':start', ':end'))
->andWhere($qb->expr()->eq('c.status', ':status'))
->andWhere($qb->expr()->isNull('b.type')) // Only select records where no log record is found
->setParameter(':type', ['opened'])
->setParameter(':standardScratchScore', [74])
->setParameter(':status', Course::OPENED)
->setParameter(':start', $dateFrom->format('Y-m-d H:i:s'))
->setParameter(':end', $dateTo->format('Y-m-d H:i:s'))
;
Related
I have to retrieve this data from 2 different databases within the same instance
For which I put that same SQL statement in my code
public int ImportarUTEs()
{
try
{
int registrosAñadidos = 0;
var registrosSAP = _contextSAP.Licitadores
.FromSqlRaw(#"select distinct ot.IDLICITADOR as IdLicitador,
l.cardcode as CodigoSAP,
ic.cardname as Nombre
from ofertantes ot INNER JOIN licitadores l on ot.idlicitador=l.idlicitador
inner join ofertas o on o.codigoanalizada=ot.codigoanalizada
inner join Fulcrum.dbo.OCRD ic on l.cardcode=ic.cardcode collate SQL_Latin1_General_CP1_CI_AS
where year(o.fechapres)>=2015 AND
ot.idlicitador in(
select IDLICITADOR from LICITADORES
GROUP by IDLICITADOR
HAVING COUNT(*)>1
)
order by IdLicitador, CodigoSAP")
.ToList();
But what is my surprise when I see the result obtained
When you have to obtain the 2 records corresponding to LicitasorID 2368, I see that I get 3 records where [8] repeats the value of [6] and instead of being the value corresponding to LicitadorID 2881 and CodigoSAP 430FULCRUM, it assigns the value LicitadorID 2368. But the strangest thing is that when it is time to collect the values of IdLicitador 3150 it turns out that it does the same thing, IdLicitador 3150 and CodigoSAP 430FULCRUM the [10 ] turns it into IdLicitador 2368 and CodigoSAP 430FULCRUM.
That is, for some reason that I can't understand the value obtained in the EF Core 5 project is not the same as the one obtained in the SQL Server instance and I can't think of what to do about it
Any idea, please?
Thanks
The problem was to define the primary key in LicitadoresSAP entity
modelBuilder.Entity<LicitadorSAP>()
.HasKey(c => new { c.IdLicitador, c.CodigoSAP });
Now works fine
Is it possible to build nested SELECT statements like the one below using the DBAL QueryBuilder?
SELECT i.id, i.stable_id, i.version, i.title
FROM initiatives AS i
INNER JOIN (
SELECT stable_id, MAX(version) AS max_version FROM initiatives GROUP BY stable_id
) AS tbl1
ON i.stable_id = tbl1.stable_id AND i.version = tbl1.max_version
ORDER BY i.stable_id ASC
The goal is to query an external non TYPO3 table which contains different versions of each data set. Only the data set with the highest version number should be rendered. The database looks like this:
id, stable_id, version, [rest of the data row]
stable_id is the external id of the data set. id is the internal autoincrement id. And version is also incremented automatically.
Code example:
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
$result = $queryBuilder
->select(...$this->select)
->from($this->table)
->join(
'initiatives',
$queryBuilder
->select('stable_id, MAX(version) AS max_version' )
->from('initiatives')
->groupBy('stable_id'),
'tbl1',
$queryBuilder->and(
$queryBuilder->expr()->eq(
'initiatives.stable_id',
$queryBuilder->quoteIdentifier('tbl1.stable_id')
),
$queryBuilder->expr()->eq(
'initiatives.version',
$queryBuilder->quoteIdentifier('tbl1.max_version')
)
)
)
->orderBy('stable_id', 'DESC')
I cannot figure out the correct syntax for the ON ... AND statement. Any idea?
Extbase queries have JOIN capabilities but are otherwise very limited. You could use custom SQL (see ->statement() here), though.
A better API to build complex queries is the (Doctrine DBAL) QueryBuilder, including support for JOINs, database functions like MAX() and raw expressions (->addSelectLiteral()). Make sure to read until the ExpressionBuilder where it gets interesting.
So Extbase queries are useful in order to retrieve Extbase (model) objects. It can make implicit use of its knowledge of your data structure in order to save you some code but only supports rather simple queries.
The (Doctrine DBAL) QueryBuilder fulfills all other needs. If needed, you can convert the raw data to Extbase models, too. (for example $propertyMapper->convert($data, Job::class)).
I realize that we lack clear distinguishing between the two because they were both known at some time as "QueryBuilder", but they are totally different. That's why I like to add "Doctrine" when referring to the non-Extbase one.
An example with a JOIN ON multiple criteria.
$q = TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(TYPO3\CMS\Core\Database\ConnectionPool::class)
->getQueryBuilderForTable('fe_users');
$res = $q->select('*')
->from('tt_content', 'c')
->join(
'c',
'be_users',
'bu',
$q->expr()->andX(
$q->expr()->eq(
'c.cruser_id', $q->quoteIdentifier('bu.uid')
),
$q->expr()->comparison(
'2', '=', '2'
)
)
)
->setMaxResults(5)
->execute()
->fetchAllAssociative();
Short answer: it is not possible because the table to be joined in is generated on the fly. The related expression is back-ticked and thus causes an SQL error.
But: The SQL query can be changed to the following SQL query which does basically the same:
SELECT i1.id,stable_id, version, title, p.name, l.name, s.name
FROM initiatives i1
WHERE version = (
SELECT MAX(i2.version)
FROM initiatives i2
WHERE i1.stable_id = i2.stable_id
)
ORDER BY stable_id ASC
And this can be rebuild with the DBAL queryBuilder:
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
$result = $queryBuilder
->select(...$this->select)
->from($this->table)
->where(
$queryBuilder->expr()->eq(
'initiatives.version',
'(SELECT MAX(i2.version) FROM initiatives i2 WHERE initiatives.stable_id = i2.stable_id)'
),
->orderBy('stable_id', 'DESC')
->setMaxResults( 50 )
->execute();
I have the following select statement in ABAP:
SELECT munic~mandt VREFER BIS AB ZZELECDATE ZZCERTDATE CONSYEAR ZDIMO ZZONE_M ZZONE_T USAGE_M USAGE_T M2MC M2MT M2RET EXEMPTMCMT EXEMPRET CHARGEMCMT
INTO corresponding fields of table GT_INSTMUNIC_F
FROM ZCI00_INSTMUNIC AS MUNIC
INNER JOIN EVER AS EV on
MUNIC~POD = EV~VREFER(9).
"where EV~BSTATUS = '14' or EV~BSTATUS = '32'.
My problem with the above statement is that does not recognize the substring/offset operation on the 'ON' clause. If i remove the '(9) then
it recognizes the field, otherwise it gives error:
Field ev~refer is unknown. It is neither in one of the specified tables
nor defined by a "DATA" statement. I have also tried doing something similar in the 'Where' clause, receiving a similar error:
LOOP AT gt_instmunic.
clear wa_gt_instmunic_f.
wa_gt_instmunic_f-mandt = gt_instmunic-mandt.
wa_gt_instmunic_f-bis = gt_instmunic-bis.
wa_gt_instmunic_f-ab = gt_instmunic-ab.
wa_gt_instmunic_f-zzelecdate = gt_instmunic-zzelecdate.
wa_gt_instmunic_f-ZZCERTDATE = gt_instmunic-ZZCERTDATE.
wa_gt_instmunic_f-CONSYEAR = gt_instmunic-CONSYEAR.
wa_gt_instmunic_f-ZDIMO = gt_instmunic-ZDIMO.
wa_gt_instmunic_f-ZZONE_M = gt_instmunic-ZZONE_M.
wa_gt_instmunic_f-ZZONE_T = gt_instmunic-ZZONE_T.
wa_gt_instmunic_f-USAGE_M = gt_instmunic-USAGE_M.
wa_gt_instmunic_f-USAGE_T = gt_instmunic-USAGE_T.
temp_pod = gt_instmunic-pod.
SELECT vrefer
FROM ever
INTO wa_gt_instmunic_f-vrefer
WHERE ( vrefer(9) LIKE temp_pod ). " PROBLEM WITH SUBSTRING
"AND ( BSTATUS = '14' OR BSTATUS = '32' ).
ENDSELECT.
WRITE: / sy-dbcnt.
WRITE: / 'wa is: ', wa_gt_instmunic_f.
WRITE: / 'wa-ever is: ', wa_gt_instmunic_f-vrefer.
APPEND wa_gt_instmunic_f TO gt_instmunic_f.
WRITE: / wa_gt_instmunic_f-vrefer.
ENDLOOP.
itab_size = lines( gt_instmunic_f ).
WRITE: / 'Internal table populated with', itab_size, ' lines'.
The basic task i want to implement is to modify a specific field on one table,
pulling values from another. They have a common field ( pod = vrefer(9) ). Thanks in advance for your time.
If you are on a late enough NetWeaver version, it works on 7.51, you can use the OpenSQL function LEFT or SUBSTRING. Your query would look something like:
SELECT munic~mandt VREFER BIS AB ZZELECDATE ZZCERTDATE CONSYEAR ZDIMO ZZONE_M ZZONE_T USAGE_M USAGE_T M2MC M2MT M2RET EXEMPTMCMT EXEMPRET CHARGEMCMT
FROM ZCI00_INSTMUNIC AS MUNIC
INNER JOIN ever AS ev
ON MUNIC~POD EQ LEFT( EV~VREFER, 9 )
INTO corresponding fields of table GT_INSTMUNIC_F.
Note that the INTO clause needs to move to the end of the command as well.
field(9) is a subset operation that is processed by the ABAP environment and can not be translated into a database-level SQL statement (at least not at the moment, but I'd be surprised if it ever will be). Your best bet is either to select the datasets separately and merge them manually (if both are approximately equally large) or pre-select one and use a FAE/IN clause.
They have a common field ( pod = vrefer(9) )
This is a wrong assumption, because they both are not fields, but a field an other thing.
If you really need to do that task through SQL, I'll suggest you to check native SQL sentences like SUBSTRING and check if you can manage to use them within an EXEC_SQL or (better) the CL_SQL* classes.
I am fairly new to rails. I have a rails Model 'Message' with: 'belongs_to :sender' and 'belongs_to :receiver' relations.
I am trying to create a message thread between two users: 'current_user' and 'params'.
In the show controller action of the MessagesController, I want to use the equivalent of this sql query:
Message.find_by_sql(
"SELECT *
FROM messages
WHERE
(sender_id = #{current_user.id} OR sender_id = #{params[:id]})
AND
(receiver_id = #{current_user.id} OR receiver_id = #{params[:id]});"
)
If I where looking for one Message I would use this Activerecord queryto prevent SQL injection:
Message.where('sender_id = ? OR receiver_id = ?', current_user.id, current_user.id).find(params[:id])
My current query is:
Message.where(sender_id: [current_user.id, params[:id]], receiver_id: [current_user.id, params[:id]])
Is this query currently guarded against SQL injection?
it's safe. the final query would be something like sender_id IN (1, 2) AND receiver_id IN (3, 4) and all integer values are sanitized. You can simply run tests:
Message.where(sender_id: [current_user.id, "' is dangerous"], receiver_id: [current_user.id, params[:id]])
and see raw SQL output in console. illegal integers should be converted to 0.
Kindly helping in converting native query ti JPQL query for multiple views with CASE condition and join statements.Table c1 and c3 are views. I am trying the get the current and pending information from c1.
Please find the query mentioned below
SELECT c3.eqip_id AS EQIP_ID,
CASE WHEN c1.inst_ts IS NULL OR c1.sent_ts > c1.inst_ts THEN c1.ver_nm END AS PEND,
CASE WHEN c1.sent_ts IS NULL OR c1.sent_ts > c1.inst_ts THEN c1.ver_nm END AS CURRENT,
c1.trm_ver_hist_id AS TRM_VER_HIST_ID
FROM trm_ver_hist_vw c1
JOIN(SELECT Max(trm_ver_hist_id) AS TRM_VER_HIST_ID, dvc_id, status
FROM trm_ver_hist_vw
WHERE ver_typ_id = 1 AND status IN( 'C', 'P' )
GROUP BY dvc_id, status) c2
ON c1.trm_ver_hist_id = c2.trm_ver_hist_id
JOIN trm_dtl_vw c3 ON c1.dvc_id = c3.trm_id
WHERE c3.co_actv_ind = 'Y' AND c3.mach_hdwr_asscn_ind = 'Y' AND pin = 'ABC'
Can anyone please help me to make this query in JPA/JPQL?
It seems very complex and data specific. I would recommend using a native SQL query.
The JPA spec does not allow selects in the FROM clause, although EclipseLink does have some support for this.
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/JPQL#Sub-selects_in_FROM_clause