Write SQL Statement in CakePhp (group by if null) - php

So I need to write SQL statement using CakePhp ORM, but I have problem how to write in Cakephp GROUP BY IF NULL(condition).
Here is SQL Statement:
SELECT COUNT(*) FROM
(
SELECT i.id
FROM items i
INNER JOIN orders o ON i.order_id = o.id
WHERE (
(i.type = 1 AND i.status = 50) OR ((i.type = 2 OR i.type = 4) AND i.status = 60))
AND i.date_of_completion IS NOT NULL
GROUP BY IFNULL(i.vessel_change_identifier, i.id)
) AS temptbl;
This is my CakePhp Query
$query = TableRegistry::get('Items')
->find('all')
->innerJoinWith('Orders', function ($q) {
return $q->where(['Orders.id' => 'Items.order_id']);
})
->Where([
'Items.type' => 1,
'Items.status' => 50,
])
->orWhere([
'Items.type IN ' => [2, 4],
'Items.status' => 60,
])
->andWhere([
'Items.date_of_completion IS NOT' => NULL
]);
$query->select([
'count' => $query->func()->count('*')
]);
Thank you!

Try to use ->ifnull()
$query = TableRegistry::get('Items')
->find()
->innerJoinWith('Orders')
->where([
'Items.type' => 1,
'Items.status' => 50,
])
->orWhere([
'Items.type IN ' => [2, 4],
'Items.status' => 60,
])
->andWhere([
'Items.date_of_completion IS NOT' => NULL
]);
$query
->group(
$query
->func()
->ifnull([
'Items.vessel_change_identifier',
'Items.id'
])
);
$query->select([
'count' => $query->func()->count('*')
]);
Use it and enjoy it :D

Related

Select just one user per account

