Subquery By Zend Database Format - mysql

I created a query in MYSQL as follows :
select subsql.item_id, subsql.uid, subsql.post_date, subsql.uid_prev,
max(workflow_trans.date) AS pre_date
from (
select item_id, max(date) AS post_date, uid, uid_prev
from workflow_trans
where uid = 'name' and date <= 'date1' and date >= 'date2'
group by item_id, uid, uid_prev
) AS subsql
left join workflow_trans on subsql.item_id = workflow_trans.item_id and
subsql.uid_prev = workflow_trans.uid and subsql.post_date > workflow_trans.date
where workflow_trans.date is not null
group by subsql.item_id, subsql.uid, subsql.post_date, subsql.uid_prev
order by subsql.post_date
The In translated it to Zend DB format as follows :
$this->db->select()->from(array("subsql" => $this->db->select()
->from(array($this->_name), array('item_id', 'max(date) AS post_date',
'uid', 'uid_prev'))
->where("uid = ?", $username)->where("date >= ?", $tgl1)
->where("date <= ?", $tgl2)
->group(array('item_id', 'uid', 'uid_prev'))),
array('subsql.item_id','subsql.uid',
'subsql.post_date','subsql.uid_prev','max(workflow_trans.date)
as pre_date'))
->joinLeft($this->_name, 'subsql.item_id = workflow_trans.item_id
and subsql.uid_prev = workflow_trans.uid and subsql.post_date >
workflow_trans.date')
->where("workflow_trans.date != ?", null)
->group(array('subsql.item_id', 'subsql.uid', 'subsql.post_date',
'subsql.uid_prev'))
->order(array('subsql.post_date'))
Yet the Zend model could not working. i've been reexamined it, and made 3 changes, but still there is something wrong with the formatting. Fresh pair of sharp eyes are appreciated.
ANSWER UPDATE
Hello guys, I already found it, below the running code :
$this->db->select()->from(array("subsql" => $this->db->select()
->from(array($this->_name), array('item_id', 'max(date) AS post_date',
'uid', 'uid_prev'))
->where("uid = ?", $username)->where("date >= ?", $tgl1)
->where("date <= ?", $tgl2)
->group(array('item_id', 'uid', 'uid_prev'))),
array('subsql.item_id','subsql.uid','subsql.post_date','subsql.uid_prev'))
->joinLeft(array($this->_name), 'subsql.item_id = workflow_trans.item_id and
subsql.uid_prev = workflow_trans.uid and
subsql.post_date > workflow_trans.date',
array('max(workflow_trans.date) as pre_date'))
->where("workflow_trans.date is not null")
->group(array('subsql.item_id', 'subsql.uid', 'subsql.post_date',
'subsql.uid_prev'))
->order(array('subsql.post_date'));
You should define the column from joining table in its own join function, and of course I got it wrong on how to handle the null.

If we talks about zf3, this query generates same sql as with yours.
$from = $this->getSql()->select('workflow_trans')
->columns(['item_id, max(date) AS post_date, uid, uid_prev', new Literal('max(workflow_trans.date) AS pre_date')])
->where(['uid = ?' => 'name'])
->where(['date <= ?' => 'date1'])
->where(['date >= ?' => 'date2'])
->group(['item_id', 'uid', 'uid_prev']);
$query = $this->getSql()->select()
->columns(['item_id, uid, post_date, uid_prev'])
->from(['subsql' => $from])
->join('workflow_trans', 'subsql.item_id = workflow_trans.item_id and subsql.uid_prev = workflow_trans.uid and subsql.post_date > workflow_trans.date', [])
->where(new IsNotNull('workflow_trans.date'))
->group(['subsql.item_id', 'subsql.uid', 'subsql.post_date', 'subsql.uid_prev'])
->order('subsql.post_date');

Related

How to convert this query to doctrine DQL

SELECT apntoken,deviceid,created
FROM `distribution_mobiletokens` as dm
WHERE userid='20'
and not exists (
select 1
from `distribution_mobiletokens`
where userid = '20'
and deviceid = dm.deviceid
and created > dm.created
)
What this query does is selects all mobiletokens where the user id is equal to 20 and the deviceid is the same but chooses the newest apntoken for the device.
My database looks like below.
For more information on this query, I got this answer from another question I asked here(How to group by in SQL by largest date (Order By a Group By))
Things I've Tried
$mobiletokens = $em->createQueryBuilder()
->select('u.id,company.id as companyid,user.id as userid,u.apntoken')
->from('AppBundle:MobileTokens', 'u')
->leftJoin('u.companyId', 'company')
->leftJoin('u.userId', 'user')
->where('u.status = 1 and user.id = :userid')
->setParameter('userid',(int)$jsondata['userid'])
->groupby('u.apntoken')
->getQuery()
->getResult();
//#JA - Get the list of all the apn tokens we need to send the message to.
foreach($mobiletokens as $tokenobject){
$deviceTokens[] = $tokenobject["apntoken"];
echo $tokenobject["apntoken"]."\n";
}
die();
This gives me the incorrect response of
63416A61F2FD47CC7B579CAEACB002CB00FACC3786A8991F329BB41B1208C4BA
9B25BBCC3F3D2232934D86A7BC72967A5546B250281FB750FFE645C8EB105AF6
latestone
Any help here is appreciated!
Other Information
Data with SELECT * FROM
Data after using the SQL I provided up top.
You could use a subselect created with the querybuilder as example:
public function selectNewAppToken($userId)
{
// get an ExpressionBuilder instance, so that you
$expr = $this->_em->getExpressionBuilder();
// create a subquery in order to take all address records for a specified user id
$sub = $this->_em->createQueryBuilder()
->select('a')
->from('AppBundle:MobileTokens', 'a')
->where('a.user = dm.id')
->andWhere('a.deviceid = dm.deviceid')
->andWhere($expr->gte('a.created','dm.created'));
$qb = $this->_em->createQueryBuilder()
->select('dm')
->from('AppBundle:MobileTokens', 'dm')
->where($expr->not($expr->exists($sub->getDQL())))
->andWhere('dm.user = :user_id')
->setParameter('user_id', $userId);
return $qb->getQuery()->getResult();
}
I did this for now as a temporary fix, not sure if this is best answer though.
$em = $this->em;
$connection = $em->getConnection();
$statement = $connection->prepare("
SELECT apntoken,deviceid,created
FROM `distribution_mobiletokens` as dm
WHERE userid=:userid
and not exists (
select 1
from `distribution_mobiletokens`
where userid = :userid
and deviceid = dm.deviceid
and created > dm.created
)");
$statement->bindValue('userid', $jsondata['userid']);
$statement->execute();
$mobiletokens = $statement->fetchAll();
//#JA - Get the list of all the apn tokens we need to send the message to.
foreach($mobiletokens as $tokenobject){
$deviceTokens[] = $tokenobject["apntoken"];
echo $tokenobject["apntoken"]."\n";
}

How to order including word order in SQL

Here is my query:
$select = $this->_conn->select();
$select->from(array('usr' => $this->_prefix . 'user'));
$select->join(array('rol' => 'role'), 'usr.role_id = rol.role_id',array());
$select->join(array('law' => 'lawyer_details'), 'usr.user_id = law.user_id', array('lawyer_url'));
$select->where("usr.user_status = ?","yes");
$select->where("rol.role_key = ?","yes");
$select->where("usr.user_section_show = ?","yes");
$select->where("usr.managment_show = ?","yes");
$select->limit(4);
$select->order(array('usr.user_firstname ASC'));
$rs = $select->query()->fetchAll();
return new Obt_Model_RecordSet($rs, $this);
I want to order by user_firstname but first get that user which names are "xxx","yyy","lll";
->order(new Zend_Db_Expr("FIELD(usr.user_firstname, 'xxx','yyy','lll')"));
Try this :-
order by (user_firstname='xxx') DESC,user_firstname ASC
In standard SQL, you may use:
order by
(case when usr.user_firstname in ('xxx', 'yyy', 'III') then 1 else 0 end) DESC,
usr.user_firstname ASC

Rails3 NOT IN query takes string as a value

I am trying to select users who don't have post in the forum list. For that I wrote a query like this
users_id = Post.where(:forum_id => 1).collect { |c| c.user_id }
#users = User.where('topic_id = ? and id not in ? ', "#{#topic.id}", "#{users_id}")
This code throws mysql error, and in my log
SELECT `user`.* FROM `user` WHERE (forum_id = '2222' and id not in '[5877, 5899, 5828, 5876, 5841, 5838, 5840, 5882, 5881, 5870, 5842, 5843, 5844, 5845, 5889, 5896, 5869, 5847, 5849, 5850, 5855, 5857, 5859, 5867, 5861, 5863, 5865, 5868, 5829, 5830, 5831, 5832, 5833, 5900, 6326, 6326, 6332, 5898, 6333, 6334, 6335, 6336, 6339, 7034, 7019, 6336, 5887, 5827, 9940, 9943, 9949, 7030, 9979, 9980, 5892, 9896, 14208, 14224, 14281, 14282, 14283, 5894, 5895, 14689, 14717]'
In mysql I execute the following query, and got the expected result
select * from users where topic_id = 1 and id not in (select users_id from posts where forum_id = 1);
The above query in rails doesn't seem to work..
Try this:
users_ids = Post.where(:forum_id => 1).collect { |c| c.user_id }
#users = User.where('topic_id = ? and id not in (?) ', #topic.id, users_ids)
Also, I advice you to make some changes:
Use pluck instead of collect (pluck is on the DB level)(pluck doc ; pluck vs. collect)
users_ids = Post.where(:forum_id => 1).pluck(:user_id)
name the table in the where clause to avoid ambiguous calls (in where chaining for example):
User.where('users.topic_id = ? AND users.id NOT IN (?)', #topic.id, users_ids)
The final code:
users_ids = Post.where(:forum_id => 1).pluck(:user_id)
#users = User.where('users.topic_id = ? AND users.id NOT IN (?)', #topic.id, users_ids)

How to run raw SQL Query with Zend Framework 2

Is there a way to execute a SQL String as a query in Zend Framework 2?
I have a string like that:
$sql = "SELECT * FROM testTable WHERE myColumn = 5"
now I want to execute this string directly.
Just pass the sql string to your db adapter like this:
$resultSet = $adapter->query($sql, \Zend\Db\Adapter\Adapter::QUERY_MODE_EXECUTE);
And if you want to pass parameters:
$sql = "SELECT * FROM testTable WHERE myColumn = ?";
$resultSet = $adapter->query($sql, array(5));
EDIT: Please note that the query method does not always returns a resultset. When its a resultset producing query(SELECT) it returns a \Zend\Db\ResultSet\ResultSet otherwise(INSERT, UPDATE, DELETE, ...) it will return a \Zend\Db\Adapter\Driver\ResultInterface.
And when you leave the second Parameter empty you will get a \Zend\Db\Adapter\Driver\StatementInterface which you can execute.
use Zend\Db\Sql\Sql;
use Zend\Db\Adapter\Adapter;
$dbAdapterConfig = array(
'driver' => 'Mysqli',
'database' => 'dbname',
'username' => 'dbusername',
'password' => 'dbuserpassword'
);
$dbAdapter = new Adapter($dbAdapterConfig);
$sql = new Sql($dbAdapter);
$select = $sql->select();
$select->from('testTable');
$select->where(array('myColumn' => 5));
$statement = $sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
S. docu: Zend\Db → Zend\Db\Sql
If you are using tableGateway, you can run your raw SQL query using this statement,
$this->tableGateway->getAdapter()->driver->getConnection()->execute($sql);
where $sql pertains to your raw query. This can be useful for queries that do not have native ZF2 counterpart like TRUNCATE / INSERT SELECT statements.
If you have EntityManager $em on your hands, you can do something like this:
$select = $em->getConnection()->executeQuery("
SELECT a.id, a.title, a.announcement, asvc.service_id, COUNT(*) AS cnt,
GROUP_CONCAT(asvc.service_id SEPARATOR \", \") AS svc_ids
FROM article AS a
JOIN articles_services AS asvc ON asvc.article_id = a.id
WHERE
asvc.service_id IN (
SELECT tsvc.service_id
FROM tender AS t
JOIN tenders_services AS tsvc ON tsvc.tender_id = t.id
WHERE t.id = :tenderId
)
GROUP BY a.id
ORDER BY cnt DESC, a.id DESC
LIMIT :articlesCount
", [
'articlesCount' => 5,
'tenderId' => $tenderId,
], [
'articlesCount' => \PDO::PARAM_INT,
]);
$result = $select->fetchAll(); // <-- here are array of wanted rows
I think this way to execute complex queries is best for Zend. But may be I'm not very smart in Zend still. Will glad to see if it helps to someone.

an SQL query in LINQ

I have a table with these columns: CombinationID, IndexID, Value
There is a sql query:
SELECT CombinationID
FROM CombinationIndex
where IndexID <> 4
group by CombinationID
order by sum(case indexid when 1 then -Value else Value end) desc
How could I write this query in c# by linq?
I think this should just about do it for you (it's all off the top of my head so there could be slight syntactical errors):
var results = context
.CombinationIndexes
.Where(i => i.IndexID != 4)
.GroupBy(i => i.CombinationID)
.OrderBy(g => g.Sum(i => i.IndexID == 1 ? -i.Value : i.Value))
.Select(g => g.Key);