I have 2 Tables:
region: region_id,name,state_id
state: state_id,name
I want both names in my result, state.name renamed to statename.
So far I got this:
$select = $select->from(array('r' => 'region'))->join(array('s' => 'state'),
'r.state_id = s.state_id',array("statename" =>"r.name"));
which results in following query:
SELECT `r`.*, `r`.`name` AS `statename` FROM `region` AS `r`
INNER JOIN `state` AS `s` ON r.state_id = s.state_id
So i just need to change r.name AS statename to s.name AS statename.
But i cant get it to work. If i change the last part of the select to array("statename" =>"s.name"), i get an error
Select query cannot join with another table
So how can i rename a field in the joining table?
You have to remove the integrity check.
$table = new self();
$select = $table->select()->setIntegrityCheck(false);
$select = $select->from(array('r' => 'region'))->join(array('s' => 'state'),'r.state_id = s.state_id',array("statename" =>"s.name"));
The integrity check is there to make sure your query is not going to use columns from another table, so Zend_Db_Table_Row objects can be updated, saved or deleted. If you remove the integrity, you're telling Zend that you know what you're doing and you want to use columns from another table.
Here's a brief explanation from documentation:
The Zend_Db_Table_Select is primarily used to constrain and validate
so that it may enforce the criteria for a legal SELECT query. However
there may be certain cases where you require the flexibility of the
Zend_Db_Table_Row component and do not require a writable or deletable
row. for this specific user case, it is possible to retrieve a row or
rowset by passing a FALSE value to setIntegrityCheck(). The resulting
row or rowset will be returned as a ‘locked’ row (meaning the save(),
delete() and any field-setting methods will throw an exception).
Related
I have this problem that's been killing me for a couple days now.
So we have a table of all processed orders.
We have a table for all orders that come in.
We need to effectively cross-reference the orders in the new table that is continually updating against the orders already completely in the primary table so that we don't complete the same order multiple times.
After we get a batch of new orders, this is the query that I currently run in an attempt to cross reference it with the table of completed orders:
$sql = "DELETE
FROM
`orders_new`
WHERE
`order` IN (
SELECT DISTINCT
`order`
FROM
`orders_all`
)
AND `name` IN (
SELECT DISTINCT
`name`
FROM
`orders_all`
)
AND `jurisdiction` IN (
SELECT DISTINCT
`jurisdiction`
FROM
`orders_all`
)";
As you can probably tell, I want to delete rows from the "orders_new" table where a row with the same order, name, and jurisdiction already exists in the "orders_all" table.
Is this the right way to handle this sort of query?
Well, the right way depends on many things.
But first, I do not like your division into two tables. In that case I would introduce a column identfying state, that woul reference a table with possible states. Those would be "new", "in process", "completed". That way you have one order stored as only one record as it should be.
But your query migt be ok, but you should check the performance.
Take a look at: https://sqlperformance.com/2012/12/t-sql-queries/left-anti-semi-join
Not exactly your case but very similar.
Another thing: Why do you use DISTINCT. That would imply that "order" is not a unique identifier.
Based on your edit you identify the order with composite key "order", "name", "jurisdiction". Is this really the key, the whole key and nothing but the key so help you Codd. If not, you could delete a bunch of records. But even so your query would delete an all orders for which the order, name and jurisdiction can be found in table order IN DIFFERENT RECORDS. So your query is false.
Saying that, a variant of your query might be
DELETE order_new
FROM
order_new
INNER JOIN
order_all ON order_all.order = order_new.order
AND order_all.name = order_new.name
AND order_all.jurisdiction = order_new.jurisdiction
But, the real problem is your ER model.
No, your query will delete any record where there are any records with the same order, name, and jurisdiction, even if those records are different from one another. In other words, a row in orders_new will be deleted if one row in order_all has the same order, a different one has the same name, and a third one has the same jurisdiction. You are very very likely to delete way more than you want to. Instead, this would be more appropriate:
DELETE FROM `orders_new`
WHERE (`order`, `name`, jurisdiction`) IN (
SELECT `order`, `name`, `jurisdiction`
FROM `orders_all`
)
or maybe
DELETE FROM `orders_new`
WHERE EXISTS (
SELECT 1
FROM `orders_all` AS oa
WHERE oa.`order` = `orders_new`.`order`
AND oa.`name` = `orders_new`.`name`
AND oa.`jurisdiction` = `orders_new`.`jurisdiction`
)
You should convert that to a DELETE - JOIN construct like
DELETE `orders_new`
FROM `orders_new`
INNER JOIN `orders_all` ON `orders_new`.`order` = `orders_all`.`order`
AND `orders_new`.`name` = `orders_all`.`name`
AND `orders_new`.`jurisdiction` = `orders_all`.`jurisdiction`;
i have multiple table that join together and i need one query and get all references too ! is that possible in yii2??
get them in hierarchy array ??
How ???
Is it possible to do not use join???
thanks for your help!!!!
If you created the model classes for each table using Gii and selected to create the relations in the generated models, you can do something like the following.
1) In your Countries model just change the method that declares the relationship with Airports like this:
public function getAirports() {
return $this->hasMany(Airports::className(), ['country_id' => 'id'])->with('airlines');
}
2) When you do the query for the countries and you need to have the related airports, airlines and flightbooked do it like this:
$countries = Countries::find()
->where('something = something_else')
->with('airports')
->with('flightbooked')
->all();
This way you will get all the related models populated with way less queries to the database than using lazy-loading.
I just wanted to give a small suggestion:
As you are maintaining the relations in the tables and if you have generated your code using Gii, then that will generate the joins for you. You can then access any column of any table easily.
But I think UNION may not be an alternative to JOIN.
Maybe u can use union all for this. with this operator, you can concatenate the result sets from multiple queries together, preserving all of the rows from each. Note that a UNION operator (without the ALL keyword) will eliminate any "duplicate" rows which exist in the resultset. The UNION ALL operator preserves all of the rows from each query (and will likely perform better since it doesn't have the overhead of performing the duplicate check and removal operation).
The number of columns and data type of each column must match in each of the queries. If one of the queries has more columns than the other, we sometimes include dummy expressions in the other query to make the columns and datatypes "match". Often, it's helpful to include an expression (an extra column) in the SELECT list of each query that returns a literal, to reveal which of the queries was the "source" of the row.
SELECT 'col1' AS source, col23, col343, col33, d FROM table1 WHERE ...
UNION ALL
SELECT 'col2', t2.fee, table2.fi, table2.fo, 'fum' FROM table2 JOIN table3 ON ...
UNION ALL
SELECT 'col3', '1', '2', buckle, my_shoe FROM table4
You can wrap a query like this in a set of parenthesis, and use it as an inline view (or "derived table", in MySQL lingo), so that you can perform aggregate operations on all of the rows. e.g:
select one.a
, SUM(one.b)
FROM (
SELECT 'q1' AS source, a, b, c, d FROM t1
UNION ALL
SELECT 'q2', t2.fee, t2.fi, t2.fo, 'fum' FROM t2
) one
GROUP BY one.a
ORDER BY one.a
But i think joining tables more suitable. Hope help you
This question already has answers here:
How to resolve ambiguous column names when retrieving results?
(11 answers)
Closed 2 years ago.
I have fields that have the same name in different tables that I'm joining. Such as ticket.status, user.status and transaction.status. At the moment the query returns just status.
How can I get the table name in such a way that it stops similar field names from overwriting and so I can tell the difference between the fields.
Simply put:
$data = array($eventId);
$statement = $this->db->prepare("SELECT * FROM ticket, user, transaction
WHERE ticket.eventId = ?
AND ticket.userId = user.userId
AND ticket.transactionId = transaction.transactionId");
$statement->execute($data);
$rows = $statement->fetchAll(PDO::FETCH_ASSOC);
In my research I've found the constant PDO::ATTR_FETCH_TABLE_NAMES that looks like it could help, but I do not know how to implement ( I assume through $statement->setAttribute(); somehow).
I also have concerns that it will not work, as the PHP documentation mentions it is dependent on the driver.
Thanks
Just add new aliases to your select statements
$statement = $this->db->prepare("
SELECT *, ticket.status AS ticket_status, user.status AS user_status, transaction.status AS transaction_status
FROM ticket, user, transaction
WHERE ticket.eventId = ?
AND ticket.userId = user.userId
AND ticket.transactionId = transaction.transactionId
");
Then you can do
$rows[0]['user_status'];
$rows[0]['ticket_status'];
$rows[0]['transaction_status'];
If you are really concern by performance, the quantity of data returned will be greater so instead of adding new aliases you can select every single columns and while you do so put an alias on the status column.
Why not change your to actually join instead:
SELECT
t.status as ticket_status, u.status as user_status, tr.status as trans_status
FROM
ticket as t
inner join user as u on t.userId = u.userId
inner join transaction as tr on t.transactionId = tr.transactionId
where
t.eventId = ?
You don't even need to cast the tables using as something but I find it's neater.
Note, its the casting of the columns that will actually fix this issue, not the join method.
The most obvious comment is "don't do it, that's why aliases exist". But there's still a good underlying question: does MySQL send information about where a result-set column comes from (table, view or calculated)?
Apparently, it does, since the PDOStatement object has an experimental method called getColumnMeta(). I've been testing and it returns an associative array where the table key
contains the source table if column comes from a table or view
is an empty string if the column is calculated
Of course, I'd stick to aliases anyway. Being able to use associative arrays is a killer feature for me.
I have a table TblOrders which have two fields like FldOrderStatusId and FldInstrumentID as a foreign key from the tables called TblOrderStatus and TblInstrumentMasters respectively. Is that possible to left join for the table. The code is given below:
$find_filled_orders = $this->UserOrder->query(
"Select distinct(FldOrderNumber) from TblOrders where FldOrderStatusId =12 ");
$res_order="";
$i=0;
foreach($find_filled_orders as $order_arr)
{
if($i!=0)
{
$res_order.=",";
}
$res_order.="'".$order_arr['TblOrders']['FldOrderNumber']."'";
$i++;
}
$where_not_in="";
if($i>=1)
{
$where_not_in = "AND FldOrderNumber NOT IN (".$res_order.")";
}
//debugbreak();
$current_order = $this->UserOrder->query(
"Select * from TblOrders where 1 ".$where_not_in.
" group by FldOrderNumber order by FldSlNo desc");
I want to apply left join at the last line query. Please guys help me out.
Thanks in advance.
Are you sure you're using Cake? O_o There's no need for raw sql for such a simple query. If your tables and key names followed Cake's conventions, Cake would do it all for you with just a couple chained methods in your controller.
I'm not even really sure what you're trying to accomplish, but I think you just want to pull all the status of all of a user's unfilled instrument orders, or something?
There is exactly 0 need to manually construct queries in Cake, let alone prep strings like that. Let the framework do the heavy lifting. If needed, $find_filled_orders could be written as a nested SELECT statement (for which Cake provides elegant support). Otherwise, all you need is to retool your tables / models so you can associate them properly and let Cake do the rest.
You don't show how you want to call instruments, so I can't be more specific. But Cake will automatically generate joins for associated models if you define them and name everything properly. Imply a relationship between Orders and Users by adding a column in Orders called user_id. Same for instruments_id and status_id, and if desired, for table Users - order_id, etc. Cake "foreign key" columns don't have to actually be defined foreign key constrained in the db, or even contain any data. Make them all null if it pleases you.
$current_order = $this->Order->find('all', array(
'conditions'=>array(
'Order.status_id != 12',
'Order.status_id'=>'Status.id',
'Order.instrument_id'=>'Instrument.id'
),
'fields'=>array('DISTINCT (Order.number) as number', 'name', 'other'),
'group'=> 'Order.number',
'order'=>'Order.fld_sl_no DESC'
)
);
(Both group and DISTINCT -- in real life, no need for both. I put them both in for the sake of demonstrating.)
http://book.cakephp.org/view/1002/Creating-Database-Tables
http://book.cakephp.org/view/1030/Complex-Find-Conditions
HTH. :)
I am query a database to get all the employers names out of my database, but I only want to get the ones where their ID is present in my jobs table, here is what I am trying to do.
$this->db->select('*')
->from('employers')
->join('jobwall', 'jobwall.employers_employer_id = employers.employer_id', 'left');
However this does not return the correct results, how can I select all my employers from the employers table but only if they have data in the jobwall table?
You need to add a WHERE clause:
$sql = '
SELECT *
FROM employers
LEFT JOIN jobwall ON jobwall.employers_employer_id = employers.employer_id
WHERE employers.employer_id
IN (SELECT employers_employer_id FROM jobwall)
';
$this->db->query($sql);
I'm not sure how complicated this would be to create using Codeigniter's activerecord class.
I think a better WHERE clause might be:
SELECT *
FROM employers
LEFT JOIN jobwall ON jobwall.employers_employer_id = employers.employer_id
WHERE jobwall.id IS NOT NULL
This will exclude any rows that don't have a corresponding job.
You should use whatever Primary Key your jobwall table has if jobwall.id doesn't exist.
This can also be written using ActiveRecord easily.
I don't understand you exactly, but I think you should use join without left:
this->db->select('*')->from('employers')->join('jobwall', 'jobwall.employers_employer_id = employers.employer_id');