I got this php script that should only show one user per p.account_id, but isn't working like that.
If the user have two others users in the same account, it shows as well. I couldn't think anything to fix that.
$groupConfig = [
'Administrator' => ['groupId' => 5, 'accountType' => [5]],
'Community Manager' => ['groupId' => 4, 'accountType' => [4]],
'Gamemaster' => ['groupId' => 3, 'accountType' => [4]],
'Tutor' => ['groupId' => 1, 'accountType' => [2, 3]],
];
foreach ($groupConfig as $groupTitle => $group) {
$k = $SQL->query('SELECT
`p`.`name`,
`p`.`lastlogin`,
`p`.`id`,
`p`.`group_id`,
`a`.`type`
FROM
`players` AS `p`
LEFT JOIN `accounts` AS `a`
ON `a`.`id` = `p`.`account_id`
WHERE `a`.`type`
IN (' . implode(',', $group['accountType']) . ')
AND group_id = ' . $group['groupId'] . '
ORDER BY
`group_id`
DESC')->fetchAll();
}
You can try using GROUP BY clause to group by the identical value (p.account_id).
Why does your data allow multiple users per same account?
$groupConfig = [
'Administrator' => ['groupId' => 5, 'accountType' => [5]],
'Community Manager' => ['groupId' => 4, 'accountType' => [4]],
'Gamemaster' => ['groupId' => 3, 'accountType' => [4]],
'Tutor' => ['groupId' => 1, 'accountType' => [2, 3]],
];
foreach ($groupConfig as $groupTitle => $group) {
$k = $SQL->query('SELECT
`p`.`name`,
`p`.`lastlogin`,
`p`.`id`,
`p`.`group_id`,
`a`.`type`
FROM
`players` AS `p`
LEFT JOIN `accounts` AS `a`
ON `a`.`id` = `p`.`account_id`
WHERE `a`.`type`
IN (' . implode(',', $group['accountType']) . ')
AND group_id = ' . $group['groupId'] . '
GROUP BY `p`.`account_id`
ORDER BY
`group_id`
DESC')->fetchAll();
}
Change the fetchAll to fetch, or add a "LIMIT" to the SQL query. It's absolutely normal that you get multiple results. You aren't querying from table accounts, you are querying the table players. So your result will contain as many rows as the account had players. The best way would be to query the right table, but you could also solve it with the fixes mentioned before.

how to make the model->search function in yii2 not return rows with null values

so i have a model that has relations and i've modified the search function to permit querying the relational data but i don't want it to return the entries which have null values inside them. here's my search function:
public function search($params)
{
$query = Services::find();
$query->joinWith(['location', 'client', 'operator']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'sort'=> ['defaultOrder' => ['date'=>SORT_ASC]]
]);
...
$query->andFilterWhere([
'id' => $this->id,
'tip' => $this->tip,
'status' => $this->status,
]);
if ( ! is_null($this->date) && strpos($this->date, ' - ') !== false ) {
$datelist = explode(' - ', $this->date);
// var_dump($datelist);
// die($datelist);
$start_date = \DateTime::createFromFormat('m-d-Y H:i:s', $datelist[0].' 00:00:00');
$end_date = \DateTime::createFromFormat('m-d-Y H:i:s', $datelist[1].' 23:59:59');
$query->andFilterWhere(['between', 'date', $start_date->format('Y-m-d H:i:s'),$end_date->format('Y-m-d H:i:s')]);
}
$query->andFilterWhere(['like', 'location.address', $this->location]);
$query->andFilterWhere(['like', 'client.name', $this->client]);
$query->andFilterWhere(['like', 'personal.nume', $this->operator_id]);
$query->andFilterWhere(['NOT', [$this->client=>null]]);
$query->andFilterWhere(['NOT', [$this->location=>null]]);
$query->andFilterWhere(['NOT', ['location_id' => null]]);
$query->andFilterWhere(['NOT', ['client_id' => null]]);
return $dataProvider;
}
Notice the last 4 query rows. I think that should omit the rows that have null values in those specific attributes
This is the query generated, it does not include any NOT conditions and i don't get why.
SELECT `services`.* FROM `services` LEFT JOIN `location` ON `services`.`location_id` = `location`.`id` LEFT JOIN `client` ON `services`.`client_id` = `client`.`id` LEFT JOIN `personal` ON `services`.`operator_id` = `personal`.`id` WHERE `date` BETWEEN '2015-01-01 00:00:00' AND '2015-01-22 23:59:59' ORDER BY `client`.`name` DESC LIMIT 20
If someone manages to do this before, please show how :D
Thank you in advance
Instead of using andFilterWhere use andWhere. andFilterWhere ignores the empty operands and thus your null values will not be added to the query.
Replace
$query->andFilterWhere(['NOT', [$this->client=>null]]);
$query->andFilterWhere(['NOT', [$this->location=>null]]);
$query->andFilterWhere(['NOT', ['location_id' => null]]);
$query->andFilterWhere(['NOT', ['client_id' => null]]);
With
$query->andWhere(['NOT',['location_id' => null]])
$query->andWhere(['NOT', ['client_id' => null]]);

How to Implement this Mysql query into Zend framework 1 using dbSelect

SELECT
CONCAT(us.user_id,' ', us.name),
UPPER(sc.so_number) Order_no ,
sh.upc UPC,re.label Error,
(SELECT count(*) FROM order_checker_scan scan WHERE scan.so_number =sh.so_number and scan.upc=sh.upc and scan.user_id!=0
and DATE_FORMAT(scan_time,'%Y-%m-%d') >= '2015-11-01' ) AS
prev_data,
(select CONCAT(u.user_id,' ', u.name) from users u,picklist_history p where u.user_id=p.user_id and
p.so_number=sh.so_number limit 1) as picker,
sh.item_key Times,
DATE_FORMAT(sc.date_started,'%b%d %Y %h:%i%p') datetime,sh.qty_required QTY
FROM
order_checker_short sh,
order_checker_header
sc,order_checker_short_reason re,
users us
WHERE sh.so_number=sc.so_number AND
sh.reason_id=re.reason_id AND
sc.created_by=us.user_id And
sc.created_by!=0 AND
DATE_FORMAT(date_started,'%Y-%m-%d') between '2015-11-16' and '2015-11-17' AND
sh.reason_id !=0 AND
sh.upc !=1
GROUP BY sc.so_number,sh.upc
ORDER BY sc.date_started DESC, sc.so_number DESC , sh.upc ASC
Please test the following:
// 1st subselect
$prevDataSelect = $db->select()
->from(array('scan' => 'order_checker_scan'), array('count(*)'))
->where('scan.so_number = sh.so_number')
->where('scan.upc = sh.upc')
->where('scan.user_id != 0')
->where("DATE_FORMAT(scan_time,'%Y-%m-%d') >= '2015-11-01'");
// 2nd subselect
$pickerSelect = $db->select()
->from(array('u' => 'users', 'p' => 'picklist_history'), array("CONCAT(u.user_id,' ', u.name)"))
->where('u.user_id = p.user_id')
->where('p.so_number = sh.so_number')
->limit(1);
// Main selection
$mainSelect = $db->select()
->from(
// tables
array(
'sh' => 'order_checker_short',
'sc' => 'order_checker_header',
're' => 'order_checker_short_reason',
'us' => 'users',
),
// columns
array(
'SomeName' => "CONCAT(us.user_id, ' ', us.name)",
'Order_no' => 'UPPER(sc.so_number)',
'UPC' => 'sh.upc',
'Error' => 're.label',
'prev_data' => new Zend_Db_Expr('(' . $prevDataSelect . ')'),
'picker' => new Zend_Db_Expr('(' . $pickerSelect . ')'),
'Times' => 'sh.item_key',
'datetime' => "DATE_FORMAT(sc.date_started,'%b%d %Y %h:%i%p')",
'QTY' => 'sh.qty_required',
)
)
// AND WHERE clauses
->where('sh.so_number = sc.so_number')
->where('sh.reason_id = re.reason_id')
->where('sc.created_by = us.user_id')
->where('sc.created_by != 0')
->where("DATE_FORMAT(date_started, '%Y-%m-%d') between '2015-11-16' and '2015-11-17'")
->where('sh.reason_id != 0')
->where('sh.upc != 1')
// GROUP BY clause
->group(array('sc.so_number', 'sh.upc'))
->order(array('sc.date_started DESC', 'sc.so_number DESC', 'sh.upc ASC'));
If doesn't work please tell me what's the output of $mainSelect->assemble()

how to use not null condition in YII2

Hi i want to use not null condition in my yii2 query how should i use that.
i don't want city and state null.
My query is
$query = new Query;
$query->select('ID, City,State,StudentName')
->from('student')
->where(['IsActive' => 1])
->orderBy(['rand()' => SORT_DESC])
->limit(10);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false,
]);
You can use the not operator combined with the fields that should not be null to generate a IS NOT NULL SQL statement. Like this:
$query = new Query;
$query->select('ID, City,State,StudentName')
->from('student')
->where(['IsActive' => 1])
->andWhere(['not', ['City' => null]])
->andWhere(['not', ['State' => null]])
->orderBy(['rand()' => SORT_DESC])
->limit(10);
Also check the examples in the documentation.
->where(['IS NOT', 'column', null]);
get
WHERE column IS NOT NULL
You can also use, it is faster to type
->where('column IS NOT NULL')
In complex query
->where(['AND',
'column1 IS NOT NULL', // works
['IS NOT', 'column2', null], // works
['column3' => $value],
)
One of the options will be:
$query = new Query;
$query->select('ID, City,State,StudentName')
->from('student')
->where(['IsActive' => 1])
->andWhere(['<>', 'City', null])
->andWhere(['<>', 'State', null])
->orderBy(['rand()' => SORT_DESC])
->limit(10);
Check official docs for where.
$items = BadOffer::find()->where(['OR',
['IS', 'moderator_id', (new Expression('Null'))],
['moderator_id' => $user->id],
]);
In Yii2, we can use any of the queries below to verify the null condition,
->andWhere(['NOT', ['city' => null]]);
or
->andWhere(['<>', ['city' => null]]);
or
->andWhere('city IS NOT NULL');
use ->andWhere(['not', ['State' => null]]) or ->andWhere(['is not', 'State', null]);
Do no use :
andFilterWhere, as the null will make this filter be ignored
->andWhere(['<>', 'State', null]) as it form query AND State <> null
How to select non-empty columns in MySQL?
use LENGTH :
SELECT col1
FROM table
WHERE LENGTH(col1) > 0
Yii2 :
->andWhere(['>', 'LENGTH(col1)', 0])
This work for me, but only when pass null as string
->andFilterWhere(['<>', '`city`', 'null']);

creating mysql query using Yii2 Query Builder, strpos: array given

I'm trying to make query builder to output the following MySQL query:
SELECT p1.id, p1.product_id, p1.updated_at
FROM tbl_scrape_data p1
INNER JOIN
(
SELECT max(updated_at) MaxDate, product_id
FROM tbl_scrape_data
WHERE product_id IN (1,2,3)
GROUP BY product_id
) p2
ON p1.product_id = p2.product_id
AND p1.updated_at = p2.MaxDate
WHERE p1.product_id IN (1,2,3)
order by p1.updated_at desc
Here's what I tried:
$scrapeData = (new Query() )
->select(['p1.product_id', 'p1.id', 'p1.updated_at'])
->from('tbl_scrape_data p1')
->innerJoin([
'p2' => (new Query)
->select(['MAX(updated_at) MaxDate', 'product_id' ])
->from('tbl_scrape_data')
->where([ 'product_id' => [1, 2, 3, 15, 4] ])
->groupBy('product_id'),
//->all(),
['p1.product_id' => 'p2.product_id', 'p1.updated_at' => 'p2.MaxDate']
])
->where([ 'p1.product_id' => [1, 2, 3, 15, 4] ])
->orderBy('p1.updated_at DESC')
->all();
Yii2 throws an error trying to perform this query. Can someone tell me if this is a Yii2 bug or if I'm missing something? Or maybe the way I formatted the query builder is wrong?
I'm using Yii 2.0.1 and the error is
strpos() expects parameter 1 to be string, array given
\vendor\yiisoft\yii2\db\QueryBuilder.php at line 715
The reason of the error is in this section of code:
->innerJoin([
'p2' => (new Query)
->select(['MAX(updated_at) MaxDate', 'product_id' ])
->from('tbl_scrape_data')
->where([ 'product_id' => [1, 2, 3, 15, 4] ])
->groupBy('product_id'),
//->all(),
['p1.product_id' => 'p2.product_id', 'p1.updated_at' => 'p2.MaxDate']
])
Instead of passing two parameters - table and on separately you actually passing them in one parameter - array.
Also the first parameter (table) should be array with one element.
In other words, the placement of square brackets is incorrect.
So here is correct code of the INNER JOIN section:
->innerJoin(
['p2' => (new Query)
->select(['MAX(updated_at) MaxDate', 'product_id' ])
->from('tbl_scrape_data')
->where([ 'product_id' => [1, 2, 3, 15, 4] ])
->groupBy('product_id'),
//->all(),
],
['p1.product_id' => 'p2.product_id', 'p1.updated_at' => 'p2.MaxDate']
)
Check the official documentation for innerJoin() method.

Categories