Propel ORM - Joining unrelated tables - php

How does this SQL statement translate into Propel (1.6.3)?
SELECT * FROM table_a JOIN table_b
With tableA and tableB sharing no Foreign Keys and having no relationships defined.
TableAQuery::create()->join('tableB')
doesn't work since Propel complains with an error:
"Fatal error: Uncaught exception 'PropelException' with message 'Unknown relation TableB on the TableA table'
Thanks very much in advance for any help and hints! This is my first post here and I hope I haven't done anything wrong yet :-) (I've searched thoroughly before I posted!)

You could also use "addJoin" like this:
TableAQuery::create()
->addJoin(TableAPeer::ThisCOLUMN, TableBPeer::ThatCOLUMN, Criteria::INNER_JOIN); //Can also be left/right
The third argument also takes left and right join.
And, instead of the usual "filterByXXX()"
->filterByOtherColumn(value)
you'd use "add()", like this:
->add(TableAPeer::OtherCOLUMN, value)

You can work around this limitation by using raw SQL syntax. For instance:
$con = Propel::getConnection(SomePeer::DATABASE_NAME);
$query = 'SELECT * FROM `table_a` JOIN `table_b` LIMIT 10';
$stmt = $con->prepare($query);
if($stmt->execute()) {
$res = $stmt->fetchAll();
var_dump($res);
}
Note #1: These kind of joins can become very big and quickly exhaust the allowed memory size. That's why I've added a LIMIT.
Note #2: The output isn't very clean, arrays of both numeric and associative keys. Maybe there are ways to improve this.

Related

How to optimize long query that displays thousands of data

I have almost thousands of data to display for my reports and it makes my browser lags due to the heavy data. I think that my query is the real problem. How can I optimized my query? is there something that I should add in my query?
I am using Xampp which supports PHP7.
SELECT
`payroll_billed_units`.`allotment_code`,
`payroll_billed_units`.`category_name`,
`payroll_billed_units`.`ntp_number`,
`payroll_billed_units`.`activity`,
`payroll_billed_units`.`regular_labor`,
`payroll_sub`.`block_number`,
(SELECT
GROUP_CONCAT(DISTINCT `lot_number` SEPARATOR ', ')
FROM
`payroll_billed_units` `lot_numbers`
WHERE
`lot_numbers`.`allotment_code` = `payroll_billed_units`.`allotment_code`
AND `lot_numbers`.`category_name` = `payroll_billed_units`.`category_name`
AND `lot_numbers`.`ntp_number` = `payroll_billed_units`.`ntp_number`
AND `lot_numbers`.`activity` = `payroll_billed_units`.`activity`) AS `lot_numbers`,
(SELECT
COUNT(`billed`.`ntp_id`)
FROM
`regular_ntp` `billed`
WHERE
`billed`.`allotment_code` = `payroll_billed_units`.`allotment_code`
AND `billed`.`category_name` = `payroll_billed_units`.`category_name`
AND `billed`.`ntp_number` = `payroll_billed_units`.`ntp_number`
AND `billed`.`activity` = `payroll_billed_units`.`activity`) AS `billed`,
(SELECT
COUNT(`approved`.`id`)
FROM
`payroll_billed_units` `approved`
WHERE
`approved`.`allotment_code` = `payroll_billed_units`.`allotment_code`
AND `approved`.`category_name` = `payroll_billed_units`.`category_name`
AND `approved`.`ntp_number` = `payroll_billed_units`.`ntp_number`
AND `approved`.`activity` = `payroll_billed_units`.`activity`) AS `approved`
FROM
`payroll_billed_units`
JOIN payroll_transaction ON payroll_billed_units.billing_number =
payroll_transaction.billing_number
JOIN payroll_sub ON payroll_transaction.billing_number =
payroll_sub.billing_number
WHERE payroll_billed_units.billing_date = '2019-02-13'
AND payroll_transaction.contractor_name = 'Roy Codal' GROUP BY allotment_code, category_name, activity
I was expecting that it will load or display all my data.
The biggest problem are the dependendt sub-selects, they are responsible for a bad performance. A sub-select will be executed for EVERY ROW of the outer query. And if you cascade subs-selects, you'll quickly have a query run forever.
If any of the parts would yield only 5 resultsets, 3 sub-select would mean that the database has to run 625 queries (5^4)!
Use JOINs.
Several of your tables need this 'composite' index:
INDEX(allotment_code, category_name, ntp_number, activity) -- in any order
payroll_transaction needs INDEX(contractor_name), though it may not get used.
payroll_billed_units needs INDEX(billing_date), though it may not get used.
For further discussion, please provide SHOW CREATE TABLE for each table and EXPLAIN SELECT ...
Use simply COUNT(*) instead of COUNT(foo). The latter checks the column for being not-NULL before including it. This is usually not needed. The reader is confused by thinking that there might be NULLs.
Your GROUP BY is improper because it is missing ntp_number. Read about the sql_mode of ONLY_FULL_GROUP_BY. I bring this up because you can almost get rid of some of those subqueries.
Another issue... Because of the "inflate-deflate" nature of JOIN with GROUP BY, the numbers may be inflated. I recommend you manually check the values of the COUNTs.

