How to implement sql query in zend db - php

I tried myself for another queries but this one is more complex for me as i am new to zend. Please help me i tried different ways but not worked.
Tour Id fetching from another query
$tourId = $row2 ['test_public_id'];
$query = select count(ms.test_public_id) as total_views, ms1.recent_views from test_stats
ms join (select count(test_stats.test_public_id) as recent_views
from test_stats where test_stats.test_public_id = '$tourId'
and test_stats.updated_on > DATE_SUB(CURDATE(), INTERVAL 7 DAY)) ms1
where ms.test_public_id ='$tourId'" ;

Something like that should work:
$subselect = $dbAdapther->select()->from(
array('test_stats' => 'test_stats'),
array(
'(COUNT(test_public_id)) AS recent_views'
)
)->where(
$dbAdapther->quoteInto('test_stats.test_public_id = ?', $tourId)
)->where(
'test_stats.updated_on > DATE_SUB(CURDATE(), INTERVAL 7 DAY)'
);
$select = $dbAdapther->select()->from(
array('ms' => 'test_stats'),
array(
'(COUNT(ms.test_public_id)) AS total_views' // COUNT should be in brackets to preevent Zend from interpreting it as a field name
)
)->join(
array('ms1' => $subselect),
'',
array(
'ms1.recent_views'
)
)->where(
$dbAdapther->quoteInto('ms.test_public_id = ?', $tourId)'
);
Although I'd have your query broken into two separate ones or, more precisely, write a universal "get number of views" query with a date as its parameter, and then I'd be calling it twice, with or without the date.
But if you still need to get those two figures in one go in a single row (i.e. you can't use UNION instead of your unnecessary JOIN), I'd recommend you to use the following code instead:
$select = $dbAdapther->select()->from(
array('ms' => 'test_stats'),
array(
'(COUNT(ms.test_public_id)) AS total_views',
'(
COUNT(
CASE
WHEN ms.updated_on > DATE_SUB(CURDATE(), INTERVAL 7 DAY)) THEN ms.test_public_id
ELSE NULL
END
)
) AS recent_views'
)
)->where(
$dbAdapther->quoteInto('ms.test_public_id = ?', $tourId)
);

I'm new too in Zend, but I've tried this sample and it's works.
See this tutorial, I hope it'll help you:
http://framework.zend.com/manual/en/zend.db.select.html
or you can do this:
$db = Zend_Db_Table_Abstract::getDefaultAdapter();
$stmt = $db->query($query);
$result = $stmt->fetchAll();

Related

Write nested Select queries for same table in Zend Framework2

Following is my query
SELECT d.[today date], d.mydatediff,d.cc_exp
FROM (
SELECT GETDATE() AS 'today date',
cc_exp,
DATEDIFF(DAY, CONVERT(DATE, DATEADD(DAY, -1, DATEADD(MONTH, 1, CONVERT(DATETIME, '1/' + cc_exp, 103)))), GETDATE()) AS mydatediff,
[customer_member_id]
FROM [ats].[dbo].[customers]
WHERE cc_exp IS NOT NULL AND customer_member_id IN ('11111','2222','33333')
) d
WHERE d.mydatediff BETWEEN 30 AND 100
ORDER BY d.mydatediff DESC
I tried creating two SQL statments
$column = array(
'dateDiff' => new Expression('DATEDIFF(DAY, CONVERT(DATE, DATEADD(DAY, -1, DATEADD(MONTH, 1, CONVERT(DATETIME, \'1/\' + cc_exp, 103)))), GETDATE())'),
'cc_exp',
'customer_member_id'
);
$subselect = $sql->select();
$subselect->from(array('cus' => 'customers'));
$subselect->columns($column);
$where = new Where();
$where->in('customer_member_id', $memberId);
$where->and->isNotNull('cc_exp');
$subselect->where($where);
//$parent select
$select = $sql->select();
$select->from(array($subselect));
$selectColumn = array('cus.customer_member_id', 'cus.cc_exp', 'cus.dateDiff');
$where2 = new Where();
$where->between('cus.dateDiff','30','100');
$select->where($where2);
But it gives me an error
from() expects $table as an array is a single element associative array
You have a number of errors in this code that I can see:
You're defining the cus alias inside the subquery, but then using it in the main query
You're defining a list of columns for the main query but then not using them
You're not defining an alias for the subquery results
Try refactoring the code using the same aliases used in the original query, this will make it easier to compare the two. Then I think your main query would have something like this $select->from(array("d" => $subselect)); which should work.

How to optimise handle of big data on laravel?

