SQL EXISTS condition in Symfony 1.4 - symfony1

I'd like to express the following sql query in Symfony 1.4 using Doctrine's Query Builder :
select `user_agent`
from ticket
WHERE EXISTS (SELECT *
FROM log
WHERE ticket.id = log.ticket_id AND log.task_id = 1)
How I can express the "where exist....." condition?

You can use exists statement in where clause as other conditions. In your case it would look something like:
Doctrine_Core::getTable('ticket')->createQuery('t')
->select('user_agent')
->addWhere('exists(select * from log l where l.ticket_id = t.id AND l.task_id = 1')
->fetchArray();

Related

Rails Translate SQL raw in ActiveRecord

I have this SQL query
sql = "select mt1.* from mail_templates as mt1 join mail_templates as mt2 where mt1.template_id = mt2.id AND mt1.technical_name='#{name}' AND mt2.festival_id=#{festival}"
If I execute this query with ActiveRecord::Base.connection.execute(sql).first it returns an array and I need to have a MailTemplate ActiveRecord.
I don't know how to do it.
Thanx for your help
I found the solution by using
sql = "select mt1.* from mail_templates as mt1 join mail_templates as mt2 where mt1.template_id = mt2.id AND mt1.technical_name='#{name}' AND mt2.festival_id=#{festival}"
MailTemplate.find_by_sql(sql)

How can you specify Oracle SQL functions such as trunc() in Rails select functions?

