I have a database like this
order_id | date | qty
------------------------------------
a |2018-11-11 10:03:33 |1
b |2018-11-12 10:03:33 |1
c |2018-11-11 12:03:33 |1
and I have a model like this,
public function get_total_sales_per_day($date_from, $date_to)
{
$this->db->select('order_id, SUM(qty) as total, date');
$this->db->from("order");
$this->db->group_by('date');
$this->db->order_by('date','asc');
$query = $this->db->get();
log_message("debug", $this->db->last_query());
return $query->result();
}
how to use group_by date but only from the year, month and day?
If you want to group by date only like (y-m-d), not apply group by on time
then some change in your code like:
Some modification in your code
public function get_total_sales_per_day($date_from, $date_to)
{
$this->db->select('order_id, SUM(qty) as total, date');
$this->db->from("order");
$this->db->group_by(DATE_FORMAT('date', "%y-%y-%d"));
$this->db->order_by('date','asc');
$query = $this->db->get();
log_message("debug", $this->db->last_query());
return $query->result();
}
You just need to escape while using DATE() function
/*You have not used arguments (date_from, date_to)
anywhere in active record, decide whether you need that,
*/
public function get_total_sales_per_day($date_from, $date_to)
{
$this->db->select('order_id, SUM(qty) as total, date');
$this->db->from("order");
/* This is what you need, $escape = FALSE */
$this->db->group_by('DATE(`date`)',FALSE);
/* If field exists in select then
you can also use : $this->db->order_by('3','asc',FALSE);
meaning sort by 3rd field
OR like below more readable
*/
$this->db->order_by('DATE(`date`)','asc',FALSE);
/* if you wish to order by datetime then you may keep
$this->db->order_by('date','asc');
*/
$query = $this->db->get();
log_message("debug", $this->db->last_query());
return $query->result();
}
You may read source code here :
public function group_by($by, $escape = NULL)
public function order_by($orderby, $direction = '', $escape = NULL)
Related
I am working in codeigniter, i have a below table of schemes, my problem is i want to show last updated data of each scheme. I dont know how to do that, please help.
my_table
scheme_code updated_on scheme_name
1 2015-04-13 One
3 2015-04-12 Three
4 2015-04-13 Four
3 2015-04-10 Three
3 2015-04-8 Three
1 2015-04-10 One
4 2015-04-11 Four
My Model
function show_last_updated_data(){
$this->db->select('*');
$this->db->from('my_table');
$this->db->order_by('updated_on', 'DESC');
$query = $this->db->get();
return $query->result();
}
Output Needed
scheme_code updated_on scheme_name
1 2015-04-13 One
3 2015-04-12 Three
4 2015-04-13 Four
My answer is based on #Syed Qarib. I modified it to be compatible with codeigniter active record format.
function show_last_updated_data() {
$this->db->select('*, str_to_date(updated_on, "%Y-%M-%d") As date', false); // false to skip escape
$this->db->from('scheme');
$this->db->group_by('scheme_code');
$this->db->order_by('date', 'DESC');
$query = $this->db->get();
return $query->result();
}
Edit
In another way,
function show_last_updated_data() {
$max = $this->db->select_max("updated_on")->group_by("scheme_code")->get('scheme')->result_array();
$updated_on = array();
if (count($max)) {
$updated_on = array_column($max, "updated_on"); // make sure your php version is >= 5.5
}
$this->db->select("*");
$this->db->from("scheme");
$this->db->where_in("updated_on", $updated_on);
$query = $this->db->get();
return $query->result();
}
Hope it will be useful for you.
Try this:
function show_last_updated_data(){
$this->db->select('*');
$this->db->from('my_table');
$this->db->group_by('scheme_name');
$this->db->order_by('updated_on', 'DESC');
$query = $this->db->get();
return $query->result();
}
You need to use group by it will retrieve your record based on scheme_code without repeating it and your desire results. :)
function show_last_updated_data() {
$query = $this->db->select('*')
->from('my_table')
->group_by('scheme_code')
->order_by('updated_on', 'DESC')
->get();
return $query->result();
}
As you have used custom date format, so the ordering will not work correctly until you convert the string to date format. Try this:
function show_last_updated_data(){
$this->db->select('*, str_to_date(updated_on, "%Y-%M-%d") date');
$this->db->from('my_table');
$this->db->order_by('date', 'DESC');
$query = $this->db->get();
return $query->result();
}
Note: It is recommended to use native date/datetime field, do not use custom formats. You can also go for UNIX timestamp and save it in an int field. As the date can be fetched in any format afterwards and will save you hassle like this one.
I have a query:
User::selectRaw('users.facebook_id')
->join('orders', 'orders.customer_id', 'shop_users.id')
->groupBy('shop_users.id')
->havingRaw('SUM(orders.total) >= 0')
->get()->pluck('facebook_id')->all();
but I want it only for orders from the last 30 days from now.
I assume I could use something such as ->whereDate('created_at', '>', Carbon::now()->subDays(30)) but not sure how to apply this to orders.
I think where between is what you need
Here try this
User::selectRaw('users.facebook_id')
->join('orders', 'orders.customer_id', 'shop_users.id')
->groupBy('shop_users.id')
->havingRaw('SUM(orders.total) >= 0')
->whereBetween('orders.created_at', [Carbon::now()->addDays(-30), Carbon::now()])
->get()->pluck('facebook_id')->all();
This will work if your datatype is dateTime.
now if you want to date only you can use this ->toDateString() just add this on your carbon
Hope it helps.
Here is the Join function from Laravel Code base,
/**
* Add a join clause to the query.
*
* #param string $table
* #param \Closure|string $first
* #param string|null $operator
* #param string|null $second
* #param string $type
* #param bool $where
* #return $this
*/
public function join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false)
{
$join = $this->newJoinClause($this, $type, $table);
// If the first "column" of the join is really a Closure instance the developer
// is trying to build a join with a complex "on" clause containing more than
// one condition, so we will add the join and call a Closure with the query.
if ($first instanceof Closure) {
call_user_func($first, $join);
$this->joins[] = $join;
$this->addBinding($join->getBindings(), 'join');
}
// If the column is simply a string, we can assume the join simply has a basic
// "on" clause with a single condition. So we will just build the join with
// this simple join clauses attached to it. There is not a join callback.
else {
$method = $where ? 'where' : 'on';
$this->joins[] = $join->$method($first, $operator, $second);
$this->addBinding($join->getBindings(), 'join');
}
return $this;
}
That means, you can do may be something like below
User::selectRaw('users.facebook_id')
->join('orders',function ($j) {
// Now $j is instance of builder e.g.
// $j->on('users.id', '=', 'orders.id')->orOn('users.name', '=', 'orders.name')->->whereDate('created_at', '>', Carbon::now()->subDays(30));
// Not super clear on the tables you are using
})
->groupBy('shop_users.id')
->havingRaw('SUM(orders.total) >= 0')
->get()->pluck('facebook_id')->all();
I have a function that retrieve values from database as json.I need some data from database and a value of SUM for certain column.When i not retrieve SUM from those value i get all required data but when i also include SUM function to get total of values from certain column i get only single object of value
MODEL
public function search_tickets($data){
$ticketDate = $data['ticket_date'];
$ticketBus = $data['ticket_bus'];
$ticketAgentId = $data['agent_id'];
$user = $this->db->select("
CONCAT_WS(' ', tp.firstname, tp.lastname) AS passenger_name,
tb.seat_numbers AS seat_number,
tb.id_no AS ticket_number,
fr.reg_no AS bus_number,
DATE_FORMAT(ta.start_date, '%d/%m/%Y') as ticket_date,
tb.price AS fare_paid,
tb.pickup_trip_location AS boarding,
tb.drop_trip_location AS dropping,
SUM(tb.price) AS total_fare
")
->from('tkt_booking AS tb')
->join('tkt_passenger AS tp', 'tb.tkt_passenger_id_no = tp.id_no' ,'full')
->join('trip_assign AS ta', 'ta.id = tb.trip_id_no' ,'full')
->join('trip_route AS tr', 'tr.id = tb.trip_route_id','full')
->join('agent AS a', 'a.agent_id = tb.agent_id','full')
->join('fleet_registration AS fr', 'fr.id = ta.fleet_registration_id','full')
->where('ta.start_date', $ticketDate )
->where('fr.reg_no', $ticketBus )
->where('tb.agent_id', $ticketAgentId )
->get()
->result();
return $user;
}
CONTROLLER
public function searchTickets(){
$data = $_POST;
$ticket=$this->booking_model->search_tickets($data);
if($ticket){
$result = array('tickets'=>$ticket);
} else {
$result = NULL;
}
print json_encode($result);
}
You should GROUP BY passenger id to get the total sum for each passenger:
$this->db->group_by('tb.tkt_passenger_id_no');
Earlier this day a asked a question about an update query. But now i want to select some things ( and it is working ) but I also want to order them and put a limit on it.
This is the code to select all the food :
public function getFood($id)
{
$id = (int)$id;
$rowset = $this->tableGateway->select(array('kindOfFood_id' => $id));
$row = $rowset->current();
if (!$row) {
throw new \Exception("Could not find row $id");
}
return $row;
}
But how can i do this :
Select * from KindOfFood ==> order by kindOfFood_votes DESC ?
I saw on the documentation you can do something like this, but it doesn't work with me?
$rowset = $artistTable->select(function (Select $select) {
$select->where->like('name', 'Brit%');
$select->order('name ASC')->limit(2);
});
Are you looking to return only single row or multiple rows.
Try this for multiple rows -
use Zend\Db\Sql\Select; //at the top of the page among other use statements.
public function getFood($id)
{
$id = (int) $id;
$select = new Select(TABLE_NAME); //CHANGE TABLE_NAME as per needs
$select->where('kindOfFood_id = ' . $id);
$select->order('kindOfFood_votes DESC');
$resultSet = $this->tableGateway->selectWith($select); //Will get array of rows.
//$row = $rowset->current(); THIS IS FOR RETURNING ONLY SINGLE ROW NOT ALL ROWS
if (!$resultSet) {
throw new \Exception("Could not find rows with food id - $id");
}
return $resultSet;
}
Can access the returned resultSet via loop. Eg: foreach
foreach($resultSet as $row) {
echo $row->kindOfFood_id; //or something
}
Note:
If you need only
Select * from KindOfFood order by kindOfFood_votes DESC
then remove the $select->where('kindOfFood_id = ' . $id); line from above.
I'm currently having an issue with pagination in Zend Framework 2.
This code
public function findAllByCriteria(CourseSearchInput $input) {
$concatDelimiter = self::CONCAT_DELIMITER;
$select = new Select();
$where = new Where();
$having = new Having();
$select->columns(array(
'id', 'title', 'description'
));
$select->from($this->tableGateway->getTable());
$select
->join('coursedata', 'courses.id = coursedata.id', array(
'relevance' => $this->buildRelevanceExpressionFromCriteria($input)
))
;
$having
->greaterThanOrEqualTo('relevance', self::RELEVANCE_MIN);
;
$select->where($where, Predicate::OP_AND);
$select->having($having);
$select->group(array('courses.id'));
$dbAdapter = $this->tableGateway->getAdapter();
// $dbAdapter->getDriver()->getConnection()->execute('SET sql_mode = "";');
$adapter = new \Zend\Paginator\Adapter\DbSelect($select, $dbAdapter);
$paginator = new \Zend\Paginator\Paginator($adapter);
return $paginator;
}
create this SQL:
SELECT
`courses`.`id` AS `id`,
`courses`.`title` AS `title`,
`courses`.`description` AS `description`,
MATCH (coursedata.title) AGAINST ('Salsa') * 5 + MATCH (coursedata.description) AGAINST ('Salsa') * 2 AS `relevance`
FROM `courses`
INNER JOIN `coursedata` ON `courses`.`id` = `coursedata`.`id`
GROUP BY `courses`.`id`
HAVING `relevance` >= '3'
It ueses the MySQL Extensions to GROUP BY and cannot be executed, if the sql_mode is set to ONLY_FULL_GROUP_BY. So, I tried to reset the sql_mode before the statement is executed (see the commented out line above: $dbAdapter->getDriver()->getConnection()->execute('SET sql_mode = "";');). But it didn't worked. So, how can I set the sql_mode in order to execute my non-standard SQL?
This may not be the answer to the question you are asking, but I can see you are going to have an issue with your query regardless when using Paginator.
The DbSelect Adapter for the Paginator doesn't like the aggregate function in there (Group By)
The Paginator will try and use your query to build it's own query to calculate the "count" for items in the collection. This is broken due to you using an aggregate in your query, any groups etc will break the adapter.
if you check the default implementation you will see:
/**
* Returns the total number of rows in the result set.
*
* #return integer
*/
public function count()
{
if ($this->rowCount !== null) {
return $this->rowCount;
}
$select = clone $this->select;
$select->reset(Select::COLUMNS);
$select->reset(Select::LIMIT);
$select->reset(Select::OFFSET);
// This won't work if you've got a Group By in your query
$select->columns(array('c' => new Expression('COUNT(1)')));
$statement = $this->sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
$row = $result->current();
$this->rowCount = $row['c'];
return $this->rowCount;
}
this doesn't like when you are using Group BY and will give back incorrect results.
You can create your own adataper, and extend the existing DbSelect and override the count method when you are planning to use Group BY;
Off the top of my head something like this should work, but may not be the most efficient way of doing it
/**
* Returns the total number of rows in the result set.
*
* #return integer
*/
public function count()
{
if ($this->rowCount !== null) {
return $this->rowCount;
}
/**
* If the query hasn't got 'GROUP BY' just try and use the old method
*/
$stateGroup = $this->select->getRawState('group');
if( ! isset($stateGroup) || empty($stateGroup)) {
return parent::count();
}
$select = clone $this->select;
$select->reset(Select::LIMIT);
$select->reset(Select::OFFSET);
$statement = $this->sql->prepareStatementForSqlObject($select);
$result = $statement->execute();
$this->rowCount = $result->count();
return $this->rowCount;
}