Get aggregated column from query with multiple joins to single table - php

I'm struggling with retreiving data in propel 1.6.7.
Here's the sample of query I want to achieve:
select count(1) as amount, p1.local_id FROM panel_data pd
JOIN panel_data_has_code pp1 on (pd.panel_data_id = pp1.panel_data_id)
JOIN panel_code p1 on (pp1.panel_code_id = p1.panel_code_id AND p1.type='equipment' AND model_id = 'my_model_id')
JOIN panel_data_has_code pp2 on (pd.panel_data_id = pp2.panel_data_id)
JOIN panel_code p2 on (pp2.panel_code_id = p2.panel_code_id AND p2.type='model' AND p2.local_id='my_local_id')
GROUP BY p1.local_id
However whenever I try to construct proper criteria in Propel ORM, I'm having an issue - apparently propel always translate join alias to table name, whenever I try to use add join condition or use alias in select method. I've replaced multiple join condition with simple filterBy method (I always use inner joins, so effect will be the same), but I'm still having issue with retreiving groupped column (p1.local_id).
Here's the code I work with atm:
PanelDataQuery::create()
->select(array( 'p1.localId'))
->withColumn('count(1)', 'amount')
->usePanelDataHasCodeQuery('pp1')->usePanelCodeQuery('p1')->groupByLocalId()->filterByType($type)->endUse()->endUse()
->usePanelDataHasCodeQuery('pp2')->usePanelCodeQuery('p2')->filterByType('model')->filterByLocalId($model)->endUse()->endUse()
->find();
Above statement returns an error:
Unable to execute SELECT statement [SELECT count(1) AS amount, panel_code.LOCAL_ID AS \"p1.localId\" FROM panel_data INNER JOIN panel_data_has_code pp1 ON (panel_data.PANEL_DATA_ID=pp1.PANEL_DATA_ID) INNER JOIN panel_code p1 ON (pp1.PANEL_CODE_ID=p1.PANEL_CODE_ID) INNER JOIN panel_data_has_code pp2 ON (panel_data.PANEL_DATA_ID=pp2.PANEL_DATA_ID) INNER JOIN panel_code p2 ON (pp2.PANEL_CODE_ID=p2.PANEL_CODE_ID) WHERE p1.TYPE=:p1 AND p2.TYPE=:p2 AND p2.LOCAL_ID=:p3 GROUP BY p1.LOCAL_ID] [wrapped: SQLSTATE[42000]: [Microsoft][SQL Server Native Client 11.0][SQL Server]The multi-part identifier \"panel_code.LOCAL_ID\" could not be bound.]
Obviously, select clause causes the problem. Any ideas how to force propel to use table alias instead of translating it to table name?
Thank you in advance for any help.

Found partial solution:
PanelDataQuery::create()
->withColumn('p1.local_id','localId')
->withColumn('count(1)', 'amount')
->select(array( 'localId','amount'))
[...]
Seems to work fine. Altought I'd appreciate any other solutions. Still would be great how to deal with similar problem in addJoinCondition.
When i replace:
->filterByType('model')->filterByLocalId($model)
From the original query, with:
->addJoinCondition('p2', 'p2.localId = ?', $model)
->addJoinCondition('p2', "p2.type = 'model'");
I got similar issue as stated in error: propel translates p2.localId to panel_code.local_id which isn't correct (multiple panel_code table joins with aliases are included in query).

Related

MySQL query - Return consult even if one field doesn't exist in the related tables

I have this Query:
SELECT of2ab_content.id, of2ab_content.title, of2ab_content.metakey, of2ab_content.metadesc, of2ab_content.introtext, of2ab_content.fulltext AS completetext, of2ab_content.publish_up, of2ab_users.name AS author
FROM of2ab_content, of2ab_users
WHERE of2ab_content.id = 5039
AND (of2ab_users.id=of2ab_content.created_by)
The problem here is when in the field exist in of2ab_content.created_by but it does not exist on the table of2ab_users.id, then the query return empty. I need the query to return the rest of the fields if the author does not exist in the users table.
Any suggest?
You want a left join. Simple rule: Never use commas in the FROM clause; always use explicit join syntax.
SELECT c.id, c.title, c.metakey, c.metadesc, of2ab_content.introtext,
c.fulltext AS completetext, c.publish_up, u.name AS author
FROM of2ab_content c LEFT JOIN
of2ab_users u
ON u.id = c.created_by
WHERE c.id = 5039;
Note that the use of table aliases always makes the query easier to write and to read.

How do I select specific columns on table join in propel?

I need to select specific set of columns from both the table using propel orm 2.0.0. The equivalent query is as below
select b.name as brand_name, b.grade, d.name as dealer_name, d.number
from brand as b join dealer as d
on d.id = b.dealer_id;
I am struggling where the necessary columns on both the tables have same name but need to join using different column.
Help me with the propel php code and also with proper reference site. The document at official site is not a good tutorial.
This should work, provided you have correctly defined your models.
$rows = BrandQuery::create()
->select(['name', 'grade'])
->joinWith('dealer')
->withColumn('dealer.name', 'dealer_name')
->withColumn('dealer.number')
->find();

Cross Join to DQL

I'm trying to convert this I think simple mysql query into Doctrine dql, however, Im experience quite a struggle right now...
SELECT (c.prix-aggregates.AVG) AS test
FROM immobilier_ad_blank c
CROSS JOIN (
SELECT AVG(prix) AS AVG
FROM immobilier_ad_blank)
AS aggregates
Purpose of this: creating z-score.
Original implementation coming from this question Calculating Z-Score for each row in MySQL? (simple)
I thought about creating an association within the entity, but I mean its not necessary, its only for stats.
Edit: Btw, I dont wanna use raw SQL, I will extract the "subquery" from another query builder expression using getDQL. Otherwise, I will have to rewrite my dynamic query builder to take in account for rawSQL.
Edit 2:
Tried this
$subQb = $this->_em->createQueryBuilder();
$subQb->addSelect("AVG(subC.prix) as AMEAN")
->from("MomoaIntegrationBundle:sources\Common", "subC");
$subDql = $subQb->getDQL();
$dql = "SELECT c.prix FROM MomoaIntegrationBundle:sources\Common c INNER JOIN ($subDql) AS aggregates";
Raw dql is:
SELECT c.prix FROM MomoaIntegrationBundle:sources\Common c INNER JOIN (SELECT AVG(subC.prix) as AMEAN FROM MomoaIntegrationBundle:sources\Common subC) AS aggregates
Getting this strange error:line 0, col 70 near '(SELECT AVG(subC.prix)': Error: Class '(' is not defined.
Edit 3:
I found kinda of a hawkish way to make it work but doctrine is stubborn with its implementation of entities and such and forgot that STATISTICS do NOT need ENTITIES !
$subQb = $this->_em->createQueryBuilder();
$subQb->addSelect("AVG(subC.prix) as AMEAN")
->from("MomoaIntegrationBundle:sources\Common", "subC");
$sql = "SELECT (c.prix-aggregates.sclr_0) AS test FROM immobilier_ad_blank c CROSS JOIN "
. "({$subQb->getQuery()->getSQL()}) AS aggregates";
$stm = $stm = $this->_em->getConnection()->prepare($sql);
$stm->execute();
$data = $stm->fetchAll();
If you have a better solution, Im all ears ! I actually dislike this solution.
Starting with Doctrine 2.4 it is possible to JOIN without using a defined association, for example:
SELECT u FROM User u JOIN Items i WITH u.age = i.price
This one doesn't make any sense but you get the point. The WITH keyword is absolutely required in this case, otherwise it is a syntax error, but you can just provide a dummy condition, like so:
SELECT u FROM User u JOIN Items i WITH 0 = 0
This essentially results in a cross join. Whether this is a good idea in a given situation is a different question, but I have encountered situations where this was indeed very useful.
For complex queries you might want to consider bypassing DQL and using a native query - especially since you don't need the result in an entity.
$connection = $em->getConnection();
$statement = $connection->prepare("
select c.prix-aggregates, t1.avg
from immobilier_ad_blank
cross join (
select avg(prix) as avg
from immobilier_ad_blank
) t1
");
$statement->execute();
$results = $statement->fetchAll();

How can I create a MySQL query to include all of this information?

I am creating a report and I need to be able to create a query(s) to pull the information below into a report. Essentially here's what I want listed:
ship.name
personnel.first_name
personnel.last_name
crew_position_title.title
personnel_next_of_kin.next_of_kin_relation
personnel_next_of_kin.next_of_kin_first_name
personnel_next_of_kin.next_of_kin_last_name
personnel_next_of_kin.next_of_kin_telephone
personnel_next_of_kin.next_of_kin_alt_telephone
personnel_next_of_kin.other_kin_relation
personnel_next_of_kin.other_kin_first_name
personnel_next_of_kin.other_kind_last_name
personnel_next_of_kin.other_kin_telephone
personnel_next_of_kin.other_kin_alt_telephone
The only condition would be WHERE personnel.currently_serving_ship_id IS NOT NULL on the personnel table.
How would I go about creating a query to give me the data I need? I have tried using JOIN but I don't have much experience with them.
Below is the ERD of the tables I need data from with fields of interest highlighted:
How about something like?
SELECT s.name, p.first_name, p.last_name, c.title, pnk.next_of_kin_relation,
pnk.next_of_kin_first_name, pnk.next_of_kin_last_name, pnk.next_of_kin_telephone,
pnk.next_of_kin_alt_telephone, pnk.other_kin_relation, pnk.other_kin_first_name,
pnk.other_kin_last_name, pnk.other_kin_telephone, pnk.other_kin_alt_telephone
FROM personnel p
LEFT JOIN personnel_next_of_kin pnk ON pnk.personnel_id = p.personnel_id
LEFT JOIN ship s ON s.ship_id = p.currently_serving_ship_id
LEFT JOIN personnel_key_info pk ON pk.personnel_id = p.personnel_id
LEFT JOIN crew_position_title c ON c.crew_pos_id = p.personnel_id
WHERE p.currently_serving_ship_id IS NOT NULL
This is the long version of the query. I am not really sure about this: LEFT JOIN crew_position_title c ON c.crew_pos_id = p.personnel_id. I can't tell what key should be used there, can't figure out using the naming convention.
Query was not tested but you can give it a shot and fix the syntax issue if there are any.

How can I create sub query i have already LEFT JOIN in my first query

Good Day I would like t ask if what seem to be the problem with my SQL command??
the error I've got was #1054 - Unknown column 'imaster_tbl.id' in 'field list'
i think it is because I put 't1' after imaster_tbl after the FROM keyword
can you please help me with this problem.. here's my SQL Command:
SELECT imaster_tbl.id, imaster_tbl.die_name, imaster_tbl.part_name,
imaster_tbl.drawing_number, imaster_tbl.drawing_part_number,
imaster_tbl.sub_letter,imaster_tbl.specs, imaster_tbl.file_path,
idrawing_type_tbl.drawing_type, idie_type_tbl.die_type, irevision_tbl.revision,
irelay_type_tbl.relay_type FROM imaster_tbl t1
LEFT JOIN idrawing_type_tbl ON imaster_tbl.drawing_type_id=idrawing_type_tbl.drawing_type_id
LEFT JOIN idie_type_tbl ON imaster_tbl.die_type_id = idie_type_tbl.die_type_id
LEFT JOIN irelay_type_tbl ON imaster_tbl.relay_type_id=irelay_type_tbl.relay_type_id
LEFT JOIN irevision_tbl ON imaster_tbl.revision_id = irevision_tbl.revision_id
WHERE revision = (SELECT MAX(revision) FROM imaster_tbl t2 WHERE t2.drawing_part_number = t1.drawing_part_number)
but this one works for me, without LEFT JOIN.
select * from table t1 where revision = (select max(revision) from table t2 where t2.filename = t1.filename)
thanks a lot.
The error states that the server cant find a specific field. It's a bit difficult to say if the field really exists, since you do not post your table definitions. But asuming it does exist you only have to replace imaster_tbl with t1 in you select part of the query.
When you are writing "imaster_tbl t1" in the FROM part you are creating an alias of that table, and need to use the alias to reference fields in that table.
Alias are usefull in e.g. when you want easier readability of the code, when creating temporary tables or when running the same table more than once, and need to identify how they connect.
I've updated your SQL below
SELECT
t1.id,
t1.die_name,
t1.part_name,
t1.drawing_number,
t1.drawing_part_number,
t1.sub_letter,
t1.specs,
t1.file_path,
idrawing_type_tbl.drawing_type,
idie_type_tbl.die_type,
irevision_tbl.revision,
irelay_type_tbl.relay_type
FROM
imaster_tbl t1
LEFT JOIN idrawing_type_tbl ON
master_tbl.drawing_type_id=idrawing_type_tbl.drawing_type_id
LEFT JOIN idie_type_tbl ON
imaster_tbl.die_type_id = idie_type_tbl.die_type_id
LEFT JOIN irelay_type_tbl ON
imaster_tbl.relay_type_id=irelay_type_tbl.relay_type_id
LEFT JOIN irevision_tbl ON
imaster_tbl.revision_id = irevision_tbl.revision_id
WHERE
revision = (
SELECT
MAX(revision)
FROM
imaster_tbl t2
WHERE
t2.drawing_part_number = t1.drawing_part_number
)
In your FROM cluase, you have defined alias t1 for imaster_tbl as FROM imaster_tbl t1 and in the query you are using imaster_tbl to refer to this table/view. You should use the alias name once you declare the alias.

Categories