Doctrine group data - sql

I would like to group doctrine data using the most performatic way. In this following query I need to create an object (or array) that returns the following SiteBundle:DJ with their childs SiteBundle:HJ followed by WHERE filters correctly. I am not sure if I need to use sub-query or group by clause, but I am using the following query:
$sql = ' SELECT dj FROM SiteBundle:DJ dj '
. ' LEFT JOIN SiteBundle:HJ hj WITH dj.id = hj.date '
. ' LEFT JOIN SiteBundle:Job job WITH job.id = dj.job '
. ' LEFT JOIN SiteBundle:Dia d WITH d.id = dj.dia '
. ' WHERE job.active = 1 and job.id = :job '
. ' AND (hj.hour BETWEEN :ini and :fim) AND (d.data >= :now)'
. ' GROUP BY dj.id, hj.id, d.data ORDER BY d.data ASC';
Returns:
array:2 [▼
0 => DJ {#1584 ▶}
1 => DJ {#1580 ▶}
]
$dj->getHJ() returns all the SiteBundle:HJ related to this DJ, but I need only the ones I've filtered in where clause.
How to group them?

what you expected to happen is actually a bad idea in the global context.
doctrine is first and foremost about correctness. even though you filter something in your query (and don't select it), doctrine will provide the full collection when you (essentially) call $object->getCollection() because it's the correct collection for that object. queries of the past don't really matter here.
However, the persistent collection you usually get from doctrine for relations can be filtered: https://symfonycasts.com/screencast/doctrine-relations/collection-criteria
(however, your filter might not be representable by the options it provides)
or you filter the collection manually, i.e. write a new function for that entity that returns a filtered collection.

You have a ";" at the end of the where clause, remove it and re-try.

Related

How to write an Open SQL statement with substring in the JOIN ON condition? [duplicate]

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.

SQL query with "as" keyword

I have a below SQL query running in one of my project. I am struggling to understand the "as" concept here. In the result "user_key" and "user_all" are appearing as empty. Where as at the front end "user_all" is the combination of "rx.ord_by_userid" + "rx.ord_by_inst_id,"
SELECT rx.rx_id,
rx.pt_visit_id,
rx.pt_id,
pt_visit.date_time_sch,
' ' as print_dea_ind,
' ' as phys_rx_label,
rx.ord_by_userid,
rx.ord_by_inst_id,
' ' as user_key,
pt_visit.visit_inst_id,
' ' as user_all,
' ' as tp_agt_ind,
FROM rx LEFT OUTER JOIN tx_pln ON rx.tp_name = tx_pln.tp_name AND rx.tp_vers_no = tx_pln.tp_vers_no, pt_visit
WHERE ( pt_visit.pt_visit_id = rx.pt_visit_id ) and
( pt_visit.pt_id = rx.pt_id ) and
( ( rx.pt_id = :pt_id ) and
( rx.rx_id = :rx_id ) )
Thanks.
I think when they query database, they need two fields called "user_key" and "user_all" with empty value for some purpose. However, in the front end, they need to display column "user_all" with the combination of "rx.ord_by_userid" + "rx.ord_by_inst_id" because of business rule.
The meaning of "AS" is just setting the alias of any field which is needed to have a new name. In this situation, new columns "user_key" and "user_all" are set with empty value.
AS just provides the field in the data set a name, or in SQL terms, an alias. In PB, this is usually done so that the DataWindow gives it a consistent, easy name. That is all that AS does.
The other part of your mystery is how these get populated with non-blank values. You were assuming this was done in the SQL with AS, but we can assure you that is not the case. Most likely, this value is being set in a script that fires in the client after the Retrieve() (if I were to bet, I'd bet a script on the DataWindow control, maybe RetrieveRow or RetrieveEnd).

Failed to annotate a left join query in django 1.8

I try to a new field praise_cnt to 'Store' in django 1.8 but failed. Here is my code.
I've two models:
class Store(models.Model):
...
class Works(models.Model):
store = models.ForeignKey(Store)
...
The query is :
sql = 'select store.*, sum(works.praise_cnt) as praise_cnt from store left join works on store.id = works.store_id ' \
'where store.is_active=1 and store.audit_status=1 ' \
'group by store.id order by praise_cnt desc limit %d,%d' %(offset, rows)
store_list = Store.objects.raw(sql)
for store in store_list:
print store.praise_cnt
The sql is right but the value of store is always 'None'. So how to add a praise_cnt field to store in this case? Thanks
UPDATE: I solve this issue by myself. I replaced 'sum(works.praise_cnt) as praise_cnt' with 'sum(works.praise_cnt) as cnt' and it works. I seems that django doesn't support annotate a new field with same name.

Zend_Db_Select with 'FOR XML PATH' for SQL Server

I'm trying to code the following query using Zend_Db_Select:
SELECT p1.SKU,
(
SELECT ',' + Status
FROM "Products" "p2"
WHERE p2.SKU = p1.SKU
ORDER BY "Status"
FOR XML PATH ('')
) AS "Statuses"
FROM "Products" p1
GROUP BY SKU
This is what I have so far:
$s1 = $products->select()
->setIntegrityCheck(false)
->from(array('p2' => 'Products'),
new Zend_Db_Expr("',' + Status")
)
->where('p2.SKU = p1.SKU')
->order('Status');
$s2 = $products->select()
->from(array('p1' => 'Products'),
array('p1.SKU',
'Statuses' => new Zend_Db_Expr('(' . $s1 . ')')
)
)
->group('SKU');
echo $s2;
$dbRowSet = $Products->fetchAll($s2);
That gives me this:
SELECT "p1"."SKU",
(
SELECT ',' + Status
FROM "Products" AS "p2"
WHERE (p2.SKU = p1.SKU)
ORDER BY "Status" ASC
) AS "Statuses"
FROM "Products" AS "p1"
GROUP BY "SKU"
I can't figure out how to get the required FOR XML PATH ('').
Also, isn't using the . operator with $s1 calling __toString(), instead of leaving it as a native Zend_Db_Select object. Is there any other way to get the parens around $s1?
Alternatively, is there another way to do this whole query? I want to return each SKU and a concatenated grouping of all Statuses (a la GROUP_CONCAT() in MySQL). The table is huge, so iterating over them in PHP takes an unacceptably long time.
Unfortunately Zend Framework does not have a great support for constructing MS SQL specific queries. What you could do is use Zend_Db_Adapter_Abstract::query() and skip the object oriented query abstraction altogether. Alternatively, you could extend the Zend_Db_Select, add the appropriate code to Zend_Db_Select::$_parts and Zend_Db_Select::_render*, however you would still have an incomplete support.
I don't quite understand what exactly are you doing in the second code example, since the $2 variable is not assigned at all.
Don't worry about the __toString() being called when you use . for string construction; the expression will ultimately be subjected to string conversion either way.
Looks like I was close, and with KSiimson's comments about string conversion in mind, this works:
$s1 = $products->select()
->setIntegrityCheck(false)
->from(array('p2' => 'Products'),
new Zend_Db_Expr("',' + Status")
)
->where('p2.SKU = p1.SKU')
->order('Status');
$s2 = $products->select()
->from(array('p1' => 'Products'),
array('p1.SKU',
'Statuses' => new Zend_Db_Expr('(' . $s1 .
" FOR XML PATH(''))")
)
)
->group('SKU');
echo $s2;
$dbRowSet = $Products->fetchAll($s2);
This just concats the FOR XML PATH clause with the first query as a string. Not quite as elegant as I was hoping for, but "perfect is the enemy of good".

naming columns in excel with Complex sql

I’m trying to run this SQL using get external.
It works, but when I try to rename the sub-queries or anything for that matter it remove it.
I tried as, as and the name in '', as then the name in "",
and the same with space. What is the right way to do that?
Relevant SQL:
SELECT list_name, app_name,
(SELECT fname + ' ' + lname
FROM dbo.d_agent_define map
WHERE map.agent_id = tac.agent_id) as agent_login,
input, CONVERT(varchar,DATEADD(ss,TAC_BEG_tstamp,'01/01/1970'))
FROM dbo.maps_report_list list
JOIN dbo.report_tac_agent tac ON (tac.list_id = list.list_id)
WHERE input = 'SYS_ERR'
AND app_name = 'CHARLOTT'
AND convert(VARCHAR,DATEADD(ss,day_tstamp,'01/01/1970'),101) = '09/10/2008'
AND list_name LIKE 'NRBAD%'
ORDER BY agent_login,CONVERT(VARCHAR,DATEADD(ss,TAC_BEG_tstamp,'01/01/1970'))
You could get rid of your dbo.d_agent_define subquery and just add in a join to the agent define table.
Would this code work?
select list_name, app_name,
map.fname + ' ' + map.lname as agent_login,
input,
convert(varchar,dateadd(ss,TAC_BEG_tstamp,'01/01/1970')) as tac_seconds
from dbo.maps_report_list list
join dbo.report_tac_agent tac
on (tac.list_id = list.list_id)
join dbo.d_agent_define map
on (map.agent_id = tac.agent_id)
where input = 'SYS_ERR'
and app_name = 'CHARLOTT'
and convert(varchar,dateadd(ss,day_tstamp,'01/01/1970'),101) = '09/10/2008'
and list_name LIKE 'NRBAD%'
order by agent_login,convert(varchar,dateadd(ss,TAC_BEG_tstamp,'01/01/1970'))
Note that I named your dateadd column because it did not have a name. I also tried to keep your convention of how you do a join. There are a few things that I would do different with this query to make it more readable, but I only focused on getting rid of the subquery problem.
I did not do this, but I would recommend that you qualify all of your columns with the table from which you are getting them.
To remove the sub query in the SELECT statement I suggest the following:
SELECT list_name, app_name, map.fname + ' ' + map.lname as agent_login, input, convert(varchar,dateadd(ss, TAC_BEG_tstamp, '01/01/1970))
FROM dbo.maps_report_list inner join
(dbo.report_tac_agent as tac inner join dbo.d_agent_define as map ON (tac.agent_id=map.agent_id)) ON list.list_id = tac.list_id
WHERE input = 'SYS_ERR' and app_name = 'CHARLOTT' and convert(varchar,dateadd(ss,day_tstamp,'01/01/1970'),101) = '09/10/2008'
and list_name LIKE 'NRBAD%' order by agent_login,convert(varchar,dateadd(ss,TAC_BEG_tstamp,'01/01/1970'))
I used parentheses to create the inner join between dbo.report_tac_agent and dbo.d_agent_define first. This is now a set of join data.
The combination of those tables are then joined to your list table, which I am assuming is the driving table here. If I am understand what you are trying to do with your sub select, this should work for you.
As stated by the other poster you should use table names on your columns (e.g. map.fname), it just makes things easy to understand. I didn't in my example because I am note 100% sure which columns go with which tables. Please let me know if this doesn't do it for you and how the data it returns is wrong. That will make it easier to solve in needed.