Getting "Fatal error: Call to a member function fetch_assoc() on a non-object" on SQL query

I have these two tables in my database:
Statements
and Tags
I'm trying to execute this query
SELECT s.id, s.name, s.preview, s.approved FROM Statements s JOIN Tags t ON s.id = t.probID WHERE s.approved = TRUE AND t.tag IN ("Geometry") GROUP BY s.id, s.name, HAVING COUNT(DISTINCT t.tag) = 1,
but getting "Fatal error: Call to a member function fetch_assoc() on a non-object in C:\wamp\www\file.php on line 46", where 46th line is while($row = $res->fetch_assoc()){
Is something wrong with my query?
I suppose you are using MySQLi, correct me if I am wrong.
In the span of time I used it, whenever this kind of problem was presented to me, I had a problem with the query which I was not able to identify before the execution. Given that my query had failed, no SQLStatement object (or whatever its name is) was created. Therefore, no fetch_* method could be called on that!
I believe your problem is a very simple one: you have a trailing comma before your HAVING clause which is messing your query up. I reproduced your SQL structure and query on my PC, and everything worked correctly.
SELECT
s.id, s.name, s.preview, s.approved
FROM
Statements s JOIN Tags t ON s.id = t.probID
WHERE
s.approved = TRUE AND t.tag IN ('Geometry')
GROUP BY s.id, s.name
HAVING COUNT(DISTINCT t.tag) = 1
Try this one out.
Just a note: whenever I have to deal with a true or false in SQL and I am storing it as a *INT UNSIGNED, I feel like using 1 as true and 0 as false never creates any problem, while using TRUE or FALSE sometimes does! This was not the case, anyway :)
If you use var_dump($result); don't use it. Instead of that, put the result in the $result variable. $result = $stmt->get_result();

MySQL query into Code Igniter Active Directory format?