My task is:
"To take transactions table, grouped row by transaction date and calculate statuses. This manipulations will be formed statistics, wich will be rendered on the page".
This is my method of this statistics generation
public static function getStatistics(Website $website = null)
{
if($website == null) return [];
$query = \DB::table('transactions')->where("website_id", $website->id)->orderBy("dt", "desc")->get();
$transitions = collect(static::convertDate($query))->groupBy("dt");
$statistics = collect();
dd($transitions);
foreach ($transitions as $date => $trans) {
$subscriptions = $trans->where("status", 'subscribe')->count();
$unsubscriptions = $trans->where("status", 'unsubscribe')->count();
$prolongations = $trans->where("status", 'rebilling')->count();
$redirections = $trans->where("status", 'redirect_to_lp')->count();
$conversion = $redirections == 0 ? 0 : ((float) ($subscriptions / $redirections));
$earnings = $trans->sum("pay");
$statistics->push((object)[
"date" => $date,
"subscriptions" => $subscriptions,
'unsubscriptions' => $unsubscriptions,
'prolongations' => $prolongations,
'redirections' => $redirections,
'conversion' => round($conversion, 2),
'earnings' => $earnings,
]);
}
return $statistics;
}
if count of transaction rows below 100,000 - it's all wright. But, if count is above 150-200k - nginx throw 502 bad gateway. What can you advise to me? I'm don't have any expierince in bigdata handling. May be, my impiments has fundamental error?
Big data is never easy, but I would suggest using the Laravel chunk instead of get.
https://laravel.com/docs/5.1/eloquent (ctrl+f "::chunk")
What ::chunk does is select n rows at a time, and allow you to process them bit by bit. This is convenient in that it allows you to stream updates to the browser, but at the ~150k result range, I would suggest looking up how to push this work into a background process instead of handling it on request.
After several days of researching information on this question, I found the right answer:
NOT to use PHP for handling raw data. It's better to use SQL!
In my case, we are using PostgreSQL.
Below, i'll write sql-query which worked for me, maybe it will help someone else.
WITH
cte_range(dt) AS
(
SELECT
generate_series('2016-04-01 00:00:00'::timestamp with time zone, '{$date} 00:00:00'::timestamp with time zone, INTERVAL '1 day')
),
cte_data AS
(
SELECT
date_trunc('day', dt) AS dt,
COUNT(*) FILTER (WHERE status = 'subscribe') AS count_subscribes,
COUNT(*) FILTER (WHERE status = 'unsubscribe') AS count_unsubscribes,
COUNT(*) FILTER (WHERE status = 'rebilling') AS count_rebillings,
COUNT(*) FILTER (WHERE status = 'redirect_to_lp') AS count_redirects_to_lp,
SUM(pay) AS earnings,
CASE
WHEN COUNT(*) FILTER (WHERE status = 'redirect_to_lp') > 0 THEN 100.0 * COUNT(*) FILTER (WHERE status = 'subscribe')::float / COUNT(*) FILTER (WHERE status = 'redirect_to_lp')::float
ELSE 0
END
AS conversion_percent
FROM
transactions
WHERE
website_id = {$website->id}
GROUP BY
date_trunc('day', dt)
)
SELECT
to_char(cte_range.dt, 'YYYY-MM-DD') AS day,
COALESCE(cte_data.count_subscribes, 0) AS count_subscribe,
COALESCE(cte_data.count_unsubscribes, 0) AS count_unsubscribes,
COALESCE(cte_data.count_rebillings, 0) AS count_rebillings,
COALESCE(cte_data.count_redirects_to_lp, 0) AS count_redirects_to_lp,
COALESCE(cte_data.conversion_percent, 0) AS conversion_percent,
COALESCE(cte_data.earnings, 0) AS earnings
FROM
cte_range
LEFT JOIN
cte_data
ON cte_data.dt = cte_range.dt
ORDER BY
cte_range.dt DESC

Multiple SQL queries and FOREACH - Can be JOINED to one?