I have the below query written in a Rails controller which is querying an existing Oracle DB and it works fine.
#total_sales_volume = PaymentTransaction.joins(:settlement)
#total_sales_volume = #total_sales_volume.where("payment_transaction.transaction_status = 'S'
and payment_settlement.settlement_type = 'D'
and trunc(payment_settlement.transaction_date) > sysdate - 30")
However, I want to apply Oracle's trunc() function on the payment_settlement.transaction_date column. So I modified the above query and tried this:
#total_sales_volume = PaymentTransaction.joins(:settlement)
#total_sales_volume = #total_sales_volume.where("payment_transaction.transaction_status = 'S'
and payment_settlement.settlement_type = 'D'
and trunc(payment_settlement.transaction_date) > sysdate - 30").select("trunc(payment_settlement.transaction_date), payment_transaction.transaction_amount")
But no luck :( as I do not see any change in the actual query that gets fired. Here is the actual query that gets fired to Oracle (found it from the rails server logs)
SELECT
SUM("PAYMENT_TRANSACTION"."TRANSACTION_AMOUNT") AS sum_transaction_amount, transaction_date AS transaction_date
FROM
"PAYMENT_TRANSACTION" INNER JOIN "PAYMENT_SETTLEMENT" ON "PAYMENT_SETTLEMENT"."PAYMENT_TRANSACTION_ID" = "PAYMENT_TRANSACTION"."PAYMENT_TRANSACTION_ID"
WHERE
(payment_transaction.transaction_status = 'S'
and payment_settlement.settlement_type = 'D'
and trunc(payment_settlement.transaction_date) > sysdate - 30)
GROUP BY
transaction_date
Is applying Oracle SQL functions such as trunc() supported in ActiveRecord select functions?

Bulk updating a joined table with ActiveRecord update_all and Rails 4

I have a PostgreSQL query that I would like to write in ActiveRecord (Rails 4), but I'm having trouble getting it to work correctly.
UPDATE chats AS c
SET email = m.source_name
FROM messages AS m
WHERE c.id = m.chat_id
AND m.created_at >= '2014-10-10'
This is what I've tried:
Chat.joins(:messages)
.where("message.created_at >= '2014-10-10'")
.update_all('chat.email = message.source_name')
But it creates a query like this:
UPDATE "chats"
SET chat.email = message.source_name
WHERE "chats"."id" IN (
SELECT "chats"."id"
FROM "chats"
INNER JOIN "messages"
ON "messages"."chat_id" = "chats"."id"
WHERE (message.created_at >= '2014-10-10')
)
Any help on this?
Since Chat.update_all will add UPDATE chats SET... the only way that I can think of get rails to do an update with an alias (UPDATE chats AS c) is by using connection.update and a sql string:
Chat.connection.update(Q%{
UPDATE chats AS c
SET email = m.source_name
FROM messages AS m
WHERE c.id = m.chat_id
AND m.created_at >= '2014-10-10'
});
Not great if you want to avoid SQL fragments, but using an a join as in your question may be the only way if you want to use AREL.

Nested Select with ZF2

Trying to get a nested select using Zend\Db\Sql\Select and can't see anything at all in the documentation or on google.
Wanting to do something like this:
SELECT
table1.*,
(SELECT x,y,z FROM table2 WHERE table2.a = table1.a) as b
FROM table1
Without the nested select, it would look something like this:
$select = new Zend\Db\Sql\Select;
$select
->columns(array(
'*'
))
->from('table1')
ZF1 looked about creating a subSelect item and then adding it as an Expression inside the list of columns but in ZF2 it complains about an Expression needing to be a string.
Edit: The nested-select needs to be as a column as I end up with multiplied rows when using GROUP BY on same column name. This is the correct query I'm trying to get into Zend\Db\Sql\Select:
SELECT
users.id,
(SELECT count(explorations.id) FROM explorations WHERE user_id = users.id) as total_explorations,
count(villages.id)
FROM
users
INNER JOIN
villages
on (villages.user_id = users.id)
GROUP BY
users.id
Ralph Schindler has a repository of different DB patterns that he has specifically implemented in Zend\Db. Here's one for subselects: https://github.com/ralphschindler/Zend_Db-Examples/blob/master/example-20.php
The content is this:
<?php
/** #var $adapter Zend\Db\Adapter\Adapter */
$adapter = include ((file_exists('bootstrap.php')) ? 'bootstrap.php' : 'bootstrap.dist.php');
refresh_data($adapter);
use Zend\Db\Sql;
use Zend\Db\ResultSet\ResultSet;
$sql = new Sql\Sql($adapter);
$subselect = $sql->select();
$subselect->from('artist')
->columns(array('name'))
->join('album', 'artist.id = album.artist_id', array())
->where->greaterThan('release_date', '2005-01-01');
$select = $sql->select();
$select->from('artist')
->order(array('name' => Sql\Select::ORDER_ASCENDING))
->where
->like('name', 'L%')
->AND->in('name', $subselect);
$statement = $sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
$rows = array_values(iterator_to_array($result));
assert_example_works(
count($rows) == 2
&& $rows[0]['name'] == 'Lady Gaga'
&& $rows[1]['name'] == 'Linkin Park'
);
Basically, you can use one select as the value of the predicate of another select.
I would suggest you restructure you SQL query. I'm not sure which database you are using, but if you are using MySQL, the COUNT function can use the DISTINCT keyword. This way you don't count the duplicated ids. I've adjusted your SQL query to what I would use, this way you eliminate the need for inner select.
SELECT
users.id,
COUNT(DISTINCT explorations.id) AS total_explorations,
COUNT(DISTINCT villages.id) AS total_villages
FROM users
INNER JOIN villages ON villages.user_id = users.id
INNER JOIN explorations ON explorations.user_id = users.id
GROUP BY users.id
I haven't run this query, but I'm sure it should work and give you the result you want. Hopefully I'm not misunderstanding your situation. Below is the equivalent Zend Framework 2 select.
$select = $sql->select('users');
$select->columns(array('id'));
$select->join('villages',
'villages.user_id = users.id',
array(
'total_villages' => new Expression("COUNT(DISTINCT villages.id)")
)
);
$select->join('explorations',
'explorations.user_id = users.id',
array(
'total_explorations' => new Expression("COUNT(DISTINCT explorations.id)")
)
);
What you are describing is defined as a JOIN. There are some different join scenarios and i will not cover the differences of them, but the most commons would be INNER JOIN or LEFT JOIN.
And this is indeed to be found inside the ZF2-Documentation of Zend\Db\Sql#Join
The Query would look like this:
Select
t1.*,
t2.field1,
t2.field2,
t2.field3
FROM
tablename1 t1,
tablename2 t2
WHERE
t1.field = t2.field
Looking at the Documentation of ZF2-Documentation of Zend\Db\Sql#Join, i think the Select would look like this:
$select = new \Zend\Db\Sql\Select();
$select->columns(array(
'id',
'title',
// List ALL Columns from TABLE 1 - * is bad/slow!
), true)->from(array(
't1' => 'tablename1'
))->join(
'tablename2',
'id = t1.id',
array(
'username',
'email',
// List ALL Columns from TABLE 2 u want to select
),
$select::JOIN_INNER
)
Another i think: If you don't use the columns() you'd SELECT * but for your own sake, start writing good queries ;) Have more control over your code!
Can't promise that this code works, since i don't use Zend\Db on my own, but using the Documentation on the right point should get you running nonetheless.
I Hope I am getting your problem correctly...
Still not upgraded myself to ZF2 but this is one of the way you can create a nested Select statement in ZF1 if you are using MVC architecture(try it in ZF2 also).
$table1 = new table1();
$table1->select()->from('table1',array('*',
'b' => '(SELECT x,y,z FROM table2 WHERE table2.a = table1.a)',
));
Update:
Got back to this after your comment and realized that the code I've written would not work as you will not be able select multiple columns from another table into a single column(i.e x,y,z in b).
But yes it would work in case you have to perform some agg. function on the other table which gives out a single column. e.g.
$table1 = new table1();
$table1->select()->from('table1',array('*',
'b' => '(count (*) FROM table2 WHERE table2.a = table1.a)',
));
So this would work.
This way you can get some of the columns with some function performed on them.
And the rest of the columns from the other table(table2) you can get using a join.