I'm trying to get mysql query into Code Igniter's Active Record syntax but am having a bit of a hard time.
The query is as a result of this question: Multiple mysql ORDER BY's for multidimensional ordering/grouping
I've attempted to format the query myself, have tackled a couple of errors, but am unsure how to progress. I had to add in the get_compiled_select() function to DB_active_rec.php myself and change the _reset_select() from protected to public to get it to run at all.
The suggested query is:
select
t.id,
t.group,
t.date,
t.comlete
from
YourTable t
left join
(select
m.group,
min(m.date) as mindate,
min(t.complete) as groupcomplete
from
YourTable m) mt on mt.group = t.group
order by
coalesce(mt.groupcomplete, t.complete),
coalesce(mt.mindate, t.date),
t.group,
t.complete,
t.date
My translation looks like this (note that there's a 'where' clause not in the original, and that 'date' is actually 'due'):
// Sub query
$this->db->select('m.group, min(m.due) as mindate, min(t.complete) as groupcomplete');
$this->db->from('task m');
$this->db->where('property', $property);
$subquery = $this->db->get_compiled_select();
$this->db->_reset_select();
// Main query
$this->db->select('*');
$this->db->where('property', $property);
$this->db->from('task t');
$this->db->join('($subquery) mt','mt.group = t.group');
$this->db->order_by('coalesce(mt.groupcomplete, t.complete)');
$this->db->order_by('coalesce(mt.mindate, t.due)');
$this->db->order_by('t.group');
$this->db->order_by('t.complete');
$this->db->order_by('t.due');
$query = $this -> db -> get();
// Return
return $query->result();
Unfortunately this is just throwing an error:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'mt ON `mt`.`group` = `t`.`group` WHERE `property` = '7' ORDER BY coalesce(mt.gr' at line 3
The query as reported by CI looks like:
SELECT * FROM (`task` t) JOIN ($subquery) mt ON `mt`.`group` = `t`.`group` WHERE `property` = '7' ORDER BY coalesce(mt.groupcomplete, `t`.`complete)`, coalesce(mt.mindate, `t`.`date)`, `t`.`due`, `t`.`complete`, `t`.`date`
Anyone able to lend some advice as to how to get this formatted correctly? My mysql skills are, unfortunately, pretty bare, so this is pushing my abilities. Much of the approach of my translation is from answers on Stack Overflow, as I have no experience combining queries in this way (with the subquery).
The problem (or 'one of the problems') is here:
$this->db->join('($subquery) mt','mt.group = t.group');
You use single quotes, so the variable $subquery doesn't get expanded.
This can also be seen in the query that is outputted by CodeIgniter.
When you have multiple order by statements u separate them by comma like this
$this->db->order_by('coalesce(mt.groupcomplete, t.complete), coalesce(mt.mindate, t.date), t.due, t.complete, t.date');

PostgreSQL Database - Inner Join Query Error

With the help of this community, I was able to produce a query using an inner join which I thought would work for what I'm trying to do. Unfortunately, when I attempted to run the query found below, I received the following error:
ERROR: table name "bue" specified more than once
From what I've read on Google, some people have said that the "FROM bue" is not needed, but when I removed this, I got another error found below:
ERROR: syntax error at or near "INNER" at character 98
I'd very much appreciate your assistance in troubleshooting this. Thank you so very much.
Query:
UPDATE
bue
SET
rgn_no = chapterassociation.rgn_no,
chp_cd = chapterassociation.chp_cd
FROM
bue
INNER JOIN
chapterassociation
ON bue.work_state = chapterassociation.work_state
AND bue.bgu_cd = chapterassociation.bgu_cd
WHERE
bue.mbr_no IS NULL AND bue.chp_cd IS NULL
In PostgreSQL, specifying the table to be updated needs to be done only in the UPDATE clause, e.g. UPDATE bue. The FROM clause is only for additional tables referenced in the query. (If you were doing a self-join on bue, you would mention it again in the FROM clause, but you aren't in this case.)
The second error you get is likely just a simple syntax error. The other tricky thing is that JOIN/ON syntax doesn't fit in the FROM clause, so you have to move the join conditions to the WHERE clause. Try something like:
UPDATE
bue
SET
rgn_no = chapterassociation.rgn_no,
chp_cd = chapterassociation.chp_cd
FROM
chapterassociation
WHERE
bue.mbr_no IS NULL AND bue.chp_cd IS NULL
AND bue.work_state = chapterassociation.work_state
AND bue.bgu_cd = chapterassociation.bgu_cd
See http://www.postgresql.org/docs/current/interactive/sql-update.html.
(N.B. At least I don't know how to put JOIN/ON into an UPDATE statement... I could be missing something.)

unbale to figure out the proper sql query

I have a tables like this
Results
-------
id - autoincrement value
TestCase - varchar
Verdict - varchar
AppID - varchar
TestCases
---------
id - autoincrementr value
TestCase - varchar
TestCase_container - varchar
Basically I am displaying the results in php code. while displaying the testcase, I am storing the testcase in a variable. in the while loop of mysql_query, I am creating another connection to DB and passing this variable to TestCases table to get the TestCase_Container assiciated with it.
This is a long way of doing this but I am unable to figure out proper direct SQL query using join or any other thing. Can someone point me in right direction please?
Thanks,
LIke this?
select r.id,r.TestCase,r.Verdict,r.AppId,tc.TestCase_container
from Results r,TestCases tc
where Results.TestCase=TestCases.TestCase
For DB normalization, results table must have testcase_id field instead of TestCase
Kind of hard to say, but I think what you're trying to do is a query like this maybe?
SELECT b.id AS result_id, a.TestCase, b.Verdict, b.AppID, a.id AS testcase_id, a.TestCase_container
FROM TestCases a
LEFT JOIN Results b
ON b.TestCase = a.TestCase;
Would probably be better to be joining on an indexed integer/id field, but that would work fine.
You could easily select all data from your tables by this SQL query:
SELECT Results.TestCase AS TestCase, Results.Verdict AS Verdict, Results.AppID AS AppID, TestCases.TestCase_container AS Container FROM Results JOIN TestCases ON Results.TestCase = TestCases.TestCase
After you should iterate getted array of values in any loop (for example while) like that:
$query = "SELECT Results.TestCase, Results.Verdict, Results.AppID, TestCases.TestCase_container FROM Results JOIN TestCases ON Results.TestCase = TestCases.TestCase";
$res = mysql_query($query) or die(mysql_error());
while ($row=mysql_fetch_array($res)) {
echo $row['TestCase'], ":", $row['Verdict'], ":", $row['AppID'], ":", $row['Container'], "\n";
}

Categories