I am trying to pull a list of Events, also seeing which members have paid for the Events. I then want to see if they are on the committee, to see if they have admin permissions.
I have successfully done this, using three SQL queries, then using three foreach loops to build the Array.
I am SURE this can be done with one SQL query and one foreach loop, however I have not yet mastered the JOIN technique.
I am using Expression Engine, Codeigniter Active Record, I will display to you the SQL output and also what my current EE functions look like.
THANKS FOR THE HELP! :D
SQL to select ALL events which are active
SELECT `id` as event_ID, `name` as event_name, `description` as event_description
FROM (`events`)
WHERE `events_category_id` = '1'
AND `active` = 1
ORDER BY `name` asc
EE CODE to achieve this:
$query = $this->theDb->select('id as event_ID, name as event_name, description as event_description')
->order_by("name", "asc")
->get_where('events', array('event_category_id'=>$event_type,'active'=>1));
**
SQL to find what EVENT IDs the user has paid for
**
SELECT DISTINCT `products`.`event_ID` as joinedID
FROM (`transactions_items`)
JOIN `transactions` ON `transactions`.`id` = `transactions_items`.`id`
JOIN `products` ON `products`.`id` = `transactions_items`.`product_id`
JOIN `events` ON `events`.`id` = `products`.`event_ID`
WHERE `transactions`.`member_id` = 27500
AND `events`.`active` = 1
AND `event_category_id` = '1'
ORDER BY `events`.`name` asc
EE CODE to achieve this
$query = $this->theDb->select('products.event_ID as joinedID')
->distinct()
->order_by("events.name", "asc")
->join('transactions', 'transactions.id = transactions_items.id')
->join('products', 'products.id = transactions_items.product_id')
->join('events', 'events.id = products.event_ID')
->get_where('transactions_items', array('transactions.member_id' => $memberID, 'events.active' => 1,'activity_category_id'=>$activity_type));
SQL to find ADMIN rights
SELECT `events`.`id` as event_ID, `admins`.`admin_role_id` as role_id, `admins_roles`.`name` as role_description
FROM (`admins`)
JOIN `admins_roles` ON `admins`.`admin_role_id` = `admins_roles`.`id`
JOIN `events` ON `events`.`id` = `admins`.`event_ID`
WHERE `admins`.`member_id` = 27500
AND `events`.`active` = 1
EE CODE to achieve this
$query = $this->theDb->select('events.id as event_ID, admins.admin_role_id as role_id, admins_roles.name as role_description')
->join('admins_roles', 'admins.admin_role_id = admins_roles.id')
->join('events', 'events.id = admins.event_ID')
->get_where('admins', array('admins.member_id' => $memberID, 'events.active' => 1));
FOR EACH LOOPS
// Create list of Events setting defaults
foreach($events_list as $row)
{
$combinedEvents[$row->event_ID] = array(
'eventID' => $row->event_ID,
'eventName' => $row->event_name,
'eventDescription' => $row->event_description,
'isJoined' => 0,
'roleID' => 0,
'roleDescription' => "",
);
}
// Add Committee roles
foreach($admin_list as $row)
{
$combinedEvents[$row->event_ID]['roleID'] = $row->role_id;
$combinedEvents[$row->event_ID]['roleDescription'] = $row->role_description;
}
// Add Transactions
foreach($transaction_list as $row)
{
$combinedEvents[$row->joinedID]['isJoined'] = 1;
}
I don't quite understand the FOREACH part because I've never touched PHP - but you should be able to solve the multiple SQL queires using the ;with clause. I have created an example in response to another question here and here. Is this what you're looking for?

Zend Framework DB >> Query with subquery doesn't work

I would like to execute an SQL query like this:
SELECT a.*, (time - (SELECT time FROM activity
WHERE time < a.time ORDER BY time DESC LIMIT 1) ) AS czas
FROM activity a WHERE 1 LIMIT 6000
I have prepared the following code ZF:
$activity = new Application_Model_DbTable_Activity();
$subSql = $activity->select()
//->setIntegrityCheck(false)
->from(array('aw' => 'activity'), array('time'))
->where('time < a.time', '')
->order('time DESC')
->limit(1);
// main query
$sql = $activity->select()
//->setIntegrityCheck(false)
->from(array('a' => 'activity'), array('a.*', 'czas' => new Zend_Db_Expr('(a.time - (' . $subSql . '))')))
->where(1)
->limit(6000);
$this->rows = $bugs->fetchAll($sql);
Unfortunately, this solution does not work. What should I improve?
Sorry for my english

Zend Database Mutli table "Select" via Join

Using Zend DB. I am trying to figure out how to write this query using the DB Class.
select
org.orgid
org.role
user.userid
user.firstname
from orgTable org
join userTable user on org.userid = user.userid
where org.orgid = 'generated-id'
from the documents I understand or think I understand how to do it with one definition using an AS like condition, but even then Im still not sure. Eventually this will branch out into a multi table join, based on cross table conditions so not sure how to achieve this to begin with.
I think this is what are you looking for
$db = Zend_Db::factory( ...options... );
$select = $db->select()
->from(array('org' => 'orgTable'),
array(
'orgid' => 'org.orgid',
'role' =>'org.role',
'userid' =>'user.userid',
'firstname' =>'user.firstname'
))
->join(array('user' => 'userTable'),
'org.userid = user.userid',array())
->where('org.orgid = ?',$generated_id);
Here is a Zend_Db_Select that returns the result you are looking for.
$select = $db->select()
->from(array('org' => 'orgTable'), array('orgid', 'role'))
->join(array('user' => 'userTable'), 'org.userid = user.userid', array('userid', 'firstname'))
->where('org.orgid = ?', 'generated-id');
You can use the array notation for table names to get the aliased names in the query.
Hope that helps.
In zend framework 2 , the following code helps you what are you looking for
$generated_id = 1 ;
$select = new \Zend\Db\Sql\Select( array('org' =>'orgTable'));
$select->columns(array('orgid','role') )
->join( array('user' => 'userTable'),
'org.userid = user.userid',
array('userid','firstname')
)->where( array('org.orgid' => $generated_id ) );
if your adapter platform is mysql, then for printing sql
$mysqlPlatform = new \Zend\Db\Adapter\Platform\Mysql();
echo $select->getSqlString( $mysqlPlatform );
which print sql as
SELECT
`org`.`orgid` AS `orgid`,
`org`.`role` AS `role`,
`user`.`userid` AS `userid`,
`user`.`firstname` AS `firstname`
FROM
`orgTable` AS `org`
INNER JOIN `userTable` AS `user`
ON `org`.`userid` = `user`.`userid`
WHERE
`org`.`orgid` = '1'

Categories