Doctrine/symfony: getSqlQuery() output in phpMyAdmin/SQL tab

i have created this query that works OK:
$q1 = Doctrine_Query::create()
->from('Usuario u')
->leftJoin('u.AmigoUsuario a ON u.id = a.user2_id OR u.id = a.user1_id')
->where("a.user2_id = ? OR a.user1_id = ?", array($id,$id))
->andWhere("u.id <> ?", $id)
->andWhere("a.estado LIKE ?", 1);
echo $q1->getSqlQuery();
The calling to getSqlQuery outputs this clause:
SELECT s.id AS s__id, s.username AS
s__username, s.algorithm AS
s__algorithm, s.salt AS s__salt,
s.password AS s__password, s.is_active
AS s__is_active, s.is_super_admin AS
s__is_super_admin, s.last_login AS
s__last_login, s.email_address AS
s__email_address, s.nombre_apellidos
AS s__nombre_apellidos, s.sexo AS
s__sexo, s.fecha_nac AS s__fecha_nac,
s.provincia AS s__provincia,
s.localidad AS s__localidad,
s.fotografia AS s__fotografia,
s.avatar AS s__avatar,
s.avatar_mensajes AS
s__avatar_mensajes, s.created_at AS
s__created_at, s.updated_at AS
s__updated_at, a.id AS a__id,
a.user1_id AS a__user1_id, a.user2_id
AS a__user2_id, a.estado AS a__estado
FROM sf_guard_user s LEFT JOIN
amigo_usuario a ON ((s.id = a.user2_id
OR s.id = a.user1_id)) WHERE
((a.user2_id = ? OR a.user1_id = ?)
AND s.id <> ? AND a.estado LIKE ?)
If i take that clause to phpmyadmin SQL tab i get this error
1064 - 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 '? OR a.user1_id = ?) AND s.id <> ? AND a.estado LIKE ?) LIMIT 0, 30' at line 1
Why i'm getting this error?
Regards
Javi
The output includes placeholders in the query rather than actual values. You need to replace the ?'s with the correct values when you execute this in phpMyAdmin.
Using Symfony in dev mode, the values you're using for each query are shown in the database query panel accessible from the dev mode toolbar top right of your page, enclosed in parentheses after the query itself.

Resources